diff --git a/.forceignore b/.forceignore new file mode 100755 index 0000000..3d36001 --- /dev/null +++ b/.forceignore @@ -0,0 +1,15 @@ +# List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status +# More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm +# + +package.xml + +# LWC configuration files +**/jsconfig.json +**/.eslintrc.json + +# LWC Jest +**/__tests__/** +**/tsconfig.json + +**/*.ts diff --git a/.github/workflows/code-analyze.yml b/.github/workflows/code-analyze.yml new file mode 100644 index 0000000..c51db74 --- /dev/null +++ b/.github/workflows/code-analyze.yml @@ -0,0 +1,79 @@ +name: Salesforce Code Quality + +on: + workflow_dispatch: + workflow_call: + +jobs: + PMD: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + - name: Setup Salesforce CLI + run: | + npm i --global @salesforce/cli + sf plugins:install @salesforce/sfdx-scanner + - name: SF Code Analyzer - PMD - Report findings as comments + uses: mitchspano/sfdx-scan-pull-request@v0.1.16 + with: + report-mode: comments + engine: pmd + pmdconfig: config/pmd/ruleset.xml + severity-threshold: 4 + strictly-enforced-rules: '[{ "engine": "pmd", "category": "Performance", "rule": "AvoidDebugStatements" }]' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + RetireJS: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + - name: Setup Salesforce CLI + run: | + npm i --global @salesforce/cli + sf plugins:install @salesforce/sfdx-scanner + - name: SF Code Analyzer - RetireJS - Report findings as comments + uses: mitchspano/sfdx-scan-pull-request@v0.1.16 + with: + report-mode: comments + engine: retire-js + severity-threshold: 4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + ESLint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + - name: Setup Salesforce CLI + run: | + npm i --global @salesforce/cli + sf plugins:install @salesforce/sfdx-scanner + - name: Install deps + run: | + yarn install + - name: SF Code Analyzer - ESLint - Report findings as comments + uses: mitchspano/sfdx-scan-pull-request@v0.1.16 + with: + report-mode: comments + engine: eslint + eslintconfig: .eslintrc.json + severity-threshold: 4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + GraphEngine: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + - name: Setup Salesforce CLI + run: | + npm i --global @salesforce/cli + sf plugins:install @salesforce/sfdx-scanner + - name: SF Code Analyzer - Data Flow Analysis + run: | + sf scanner:run:dfa --target force-app --projectdir force-app --format table --severity-threshold 3 diff --git a/.github/workflows/create-package-beta.yml b/.github/workflows/create-package-beta.yml new file mode 100644 index 0000000..50bb3f5 --- /dev/null +++ b/.github/workflows/create-package-beta.yml @@ -0,0 +1,28 @@ +name: Create Package Beta + +on: + workflow_dispatch: + workflow_call: + +jobs: + default: + name: Create Package Beta + runs-on: ubuntu-latest + steps: + - uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Setup Salesforce CLI + run: | + npm install --global @salesforce/cli + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Authenticate Dev Hub org + run: | + echo "${{ secrets.SFDX_AUTH_URL_DEVHUB }}" | sf org login sfdx-url --set-default-dev-hub --sfdx-url-stdin + - name: Create package beta + run: | + # increment minor version, fallback to 0.1.0 + nextReleaseVersion="$(sf package version list --packages "ISVShowcase" --released --order-by MajorVersion,MinorVersion,PatchVersion --json | yq '.result[-1] | ( .MajorVersion + "." + ( .MinorVersion + 1 ) + "." + .PatchVersion )' || echo "0.1.0")" + sf package version create --package ISVShowcase --version-number "${nextReleaseVersion}.NEXT" --installation-key-bypass --code-coverage --wait 30 diff --git a/.github/workflows/create-package-version.yml b/.github/workflows/create-package-version.yml new file mode 100644 index 0000000..2876ab5 --- /dev/null +++ b/.github/workflows/create-package-version.yml @@ -0,0 +1,40 @@ +name: Create Package Version + +on: + workflow_dispatch: + workflow_call: + outputs: + packageVersionId: + description: 'If a package version has been published, this is the package version id (04t)' + value: ${{ jobs.default.outputs.packageVersionId }} + version: + description: 'If a package version has been published, this is the package version number (major.minor.patch.build)' + value: ${{ jobs.default.outputs.version }} + +jobs: + default: + name: Create Package Version + runs-on: ubuntu-latest + outputs: + packageVersionId: ${{ steps.create-package-version.outputs.packageVersionId }} + version: ${{ steps.create-package-version.outputs.version }} + steps: + - uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Setup Salesforce CLI + run: | + npm install --global @salesforce/cli + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Authenticate Dev Hub org + run: | + echo "${{ secrets.SFDX_AUTH_URL_DEVHUB }}" | sf org login sfdx-url --set-default-dev-hub --sfdx-url-stdin + - id: create-package-version + name: Create package version + run: | + npx -y -p @semantic-release/exec -p semantic-release semantic-release + # packageVersionId and version will be set as output for the GH action (see release.config.mjs) + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/install-package-version.yml b/.github/workflows/install-package-version.yml new file mode 100644 index 0000000..6b776b3 --- /dev/null +++ b/.github/workflows/install-package-version.yml @@ -0,0 +1,31 @@ +name: Install Package Version + +on: + workflow_dispatch: + inputs: + packageVersion: + description: 'ID (starts with 04t) or alias of the package version to install' + required: true + workflow_call: + inputs: + packageVersion: + type: string + description: 'ID (starts with 04t) or alias of the package version to install' + required: true + +jobs: + default: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Setup Salesforce CLI + run: | + npm install --global @salesforce/cli + - name: Authenticate target org + run: | + echo "${{ secrets.AUTH_URL_TRIAL_DEMO }}" | sf org login sfdx-url --set-default --sfdx-url-stdin + - name: Install package version in target org + run: | + sf package install --no-prompt --publish-wait 20 --wait 60 --package "${{ inputs.packageVersion }}" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..4562816 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,22 @@ +name: Main + +on: + push: + branches: + - main + paths: + - force-app/** + +jobs: + create-package-version: + name: Run Create Package Version Workflow + uses: ./.github/workflows/create-package-version.yml + secrets: inherit + install-package-version: + name: Run Install Package Version Workflow + uses: ./.github/workflows/install-package-version.yml + needs: create-package-version + if: ${{ needs.create-package-version.outputs.packageVersionId != '' }} + with: + packageVersion: ${{ needs.create-package-version.outputs.packageVersionId }} + secrets: inherit diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..f37dc5d --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,18 @@ +name: Pull Request + +on: + pull_request: + branches: + - main + paths: + - force-app/** + +jobs: + code-analyze: + name: Run Salesforce Code Analyzer + uses: ./.github/workflows/code-analyze.yml + secrets: inherit + create-package-beta: + name: Run Create Package Beta Workflow + uses: ./.github/workflows/create-package-beta.yml + secrets: inherit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a03ba75 --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +# This file is used for Git repositories to specify intentionally untracked files that Git should ignore. +# If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore +# For useful gitignore templates see: https://github.com/github/gitignore + +# Salesforce cache +.sf/ +.sfdx/ +.localdevserver/ +deploy-options.json + +# LWC VSCode autocomplete +**/lwc/jsconfig.json + +# LWC Jest coverage reports +coverage/ + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Dependency directories +node_modules/ + +# Eslint cache +.eslintcache + +# MacOS system files +.DS_Store + +# Windows system files +Thumbs.db +ehthumbs.db +[Dd]esktop.ini +$RECYCLE.BIN/ + +# Local environment variables +.env + +# Python Salesforce Functions +**/__pycache__/ +**/.venv/ +**/venv/ + +# SFDMU +/data/source/ +/data/target/ +/data/logs/ + +# SGD +deltas* + +# package xml +package.xml + +# SFDMU +/data/sfdmu/source/ +/data/sfdmu/target/ +/data/sfdmu/logs/ \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..868f111 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname "$0")/_/husky.sh" + +npm run precommit \ No newline at end of file diff --git a/.lintstagedrc.js b/.lintstagedrc.js new file mode 100644 index 0000000..4e73c6e --- /dev/null +++ b/.lintstagedrc.js @@ -0,0 +1,3 @@ +module.exports = { + '**/*.{auradoc,cls,cmp,component,css,design,html,js,json,md,page,trigger,xml,yaml,yml}': 'prettier --write' +}; diff --git a/.prettierignore b/.prettierignore new file mode 100755 index 0000000..45f1078 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +# List files or directories below to ignore them when running prettier +# More information: https://prettier.io/docs/en/ignore.html +# + +**/staticresources/** +.localdevserver +.sfdx +*.md +coverage/ diff --git a/.prettierrc b/.prettierrc new file mode 100755 index 0000000..d470226 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,23 @@ +{ + "singleQuote": true, + "printWidth": 120, + "requireConfig": false, + "useTabs": false, + "trailingComma": "none", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "semi": true, + "tabWidth": 4, + "editor.formatOnSave": true, + "overrides": [ + { + "files": "**/lwc/**/*.html", + "options": { "parser": "lwc" } + }, + { + "files": "*.{cmp,page,component}", + "options": { "parser": "html" } + } + ], + "plugins": ["prettier-plugin-apex", "@prettier/plugin-xml"] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..752acc7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Hutte + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2310668 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# This repository contains + +## Skeleton SF Project +Based on [Hutte Project Template](https://github.com/hutte-recipes/hutte-project-template) + +## Sample source and GitHub Actions to build/promote/install package versions + +Check [Creating a 2GP for AppExchange](https://hutte-io.notion.site/Creating-a-2GP-for-AppExchange-c3a92c93261d4cb1a658fff696622bdb) for learning more about generating your first 2GP + +When using this template, please make sure to replace the namespace Hutte in all files inside the force-app directory (replace Hutte__ with YourNamespace__) as well as in sfdx-project.json (property "namespace"). \ No newline at end of file diff --git a/data/brokers-data.json b/data/brokers-data.json new file mode 100644 index 0000000..9fedd87 --- /dev/null +++ b/data/brokers-data.json @@ -0,0 +1,100 @@ +{ + "records": [ + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "CarolineBrookerRef" + }, + "Name": "Caroline Kingsley", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "caroline@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/caroline_kingsley.jpg" + }, + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "MichaelJonesRef" + }, + "Name": "Michael Jones", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "michael@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/michael_jones.jpg" + }, + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "JonathanBradleyRef" + }, + "Name": "Jonathan Bradley", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "jonathan@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/jonathan_bradley.jpg" + }, + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "JenniferWuRef" + }, + "Name": "Jennifer Wu", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "jen@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/jennifer_wu.jpg" + }, + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "OliviaGreenRef" + }, + "Name": "Olivia Green", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "olivia@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/olivia_green.jpg" + }, + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "MiriamAupontRef" + }, + "Name": "Miriam Aupont", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "miriam@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/miriam_aupont.jpg" + }, + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "MichelleLambertRef" + }, + "Name": "Michelle Lambert", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "michelle@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/michelle_lambert.jpg" + }, + { + "attributes": { + "type": "Hutte__Broker__c", + "referenceId": "VictorOchoaRef" + }, + "Name": "Victor Ochoa", + "Hutte__Title__c": "Senior Broker", + "Hutte__Phone__c": "617-244-3672", + "Hutte__Mobile_Phone__c": "617-244-3672", + "Hutte__Email__c": "victor@dreamhouse.demo", + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/victor_ochoa.jpg" + } + ] +} diff --git a/data/brokers-data.json.tmp b/data/brokers-data.json.tmp new file mode 100644 index 0000000..e69de29 diff --git a/data/contacts-data.json b/data/contacts-data.json new file mode 100644 index 0000000..4e4e9dc --- /dev/null +++ b/data/contacts-data.json @@ -0,0 +1,54 @@ +{ + "records": [ + { + "attributes": { + "type": "Contact", + "referenceId": "Contact1Ref" + }, + "FirstName": "Brad", + "LastName": "Holmes", + "Phone": "617-555-0143", + "Email": "bholmes@goodmail.com" + }, + { + "attributes": { + "type": "Contact", + "referenceId": "Contact2Ref" + }, + "FirstName": "Leslie", + "LastName": "Martin", + "Phone": "617-555-0112", + "Email": "leslie@pentagon.com" + }, + { + "attributes": { + "type": "Contact", + "referenceId": "Contact3Ref" + }, + "FirstName": "July", + "LastName": "Walker", + "Phone": "617-555-0170", + "Email": "julywalker@brain.com" + }, + { + "attributes": { + "type": "Contact", + "referenceId": "Contact4Ref" + }, + "FirstName": "Anna", + "LastName": "Jones", + "Phone": "617-555-0181", + "Email": "annaj@mymail.com" + }, + { + "attributes": { + "type": "Contact", + "referenceId": "Contact5Ref" + }, + "FirstName": "John", + "LastName": "Connor", + "Phone": "617-555-0133", + "Email": "jconnor@goodmail.com" + } + ] +} diff --git a/data/contacts-data.json.tmp b/data/contacts-data.json.tmp new file mode 100644 index 0000000..e69de29 diff --git a/data/properties-data.json b/data/properties-data.json new file mode 100644 index 0000000..9e8032f --- /dev/null +++ b/data/properties-data.json @@ -0,0 +1,268 @@ +{ + "records": [ + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "18HenryStRef" + }, + "Name": "Stunning Victorian", + "Hutte__Address__c": "18 Henry St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "01742", + "Hutte__Price__c": 975000, + "Hutte__Beds__c": 4, + "Hutte__Baths__c": 3, + "Hutte__Location__Longitude__s": -71.11095, + "Hutte__Location__Latitude__s": 42.35663, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house01.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house01sq.jpg", + "Hutte__Tags__c": "victorian", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@CarolineBrookerRef", + "Hutte__Status__c": "Available" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "24PearlStRef" + }, + "Name": "Ultimate Sophistication", + "Hutte__Address__c": "24 Pearl St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 1200000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.10869, + "Hutte__Location__Latitude__s": 42.359103, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house02.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house02sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@MichaelJonesRef", + "Hutte__Status__c": "Contracted" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "72FrancisStRef" + }, + "Name": "Modern City Living", + "Hutte__Address__c": "72 Francis St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 825000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.106827, + "Hutte__Location__Latitude__s": 42.335435, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house03.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house03sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@JonathanBradleyRef", + "Hutte__Status__c": "Pre Market" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "32PrinceStRef" + }, + "Name": "Stunning Colonial", + "Hutte__Address__c": "32 Prince St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 930000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.110448, + "Hutte__Location__Latitude__s": 42.360642, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house04.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house04sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@JenniferWuRef", + "Hutte__Status__c": "Available" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "110BaxterStRef" + }, + "Name": "Waterfront in the City", + "Hutte__Address__c": "110 Baxter Street", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 850000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 2, + "Hutte__Location__Longitude__s": -71.084454, + "Hutte__Location__Latitude__s": 42.368168, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house05.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house05sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@OliviaGreenRef", + "Hutte__Status__c": "Closed" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "448HanoverStRef" + }, + "Name": "Quiet Retreat", + "Hutte__Address__c": "448 Hanover St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 725000, + "Hutte__Beds__c": 4, + "Hutte__Baths__c": 2, + "Hutte__Location__Longitude__s": -71.052617, + "Hutte__Location__Latitude__s": 42.366855, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house06.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house06sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@MiriamAupontRef", + "Hutte__Status__c": "Contracted" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "127EndicottStRef" + }, + "Name": "City Living", + "Hutte__Address__c": "127 Endicott St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 450000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 1, + "Hutte__Location__Longitude__s": -71.057352, + "Hutte__Location__Latitude__s": 42.365003, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house07.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house07sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@MichelleLambertRef", + "Hutte__Status__c": "Available" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "48BrattleStRef" + }, + "Name": "Heart of Harvard Square", + "Hutte__Address__c": "48 Brattle St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 450000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.121653, + "Hutte__Location__Latitude__s": 42.374117, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house10.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house10sq.jpg", + "Hutte__Tags__c": "victorian", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@VictorOchoaRef", + "Hutte__Status__c": "Under Agreement" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "121HarborwalkRef" + }, + "Name": "Seaport District Retreat", + "Hutte__Address__c": "121 Harborwalk", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 450000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 3, + "Hutte__Location__Longitude__s": -71.049327, + "Hutte__Location__Latitude__s": 42.35695, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house09.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house09sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@CarolineBrookerRef", + "Hutte__Status__c": "Available" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "640HarrisonAveRef" + }, + "Name": "Contemporary City Living", + "Hutte__Address__c": "640 Harrison Ave", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 650000, + "Hutte__Beds__c": 2, + "Hutte__Baths__c": 2, + "Hutte__Location__Longitude__s": -71.068781, + "Hutte__Location__Latitude__s": 42.339892, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house08.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house08sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@MichaelJonesRef", + "Hutte__Status__c": "Available" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "95GloucesterStRef" + }, + "Name": "Architectural Details", + "Hutte__Address__c": "95 Gloucester St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 690000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 3, + "Hutte__Location__Latitude__s": 42.349693, + "Hutte__Location__Longitude__s": -71.084407, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house11.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house11sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@JonathanBradleyRef", + "Hutte__Status__c": "Available" + }, + { + "attributes": { + "type": "Hutte__Property__c", + "referenceId": "145CommonwealthAveRef" + }, + "Name": "Contemporary Luxury", + "Hutte__Address__c": "145 Commonwealth Ave", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 845000, + "Hutte__Beds__c": 4, + "Hutte__Baths__c": 3, + "Hutte__Location__Latitude__s": 42.352466, + "Hutte__Location__Longitude__s": -71.075311, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house12.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house12sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__c": "@JenniferWuRef", + "Hutte__Status__c": "Available" + } + ] +} diff --git a/data/properties-data.json.tmp b/data/properties-data.json.tmp new file mode 100644 index 0000000..e69de29 diff --git a/data/sample-data-plan.json b/data/sample-data-plan.json new file mode 100644 index 0000000..95b2c49 --- /dev/null +++ b/data/sample-data-plan.json @@ -0,0 +1,23 @@ +[ + { + "sobject": "Hutte__Broker__c", + "saveRefs": true, + "files": [ + "brokers-data.json" + ] + }, + { + "sobject": "Hutte__Property__c", + "resolveRefs": true, + "files": [ + "properties-data.json" + ] + }, + { + "sobject": "Contact", + "resolveRefs": false, + "files": [ + "contacts-data.json" + ] + } +] diff --git a/data/sample-data-plan.json.tmp b/data/sample-data-plan.json.tmp new file mode 100644 index 0000000..e69de29 diff --git a/data/sfdmu/Account.csv b/data/sfdmu/Account.csv new file mode 100644 index 0000000..e69de29 diff --git a/data/sfdmu/Contact.csv b/data/sfdmu/Contact.csv new file mode 100644 index 0000000..15a6954 --- /dev/null +++ b/data/sfdmu/Contact.csv @@ -0,0 +1,6 @@ +$$Email$LastName$FirstName,Account.Name,AssistantName,AssistantPhone,Birthdate,CleanStatus,Department,Description,Email,EmailBouncedDate,EmailBouncedReason,Fax,FirstName,HomePhone,Individual.Name,Jigsaw,LastName,LeadSource,MailingCity,MailingCountry,MailingGeocodeAccuracy,MailingLatitude,MailingLongitude,MailingPostalCode,MailingState,MailingStreet,MobilePhone,OtherCity,OtherCountry,OtherGeocodeAccuracy,OtherLatitude,OtherLongitude,OtherPhone,OtherPostalCode,OtherState,OtherStreet,Phone,ReportsTo.$$Email$LastName$FirstName,Salutation,Title +annaj@mymail.com;Jones;Anna,,,,,Pending,,,annaj@mymail.com,,,,Anna,,,,Jones,,,,,,,,,,,,,,,,,,,,617-555-0181,,, +bholmes@goodmail.com;Holmes;Brad,,,,,Pending,,,bholmes@goodmail.com,,,,Brad,,,,Holmes,,,,,,,,,,,,,,,,,,,,617-555-0143,,, +jconnor@goodmail.com;Connor;John,,,,,Pending,,,jconnor@goodmail.com,,,,John,,,,Connor,,,,,,,,,,,,,,,,,,,,617-555-0133,,, +julywalker@brain.com;Walker;July,,,,,Pending,,,julywalker@brain.com,,,,July,,,,Walker,,,,,,,,,,,,,,,,,,,,617-555-0170,,, +leslie@pentagon.com;Martin;Leslie,,,,,Pending,,,leslie@pentagon.com,,,,Leslie,,,,Martin,,,,,,,,,,,,,,,,,,,,617-555-0112,,, diff --git a/data/sfdmu/Hutte__Broker__c.csv b/data/sfdmu/Hutte__Broker__c.csv new file mode 100644 index 0000000..49a6b45 --- /dev/null +++ b/data/sfdmu/Hutte__Broker__c.csv @@ -0,0 +1,9 @@ +Hutte__Broker_Id__c,Hutte__Email__c,Hutte__Mobile_Phone__c,Hutte__Phone__c,Hutte__Picture__c,Hutte__Title__c,Name +,caroline@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/caroline_kingsley.jpg,Senior Broker,Caroline Kingsley +,jen@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/jennifer_wu.jpg,Senior Broker,Jennifer Wu +,jonathan@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/jonathan_bradley.jpg,Senior Broker,Jonathan Bradley +,michael@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/michael_jones.jpg,Senior Broker,Michael Jones +,michelle@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/michelle_lambert.jpg,Senior Broker,Michelle Lambert +,miriam@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/miriam_aupont.jpg,Senior Broker,Miriam Aupont +,olivia@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/olivia_green.jpg,Senior Broker,Olivia Green +,victor@dreamhouse.demo,617-244-3672,617-244-3672,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/people/victor_ochoa.jpg,Senior Broker,Victor Ochoa diff --git a/data/sfdmu/Hutte__Property__c.csv b/data/sfdmu/Hutte__Property__c.csv new file mode 100644 index 0000000..06a2314 --- /dev/null +++ b/data/sfdmu/Hutte__Property__c.csv @@ -0,0 +1,13 @@ +$$Name$Hutte__Location__Longitude__s$Hutte__Location__Latitude__s,Hutte__Address__c,Hutte__Assessed_Value__c,Hutte__Baths__c,Hutte__Beds__c,Hutte__Broker__r.Hutte__Email__c,Hutte__City__c,Hutte__Date_Agreement__c,Hutte__Date_Closed__c,Hutte__Date_Contracted__c,Hutte__Date_Listed__c,Hutte__Date_Pre_Market__c,Hutte__Description__c,Hutte__Location__Latitude__s,Hutte__Location__Longitude__s,Hutte__Picture__c,Hutte__Price__c,Hutte__Price_Sold__c,Hutte__State__c,Hutte__Status__c,Hutte__Tags__c,Hutte__Thumbnail__c,Hutte__Zip__c,Name +Architectural Details;-71.084407;42.349693,95 Gloucester St,,3,3,jonathan@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.349693,-71.084407,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house11.jpg,690000,,MA,Available,contemporary,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house11sq.jpg,02420,Architectural Details +City Living;-71.057352;42.365003,127 Endicott St,,1,3,michelle@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.365003,-71.057352,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house07.jpg,450000,,MA,Available,colonial,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house07sq.jpg,02420,City Living +Contemporary City Living;-71.068781;42.339892,640 Harrison Ave,,2,2,michael@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.339892,-71.068781,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house08.jpg,650000,,MA,Available,contemporary,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house08sq.jpg,02420,Contemporary City Living +Contemporary Luxury;-71.075311;42.352466,145 Commonwealth Ave,,3,4,jen@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.352466,-71.075311,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house12.jpg,845000,,MA,Available,contemporary,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house12sq.jpg,02420,Contemporary Luxury +Heart of Harvard Square;-71.121653;42.374117,48 Brattle St,,4,5,victor@dreamhouse.demo,Cambridge,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.374117,-71.121653,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house10.jpg,450000,,MA,Under Agreement,victorian,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house10sq.jpg,02420,Heart of Harvard Square +Modern City Living;-71.106827;42.335435,72 Francis St,,4,5,jonathan@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.335435,-71.106827,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house03.jpg,825000,,MA,Pre Market,contemporary,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house03sq.jpg,02420,Modern City Living +Quiet Retreat;-71.052617;42.366855,448 Hanover St,,2,4,miriam@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.366855,-71.052617,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house06.jpg,725000,,MA,Contracted,colonial,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house06sq.jpg,02420,Quiet Retreat +Seaport District Retreat;-71.049327;42.35695,121 Harborwalk,,3,3,caroline@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.35695,-71.049327,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house09.jpg,450000,,MA,Available,contemporary,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house09sq.jpg,02420,Seaport District Retreat +Stunning Colonial;-71.110448;42.360642,32 Prince St,,4,5,jen@dreamhouse.demo,Cambridge,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.360642,-71.110448,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house04.jpg,930000,,MA,Available,colonial,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house04sq.jpg,02420,Stunning Colonial +Stunning Victorian;-71.11095;42.35663,18 Henry St,,3,4,caroline@dreamhouse.demo,Cambridge,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.35663,-71.11095,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house01.jpg,975000,,MA,Available,victorian,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house01sq.jpg,01742,Stunning Victorian +Ultimate Sophistication;-71.10869;42.359103,24 Pearl St,,4,5,michael@dreamhouse.demo,Cambridge,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.359103,-71.10869,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house02.jpg,1200000,,MA,Contracted,colonial,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house02sq.jpg,02420,Ultimate Sophistication +Waterfront in the City;-71.084454;42.368168,110 Baxter Street,,2,3,olivia@dreamhouse.demo,Boston,,,,2024-07-27,,Lorem ipsum dolor sit amet,42.368168,-71.084454,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house05.jpg,850000,,MA,Closed,contemporary,https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house05sq.jpg,02420,Waterfront in the City diff --git a/data/sfdmu/Individual.csv b/data/sfdmu/Individual.csv new file mode 100644 index 0000000..e69de29 diff --git a/data/sfdmu/MissingParentRecordsReport.csv b/data/sfdmu/MissingParentRecordsReport.csv new file mode 100644 index 0000000..e69de29 diff --git a/data/sfdmu/export.json b/data/sfdmu/export.json new file mode 100644 index 0000000..193602f --- /dev/null +++ b/data/sfdmu/export.json @@ -0,0 +1,20 @@ +{ + "objects": [ + { + "query": "SELECT readonly_false FROM Hutte__Broker__c ORDER BY Name ASC", + "operation": "Upsert", + "externalId": "Hutte__Email__c" + }, + { + "query": "SELECT readonly_false FROM Hutte__Property__c ORDER BY Name ASC", + "operation": "Upsert", + "externalId": "Name;Hutte__Location__Longitude__s;Hutte__Location__Latitude__s" + }, + { + "query": "SELECT readonly_false FROM Contact ORDER BY Email,LastName,FirstName ASC", + "operation": "Upsert", + "externalId": "Email;LastName;FirstName" + } + ], + "excludeIdsFromCSVFiles": true +} diff --git a/force-app/main/default/applications/Dreamhouse.app-meta.xml b/force-app/main/default/applications/Dreamhouse.app-meta.xml new file mode 100644 index 0000000..918a290 --- /dev/null +++ b/force-app/main/default/applications/Dreamhouse.app-meta.xml @@ -0,0 +1,63 @@ + + + + View + Action override created by Lightning App Builder during activation. + Broker_Record_Page + Large + false + Flexipage + Broker__c + + + View + Action override created by Lightning App Builder during activation. + Broker_Record_Page + Small + false + Flexipage + Broker__c + + + View + Action override created by Lightning App Builder during activation. + Property_Record_Page + Large + false + Flexipage + Property__c + + + View + Action override created by Lightning App Builder during activation. + Property_Record_Page + Small + false + Flexipage + Property__c + + + #9189FE + HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA + 1 + false + + Small + Large + false + false + false + false + + Standard + all + standard-home + Property_Explorer + Property_Finder + standard-Contact + Property__c + Broker__c + standard-File + Settings + Lightning + diff --git a/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp new file mode 100644 index 0000000..43e626e --- /dev/null +++ b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp @@ -0,0 +1,41 @@ + + + + +
+ + + + + {!v.left} + + + {!v.center} + + + {!v.right} + + + + + + + + {!v.left} {!v.center} {!v.right} + + + +
+
\ No newline at end of file diff --git a/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp-meta.xml b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp-meta.xml new file mode 100644 index 0000000..8aa7f3b --- /dev/null +++ b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + A Lightning Component Bundle + diff --git a/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.design b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.design new file mode 100644 index 0000000..5bab1af --- /dev/null +++ b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.design @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.svg b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.svg new file mode 100644 index 0000000..791b3c7 --- /dev/null +++ b/force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/classes/FileUtilities.cls b/force-app/main/default/classes/FileUtilities.cls new file mode 100644 index 0000000..f855c8a --- /dev/null +++ b/force-app/main/default/classes/FileUtilities.cls @@ -0,0 +1,29 @@ +public with sharing class FileUtilities { + @AuraEnabled + public static String createFile(String base64data, String filename, String recordId) { + try { + ContentVersion contentVersion = new ContentVersion(); + contentVersion.VersionData = EncodingUtil.base64Decode(base64data); + contentVersion.Title = filename; + contentVersion.PathOnClient = filename; + insert contentVersion; + + contentVersion = [ + SELECT ContentDocumentId + FROM ContentVersion + WHERE Id = :contentVersion.Id + WITH USER_MODE + ]; + + ContentDocumentLink contentDocumentLink = new ContentDocumentLink(); + contentDocumentLink.ContentDocumentId = contentVersion.ContentDocumentId; + contentDocumentLink.LinkedEntityId = recordId; + contentDocumentLink.ShareType = 'V'; + insert contentDocumentLink; + + return contentDocumentLink.Id; + } catch (Exception e) { + throw new AuraHandledException('Error creating file: ' + e); + } + } +} diff --git a/force-app/main/default/classes/FileUtilities.cls-meta.xml b/force-app/main/default/classes/FileUtilities.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/FileUtilities.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/FileUtilitiesTest.cls b/force-app/main/default/classes/FileUtilitiesTest.cls new file mode 100644 index 0000000..bf45ac6 --- /dev/null +++ b/force-app/main/default/classes/FileUtilitiesTest.cls @@ -0,0 +1,76 @@ +@isTest +private with sharing class FileUtilitiesTest { + @isTest + static void createFileSucceedsWhenCorrectInput() { + // GIVEN + Property__c property = new Property__c(); + insert property; + + String base64Data = '/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb'; + String fileName = 'file.png'; + String recordId = property.Id; + + // WHEN + String contentDocumentLinkId = FileUtilities.createFile(base64Data, fileName, recordId); + + // THEN + Assert.isNotNull(contentDocumentLinkId); + } + + @isTest + static void createFileFailsWhenIncorrectRecordId() { + // GIVEN + String base64Data = '/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb'; + String fileName = 'file.png'; + String recordId = 'INVALID_ID'; + + try { + // WHEN + String contentDocumentLinkId = FileUtilities.createFile(base64Data, fileName, recordId); + Assert.fail('Expected an AuraHandledException'); + } catch (Exception e) { + // THEN + Assert.isInstanceOfType(e, AuraHandledException.class); + } + } + + @isTest + static void createFileFailsWhenIncorrectBase64Data() { + // GIVEN + Property__c property = new Property__c(); + insert property; + + String base64Data = ''; + String fileName = 'file.png'; + String recordId = property.Id; + + try { + // WHEN + String contentDocumentLinkId = FileUtilities.createFile(base64Data, fileName, recordId); + Assert.fail('Expected an AuraHandledException'); + } catch (Exception e) { + // THEN + Assert.isInstanceOfType(e, AuraHandledException.class); + } + } + + @isTest + static void createFileFailsWhenIncorrectFilename() { + // GIVEN + Property__c property = new Property__c(); + insert property; + + String base64Data = '/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb'; + String fileName = ''; + String recordId = property.Id; + + try { + // WHEN + String contentDocumentLinkId = FileUtilities.createFile(base64Data, fileName, recordId); + Assert.fail('Expected an AuraHandledException'); + } catch (Exception e) { + // THEN + Assert.isInstanceOfType(e, AuraHandledException.class); + } + } +} diff --git a/force-app/main/default/classes/FileUtilitiesTest.cls-meta.xml b/force-app/main/default/classes/FileUtilitiesTest.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/FileUtilitiesTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/GeocodingService.cls b/force-app/main/default/classes/GeocodingService.cls new file mode 100644 index 0000000..e882a26 --- /dev/null +++ b/force-app/main/default/classes/GeocodingService.cls @@ -0,0 +1,72 @@ +public with sharing class GeocodingService { + private static final String BASE_URL = 'https://nominatim.openstreetmap.org/search?format=json'; + + @InvocableMethod(callout=true label='Geocode address') + public static List geocodeAddresses( + List addresses + ) { + List computedCoordinates = new List(); + + for (GeocodingAddress address : addresses) { + String geocodingUrl = BASE_URL; + geocodingUrl += (String.isNotBlank(address.street)) + ? '&street=' + address.street + : ''; + geocodingUrl += (String.isNotBlank(address.city)) + ? '&city=' + address.city + : ''; + geocodingUrl += (String.isNotBlank(address.state)) + ? '&state=' + address.state + : ''; + geocodingUrl += (String.isNotBlank(address.country)) + ? '&country=' + address.country + : ''; + geocodingUrl += (String.isNotBlank(address.postalcode)) + ? '&postalcode=' + address.postalcode + : ''; + + Coordinates coords = new Coordinates(); + if (geocodingUrl != BASE_URL) { + Http http = new Http(); + HttpRequest request = new HttpRequest(); + request.setEndpoint(geocodingUrl); + request.setMethod('GET'); + request.setHeader( + 'http-referer', + URL.getOrgDomainUrl().toExternalForm() + ); + HttpResponse response = http.send(request); + if (response.getStatusCode() == 200) { + List deserializedCoords = (List) JSON.deserialize( + response.getBody(), + List.class + ); + coords = deserializedCoords[0]; + } + } + + computedCoordinates.add(coords); + } + return computedCoordinates; + } + + public class GeocodingAddress { + @InvocableVariable + public String street; + @InvocableVariable + public String city; + @InvocableVariable + public String state; + @InvocableVariable + public String country; + @InvocableVariable + public String postalcode; + } + + public class Coordinates { + @InvocableVariable + public Decimal lat; + @InvocableVariable + public Decimal lon; + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/GeocodingService.cls-meta.xml b/force-app/main/default/classes/GeocodingService.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/GeocodingService.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/GeocodingServiceTest.cls b/force-app/main/default/classes/GeocodingServiceTest.cls new file mode 100644 index 0000000..4ebde07 --- /dev/null +++ b/force-app/main/default/classes/GeocodingServiceTest.cls @@ -0,0 +1,100 @@ +@isTest +private with sharing class GeocodingServiceTest { + private static final String STREET = 'Camino del Jueves 26'; + private static final String CITY = 'Armilla'; + private static final String POSTAL_CODE = '18100'; + private static final String STATE = 'Granada'; + private static final String COUNTRY = 'Spain'; + private static final Decimal LATITUDE = 3.123; + private static final Decimal LONGITUDE = 31.333; + + @isTest + static void successResponse() { + // GIVEN + GeocodingService.GeocodingAddress address = new GeocodingService.GeocodingAddress(); + address.street = STREET; + address.city = CITY; + address.postalcode = POSTAL_CODE; + address.state = STATE; + address.country = COUNTRY; + + Test.setMock( + HttpCalloutMock.class, + new OpenStreetMapHttpCalloutMockImpl() + ); + + // WHEN + List computedCoordinates = GeocodingService.geocodeAddresses( + new List{ address } + ); + + // THEN + Assert.areEqual(1, computedCoordinates.size()); + Assert.areEqual(LATITUDE, computedCoordinates[0].lat); + Assert.areEqual(LONGITUDE, computedCoordinates[0].lon); + } + @isTest + static void blankAddress() { + // GIVEN + GeocodingService.GeocodingAddress address = new GeocodingService.GeocodingAddress(); + + Test.setMock( + HttpCalloutMock.class, + new OpenStreetMapHttpCalloutMockImpl() + ); + + // WHEN + List computedCoordinates = GeocodingService.geocodeAddresses( + new List{ address } + ); + + // THEN + Assert.areEqual(1, computedCoordinates.size()); + Assert.isNull(computedCoordinates[0].lat); + Assert.isNull(computedCoordinates[0].lon); + } + @isTest + static void errorResponse() { + // GIVEN + GeocodingService.GeocodingAddress address = new GeocodingService.GeocodingAddress(); + address.street = STREET; + address.city = CITY; + address.postalcode = POSTAL_CODE; + address.state = STATE; + address.country = COUNTRY; + + Test.setMock( + HttpCalloutMock.class, + new OpenStreetMapHttpCalloutMockImplError() + ); + + // WHEN + List computedCoordinates = GeocodingService.geocodeAddresses( + new List{ address } + ); + + // THEN + Assert.areEqual(1, computedCoordinates.size()); + Assert.isNull(computedCoordinates[0].lat); + Assert.isNull(computedCoordinates[0].lon); + } + + public class OpenStreetMapHttpCalloutMockImpl implements HttpCalloutMock { + public HTTPResponse respond(HTTPRequest req) { + HttpResponse res = new HttpResponse(); + res.setHeader('Content-Type', 'application/json'); + res.setBody('[{"lat": ' + LATITUDE + ',"lon": ' + LONGITUDE + '}]'); + res.setStatusCode(200); + return res; + } + } + + public class OpenStreetMapHttpCalloutMockImplError implements HttpCalloutMock { + public HTTPResponse respond(HTTPRequest req) { + HttpResponse res = new HttpResponse(); + res.setHeader('Content-Type', 'application/json'); + res.setStatusCode(400); + return res; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/GeocodingServiceTest.cls-meta.xml b/force-app/main/default/classes/GeocodingServiceTest.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/GeocodingServiceTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/PagedResult.cls b/force-app/main/default/classes/PagedResult.cls new file mode 100644 index 0000000..8adf001 --- /dev/null +++ b/force-app/main/default/classes/PagedResult.cls @@ -0,0 +1,13 @@ +public with sharing class PagedResult { + @AuraEnabled + public Integer pageSize { get; set; } + + @AuraEnabled + public Integer pageNumber { get; set; } + + @AuraEnabled + public Integer totalItemCount { get; set; } + + @AuraEnabled + public Object[] records { get; set; } +} \ No newline at end of file diff --git a/force-app/main/default/classes/PagedResult.cls-meta.xml b/force-app/main/default/classes/PagedResult.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/PagedResult.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/PropertyController.cls b/force-app/main/default/classes/PropertyController.cls new file mode 100644 index 0000000..2292365 --- /dev/null +++ b/force-app/main/default/classes/PropertyController.cls @@ -0,0 +1,112 @@ +public with sharing class PropertyController { + private static final Decimal DEFAULT_MAX_PRICE = 9999999; + private static final Integer DEFAULT_PAGE_SIZE = 9; + + /** + * Endpoint that retrieves a paged and filtered list of properties + * @param searchKey String used for searching on property title, city and tags + * @param maxPrice Maximum price + * @param minBedrooms Minimum number of bedrooms + * @param minBathrooms Minimum number of bathrooms + * @param pageSize Number of properties per page + * @param pageNumber Page number + * @return PagedResult object holding the paged and filtered list of properties + */ + @AuraEnabled(cacheable=true scope='global') + public static PagedResult getPagedPropertyList( + String searchKey, + Decimal maxPrice, + Integer minBedrooms, + Integer minBathrooms, + Integer pageSize, + Integer pageNumber + ) { + // Normalize inputs + Decimal safeMaxPrice = maxPrice ?? DEFAULT_MAX_PRICE; + Integer safeMinBedrooms = minBedrooms ?? 0; + Integer safeMinBathrooms = minBathrooms ?? 0; + Integer safePageSize = pageSize ?? DEFAULT_PAGE_SIZE; + Integer safePageNumber = pageNumber ?? 1; + + String searchPattern = '%' + searchKey + '%'; + Integer offset = (safePageNumber - 1) * safePageSize; + + PagedResult result = new PagedResult(); + result.pageSize = safePageSize; + result.pageNumber = safePageNumber; + result.totalItemCount = [ + SELECT COUNT() + FROM Property__c + WHERE + (Name LIKE :searchPattern + OR City__c LIKE :searchPattern + OR Tags__c LIKE :searchPattern) + AND Price__c <= :safeMaxPrice + AND Beds__c >= :safeMinBedrooms + AND Baths__c >= :safeMinBathrooms + ]; + result.records = [ + SELECT + Id, + Name, + Address__c, + City__c, + State__c, + Description__c, + Price__c, + Baths__c, + Beds__c, + Thumbnail__c, + Location__Latitude__s, + Location__Longitude__s + FROM Property__c + WHERE + (Name LIKE :searchPattern + OR City__c LIKE :searchPattern + OR Tags__c LIKE :searchPattern) + AND Price__c <= :safeMaxPrice + AND Beds__c >= :safeMinBedrooms + AND Baths__c >= :safeMinBathrooms + WITH USER_MODE + ORDER BY Price__c + LIMIT :safePageSize + OFFSET :offset + ]; + return result; + } + + /** + * Endpoint that retrieves pictures associated with a property + * @param propertyId Property Id + * @return List of ContentVersion holding the pictures + */ + @AuraEnabled(cacheable=true scope='global') + public static List getPictures(Id propertyId) { + List links = [ + SELECT Id, LinkedEntityId, ContentDocument.Title + FROM ContentDocumentLink + WHERE + LinkedEntityId = :propertyId + AND ContentDocument.FileType IN ('PNG', 'JPG', 'GIF') + WITH USER_MODE + ]; + + if (links.isEmpty()) { + return null; + } + + Set contentIds = new Set(); + + for (ContentDocumentLink link : links) { + contentIds.add(link.ContentDocumentId); + } + + return [ + SELECT Id, Title + FROM ContentVersion + WHERE ContentDocumentId IN :contentIds AND IsLatest = TRUE + WITH USER_MODE + ORDER BY CreatedDate + ]; + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/PropertyController.cls-meta.xml b/force-app/main/default/classes/PropertyController.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/PropertyController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/SampleDataController.cls b/force-app/main/default/classes/SampleDataController.cls new file mode 100644 index 0000000..23b8b79 --- /dev/null +++ b/force-app/main/default/classes/SampleDataController.cls @@ -0,0 +1,63 @@ +public with sharing class SampleDataController { + @AuraEnabled + public static void importSampleData() { + delete [SELECT Id FROM Case]; + delete [SELECT Id FROM Property__c]; + delete [SELECT Id FROM Broker__c]; + delete [SELECT Id FROM Contact]; + + insertBrokers(); + insertProperties(); + insertContacts(); + } + + private static void insertBrokers() { + StaticResource brokersResource = [ + SELECT Id, Body + FROM StaticResource + WHERE Name = 'sample_data_brokers' + ]; + String brokersJSON = brokersResource.body.toString(); + List brokers = (List) JSON.deserialize( + brokersJSON, + List.class + ); + insert brokers; + } + + private static void insertProperties() { + StaticResource propertiesResource = [ + SELECT Id, Body + FROM StaticResource + WHERE Name = 'sample_data_properties' + ]; + String propertiesJSON = propertiesResource.body.toString(); + List properties = (List) JSON.deserialize( + propertiesJSON, + List.class + ); + randomizeDateListed(properties); + insert properties; + } + + private static void insertContacts() { + StaticResource contactsResource = [ + SELECT Id, Body + FROM StaticResource + WHERE Name = 'sample_data_contacts' + ]; + String contactsJSON = contactsResource.body.toString(); + List contacts = (List) JSON.deserialize( + contactsJSON, + List.class + ); + insert contacts; + } + + private static void randomizeDateListed(List properties) { + for (Property__c property : properties) { + property.Date_Listed__c = + System.today() - Integer.valueof((Math.random() * 90)); + } + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/SampleDataController.cls-meta.xml b/force-app/main/default/classes/SampleDataController.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/SampleDataController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/TestPropertyController.cls b/force-app/main/default/classes/TestPropertyController.cls new file mode 100644 index 0000000..f7e0062 --- /dev/null +++ b/force-app/main/default/classes/TestPropertyController.cls @@ -0,0 +1,121 @@ +@isTest +private class TestPropertyController { + private final static String MOCK_PICTURE_NAME = 'MockPictureName'; + + public static void createProperties(Integer amount) { + List properties = new List(); + for (Integer i = 0; i < amount; i++) { + properties.add( + new Property__c( + Name = 'Name ' + i, + Price__c = 20000, + Beds__c = 3, + Baths__c = 3 + ) + ); + } + insert properties; + } + + @isTest + static void testGetPagedPropertyList() { + Profile standardUserProfile = [ + SELECT Name, Id + FROM Profile + WHERE + UserType = 'Standard' + AND PermissionsPrivacyDataAccess = FALSE + AND PermissionsSubmitMacrosAllowed = TRUE + AND PermissionsMassInlineEdit = TRUE + LIMIT 1 + ]; + User testUser = new User( + Alias = 'standt', + Email = 'standarduser@testorg.com', + EmailEncodingKey = 'UTF-8', + LastName = 'Testing', + LanguageLocaleKey = 'en_US', + LocaleSidKey = 'en_US', + ProfileId = standardUserProfile.Id, + TimeZoneSidKey = 'America/Los_Angeles', + UserName = 'standarduser@dreamhouse-testorg.com' + ); + insert testUser; + PermissionSet ps = [ + SELECT Id + FROM PermissionSet + WHERE Name = 'dreamhouse' + ]; + insert new PermissionSetAssignment( + AssigneeId = testUser.Id, + PermissionSetId = ps.Id + ); + + // Insert test properties as admin + System.runAs(new User(Id = UserInfo.getUserId())) { + TestPropertyController.createProperties(5); + } + // Read properties as test user + System.runAs(testUser) { + Test.startTest(); + PagedResult result = PropertyController.getPagedPropertyList( + '', + 999999, + 0, + 0, + 10, + 1 + ); + Test.stopTest(); + Assert.areEqual(5, result.records.size()); + } + } + + @isTest + static void testGetPicturesNoResults() { + Property__c property = new Property__c(Name = 'Name'); + insert property; + + Test.startTest(); + List items = PropertyController.getPictures( + property.Id + ); + Test.stopTest(); + + Assert.isNull(items); + } + + @isTest + static void testGetPicturesWithResults() { + Property__c property = new Property__c(Name = 'Name'); + insert property; + + // Insert mock picture + ContentVersion picture = new Contentversion(); + picture.Title = MOCK_PICTURE_NAME; + picture.PathOnClient = 'picture.png'; + picture.Versiondata = EncodingUtil.base64Decode('MockValue'); + insert picture; + + // Link picture to property record + List documents = [ + SELECT Id, Title, LatestPublishedVersionId + FROM ContentDocument + LIMIT 1 + ]; + ContentDocumentLink link = new ContentDocumentLink(); + link.LinkedEntityId = property.Id; + link.ContentDocumentId = documents[0].Id; + link.shareType = 'V'; + insert link; + + Test.startTest(); + List items = PropertyController.getPictures( + property.Id + ); + Test.stopTest(); + + Assert.areEqual(1, items.size()); + Assert.areEqual(MOCK_PICTURE_NAME, items[0].Title); + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/TestPropertyController.cls-meta.xml b/force-app/main/default/classes/TestPropertyController.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/TestPropertyController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/classes/TestSampleDataController.cls b/force-app/main/default/classes/TestSampleDataController.cls new file mode 100644 index 0000000..f30fd0b --- /dev/null +++ b/force-app/main/default/classes/TestSampleDataController.cls @@ -0,0 +1,17 @@ +@isTest +private class TestSampleDataController { + @isTest + static void importSampleData() { + Test.startTest(); + SampleDataController.importSampleData(); + Test.stopTest(); + + Integer propertyNumber = [SELECT COUNT() FROM Property__c]; + Integer brokerNumber = [SELECT COUNT() FROM Broker__c]; + Integer contactNumber = [SELECT COUNT() FROM Contact]; + + Assert.isTrue(propertyNumber > 0, 'Expected properties were created.'); + Assert.isTrue(brokerNumber > 0, 'Expected brokers were created.'); + Assert.isTrue(contactNumber > 0, 'Expected contacts were created.'); + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/TestSampleDataController.cls-meta.xml b/force-app/main/default/classes/TestSampleDataController.cls-meta.xml new file mode 100644 index 0000000..651b172 --- /dev/null +++ b/force-app/main/default/classes/TestSampleDataController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + Active + diff --git a/force-app/main/default/contentassets/HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA.asset b/force-app/main/default/contentassets/HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA.asset new file mode 100644 index 0000000..30bd6ab Binary files /dev/null and b/force-app/main/default/contentassets/HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA.asset differ diff --git a/force-app/main/default/contentassets/HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA.asset-meta.xml b/force-app/main/default/contentassets/HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA.asset-meta.xml new file mode 100644 index 0000000..d310b15 --- /dev/null +++ b/force-app/main/default/contentassets/HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA.asset-meta.xml @@ -0,0 +1,17 @@ + + + false + en_US + HUTTE_LOGOTYPE_MAIN_SYMBOL_ALPHA + + + VIEWER + + + + + 1 + HUTTE LOGOTYPE_MAIN SYMBOL ALPHA.png + + + diff --git a/force-app/main/default/contentassets/dreamhouselogosquare.asset b/force-app/main/default/contentassets/dreamhouselogosquare.asset new file mode 100644 index 0000000..4fef8da Binary files /dev/null and b/force-app/main/default/contentassets/dreamhouselogosquare.asset differ diff --git a/force-app/main/default/contentassets/dreamhouselogosquare.asset-meta.xml b/force-app/main/default/contentassets/dreamhouselogosquare.asset-meta.xml new file mode 100644 index 0000000..b79ecb3 --- /dev/null +++ b/force-app/main/default/contentassets/dreamhouselogosquare.asset-meta.xml @@ -0,0 +1,17 @@ + + + false + en_US + dreamhouselogosquare + + + VIEWER + + + + + 1 + dreamhouse-logo-square.png + + + diff --git a/force-app/main/default/cspTrustedSites/openStreetMap.cspTrustedSite-meta.xml b/force-app/main/default/cspTrustedSites/openStreetMap.cspTrustedSite-meta.xml new file mode 100644 index 0000000..747f89d --- /dev/null +++ b/force-app/main/default/cspTrustedSites/openStreetMap.cspTrustedSite-meta.xml @@ -0,0 +1,15 @@ + + + false + false + LEX + OpenStreetMap tiles + https://tile.openstreetmap.org + true + false + false + false + true + false + false + diff --git a/force-app/main/default/cspTrustedSites/s3_us_west_2_amazonaws_com.cspTrustedSite-meta.xml b/force-app/main/default/cspTrustedSites/s3_us_west_2_amazonaws_com.cspTrustedSite-meta.xml new file mode 100644 index 0000000..632db8d --- /dev/null +++ b/force-app/main/default/cspTrustedSites/s3_us_west_2_amazonaws_com.cspTrustedSite-meta.xml @@ -0,0 +1,15 @@ + + + false + false + LEX + Amazon S3 hosted sample app media + https://s3-us-west-2.amazonaws.com + true + false + false + false + true + false + false + diff --git a/force-app/main/default/flexipages/Broker_Record_Page.flexipage-meta.xml b/force-app/main/default/flexipages/Broker_Record_Page.flexipage-meta.xml new file mode 100644 index 0000000..6607679 --- /dev/null +++ b/force-app/main/default/flexipages/Broker_Record_Page.flexipage-meta.xml @@ -0,0 +1,378 @@ + + + + + + + collapsed + false + + + enableActionsConfiguration + false + + + hideChatterActions + false + + + numVisibleActions + 3 + + force:highlightsPanel + force_highlightsPanel + + + Replace + header + Region + + + + + + relatedListComponentOverride + NONE + + + rowsToDisplay + 10 + + + showActionBar + true + + force:relatedListContainer + force_relatedListContainer + + + Replace + relatedTabContent + Facet + + + + + + uiBehavior + readonly + + Record.Picture_IMG__c + RecordPicture_IMG__cField + + + + + + uiBehavior + none + + Record.Picture__c + RecordPicture__cField + + + Facet-1bc3dd0f-6743-478f-8d51-2bb48e689fb5 + Facet + + + + + + body + Facet-1bc3dd0f-6743-478f-8d51-2bb48e689fb5 + + flexipage:column + flexipage_column + + + Facet-410fbc19-10c0-4677-8608-2cb7d8d102b3 + Facet + + + + + + uiBehavior + required + + Record.Name + RecordNameField + + + + + + uiBehavior + none + + Record.Title__c + RecordTitle__cField + + + + + + uiBehavior + none + + Record.Email__c + RecordEmail__cField + + + Facet-4885c180-b6bf-40af-bc91-3d83e2f7627b + Facet + + + + + + uiBehavior + none + + Record.Phone__c + RecordPhone__cField + + + + + + uiBehavior + none + + Record.Mobile_Phone__c + RecordMobile_Phone__cField + + + + + + uiBehavior + none + + Record.OwnerId + RecordOwnerIdField + + + Facet-1fcbd98c-c9c7-4a47-ad59-f4bfcd05d5a2 + Facet + + + + + + body + Facet-4885c180-b6bf-40af-bc91-3d83e2f7627b + + flexipage:column + flexipage_column2 + + + + + + body + Facet-1fcbd98c-c9c7-4a47-ad59-f4bfcd05d5a2 + + flexipage:column + flexipage_column3 + + + Facet-7da398a8-59d5-4a99-a9ea-dfac94d7055f + Facet + + + + + + uiBehavior + readonly + + Record.CreatedById + RecordCreatedByIdField + + + Facet-9e941d2d-a3ed-4186-99e4-40cfe151b0fa + Facet + + + + + + uiBehavior + readonly + + Record.LastModifiedById + RecordLastModifiedByIdField + + + Facet-f7173fe8-e18a-4fbd-8898-53927906768d + Facet + + + + + + body + Facet-9e941d2d-a3ed-4186-99e4-40cfe151b0fa + + flexipage:column + flexipage_column4 + + + + + + body + Facet-f7173fe8-e18a-4fbd-8898-53927906768d + + flexipage:column + flexipage_column5 + + + Facet-4fdd7013-0316-404e-a707-2618d3582ae5 + Facet + + + + + + columns + Facet-410fbc19-10c0-4677-8608-2cb7d8d102b3 + + + label + Picture + + flexipage:fieldSection + flexipage_fieldSection + + + + + + columns + Facet-7da398a8-59d5-4a99-a9ea-dfac94d7055f + + + label + Information + + flexipage:fieldSection + flexipage_fieldSection2 + + + + + + columns + Facet-4fdd7013-0316-404e-a707-2618d3582ae5 + + + label + System Information + + flexipage:fieldSection + flexipage_fieldSection3 + + + + + force:recordDetailPanelMobile + force_recordDetailPanelMobile + + + Replace + detailTabContent + Facet + + + + + + body + relatedTabContent + + + title + Standard.Tab.relatedLists + + flexipage:tab + relatedListsTab + + + + + + active + true + + + body + detailTabContent + + + title + Standard.Tab.detail + + flexipage:tab + detailTab + + + Replace + maintabs + Facet + + + + + + tabs + maintabs + + flexipage:tabset + flexipage_tabset + + + Replace + main + Region + + + + + + parentFieldApiName + Broker__c.Id + + + relatedListApiName + Properties__r + + + relatedListComponentOverride + NONE + + + rowsToDisplay + 10 + + + showActionBar + true + + force:relatedListSingleContainer + force_relatedListSingleContainer + + + Replace + sidebar + Region + + Broker Record Page + flexipage__default_rec_L + Broker__c + + RecordPage + diff --git a/force-app/main/default/flexipages/Property_Explorer.flexipage-meta.xml b/force-app/main/default/flexipages/Property_Explorer.flexipage-meta.xml new file mode 100644 index 0000000..019fa6f --- /dev/null +++ b/force-app/main/default/flexipages/Property_Explorer.flexipage-meta.xml @@ -0,0 +1,58 @@ + + + + + + propertyFilter + propertyFilter + + + + + + flowLayout + oneColumn + + + flowName + Create_property + + flowruntime:interview + flowruntime_interview + + + left + Region + + + + + propertyTileList + propertyTileList + + + center + Region + + + + + propertySummary + propertySummary + + + + + propertyMap + propertyMap + + + right + Region + + Property Explorer + + AppPage + diff --git a/force-app/main/default/flexipages/Property_Finder.flexipage-meta.xml b/force-app/main/default/flexipages/Property_Finder.flexipage-meta.xml new file mode 100644 index 0000000..c6e7031 --- /dev/null +++ b/force-app/main/default/flexipages/Property_Finder.flexipage-meta.xml @@ -0,0 +1,50 @@ + + + + + + barcodeScanner + c_barcodeScanner + + + + + propertyFilter + propertyFilter + + + left + Region + + + + + propertyListMap + c_propertyListMap + + + center + Region + + + + + propertySummary + propertySummary + + + + + daysOnMarket + daysOnMarket + + + right + Region + + Property Finder + + AppPage + diff --git a/force-app/main/default/flexipages/Property_Record_Page.flexipage-meta.xml b/force-app/main/default/flexipages/Property_Record_Page.flexipage-meta.xml new file mode 100644 index 0000000..9bca1a2 --- /dev/null +++ b/force-app/main/default/flexipages/Property_Record_Page.flexipage-meta.xml @@ -0,0 +1,552 @@ + + + + + + + collapsed + false + + + enableActionsConfiguration + false + + + hideChatterActions + false + + + numVisibleActions + 3 + + force:highlightsPanel + force_highlightsPanel + + + Replace + header + Region + + + + + + relatedListComponentOverride + NONE + + force:relatedListContainer + force_relatedListContainer + + + Replace + relatedTabContent + Facet + + + + + + uiBehavior + required + + Record.Name + RecordNameField + + + + + + uiBehavior + none + + Record.Address__c + RecordAddress__cField + + + + + + uiBehavior + none + + Record.State__c + RecordState__cField + + + + + + uiBehavior + none + + Record.Zip__c + RecordZip__cField + + + + + + uiBehavior + none + + Record.Tags__c + RecordTags__cField + + + + + + uiBehavior + none + + Record.Status__c + RecordStatus__cField + + + + + + uiBehavior + none + + Record.OwnerId + RecordOwnerIdField + + + Facet-eb9c4d7e-6868-43e8-9851-85aacdd3a54d + Facet + + + + + + uiBehavior + none + + Record.Picture_IMG__c + RecordPicture_IMG_cField + + + Facet-41d5d7e8-b344-4110-9175-150a259f72a8 + Facet + + + + + + body + Facet-eb9c4d7e-6868-43e8-9851-85aacdd3a54d + + flexipage:column + flexipage_column + + + + + + body + Facet-41d5d7e8-b344-4110-9175-150a259f72a8 + + flexipage:column + flexipage_column2 + + + Facet-66400b5a-c4b2-472c-af56-e7f4f40b3969 + Facet + + + + + + uiBehavior + none + + Record.Description__c + RecordDescription__cField + + + Facet-3d2d92e6-96c0-4649-a0b0-d02f5a08f655 + Facet + + + + + + body + Facet-3d2d92e6-96c0-4649-a0b0-d02f5a08f655 + + flexipage:column + flexipage_column3 + + + Facet-7e923dfb-c368-4633-ae9c-3eb3f51a73bb + Facet + + + + + + uiBehavior + readonly + + Record.CreatedById + RecordCreatedByIdField + + + Facet-89988119-afc3-4937-8a69-76d39cb3a74a + Facet + + + + + + uiBehavior + readonly + + Record.LastModifiedById + RecordLastModifiedByIdField + + + Facet-2d0a01d5-75cd-48da-b598-1e36cc2fa406 + Facet + + + + + + body + Facet-89988119-afc3-4937-8a69-76d39cb3a74a + + flexipage:column + flexipage_column4 + + + + + + body + Facet-2d0a01d5-75cd-48da-b598-1e36cc2fa406 + + flexipage:column + flexipage_column5 + + + Facet-00b780e0-4e42-4a35-854d-bec7c63f2545 + Facet + + + + + + columns + Facet-66400b5a-c4b2-472c-af56-e7f4f40b3969 + + + horizontalAlignment + false + + + label + Information + + flexipage:fieldSection + flexipage_fieldSection + + + + + + columns + Facet-7e923dfb-c368-4633-ae9c-3eb3f51a73bb + + + horizontalAlignment + false + + + label + Description + + flexipage:fieldSection + flexipage_fieldSection2 + + + + + + columns + Facet-00b780e0-4e42-4a35-854d-bec7c63f2545 + + + horizontalAlignment + false + + + label + System Information + + flexipage:fieldSection + flexipage_fieldSection3 + + + + + force:recordDetailPanelMobile + force_recordDetailPanelMobile + + + Replace + detailTabContent + Facet + + + + + + uiBehavior + none + + Record.Date_Contracted__c + RecordDate_Contracted__cField + + + + + + uiBehavior + none + + Record.Date_Pre_Market__c + RecordDate_Pre_Market__cField + + + + + + uiBehavior + none + + Record.Date_Closed__c + RecordDate_Closed__cField + + + Facet-c5e2ef33-3e0f-472c-a3bb-22376d3962e9 + Facet + + + + + + uiBehavior + none + + Record.Date_Listed__c + RecordDate_Listed__cField + + + + + + uiBehavior + none + + Record.Date_Agreement__c + RecordDate_Agreement__cField + + + Facet-1ca35247-9088-453b-a163-ef03309a958c + Facet + + + + + + body + Facet-c5e2ef33-3e0f-472c-a3bb-22376d3962e9 + + flexipage:column + flexipage_column6 + + + + + + body + Facet-1ca35247-9088-453b-a163-ef03309a958c + + flexipage:column + flexipage_column7 + + + Facet-ad40adb5-82bf-4e08-836c-f48698589d81 + Facet + + + + + + columns + Facet-ad40adb5-82bf-4e08-836c-f48698589d81 + + + horizontalAlignment + false + + + label + Dates + + flexipage:fieldSection + flexipage_fieldSection4 + + + Facet-1e191467-3189-4ef6-9dfa-5dd515d8a8f0 + Facet + + + + + brokerCard + c_brokerCard + + + Facet-be553f16-e92a-4849-9817-aaa81df23b96 + Facet + + + + + + body + relatedTabContent + + + title + Standard.Tab.relatedLists + + flexipage:tab + relatedListsTab + + + + + + active + true + + + body + detailTabContent + + + title + Standard.Tab.detail + + flexipage:tab + detailTab + + + + + + body + Facet-1e191467-3189-4ef6-9dfa-5dd515d8a8f0 + + + title + Dates + + flexipage:tab + customTab + + + + + + body + Facet-be553f16-e92a-4849-9817-aaa81df23b96 + + + title + Broker + + flexipage:tab + flexipage_tab + + + Replace + maintabs + Facet + + + + + + tabs + maintabs + + flexipage:tabset + flexipage_tabset + + + Replace + main + Region + + + + + brokerCard + c_brokerCard2 + + + + + daysOnMarket + daysOnMarket + + + {!Record.Days_On_Market__c} + GT + 0 + + + + + + + propertyMap + propertyMap + + + {!Record.Location__Latitude__s} + GT + 0 + + + + + + + propertyLocation + c_propertyLocation + + + + + propertyCarousel + propertyCarousel + + + Replace + sidebar + Region + + Property Record Page + flexipage__default_rec_L + Property__c + + RecordPage + diff --git a/force-app/main/default/flexipages/Settings.flexipage-meta.xml b/force-app/main/default/flexipages/Settings.flexipage-meta.xml new file mode 100644 index 0000000..249c99b --- /dev/null +++ b/force-app/main/default/flexipages/Settings.flexipage-meta.xml @@ -0,0 +1,26 @@ + + + + + + sampleDataImporter + sampleDataImporter + + + region1 + Region + + + region2 + Region + + + region3 + Region + + Settings + + AppPage + diff --git a/force-app/main/default/flows/Create_property.flow-meta.xml b/force-app/main/default/flows/Create_property.flow-meta.xml new file mode 100644 index 0000000..84037e0 --- /dev/null +++ b/force-app/main/default/flows/Create_property.flow-meta.xml @@ -0,0 +1,619 @@ + + + + geocode_address + + 666 + 350 + GeocodingService + apex + + property_details + + + Error5 + + CurrentTransaction + + city + + property_address.city + + + + country + + property_address.country + + + + postalcode + + property_address.postalCode + + + + state + + property_address.province + + + + street + + property_address.street + + + GeocodingService + true + 1 + + 51.0 + + If_content_document_found + + 666 + 890 + + navigate_to_record_detail + + Default Outcome + + Content_Document_Link_found + and + + get_main_content_document + IsNull + + false + + + + get_main_content_version + + + + + + if_content_version_found + + 314 + 1106 + + navigate_to_record_detail + + Default Outcome + + picture_found + and + + get_main_content_version + IsNull + + false + + + + set_main_picture + + + + + This flow helps agents creating new properties in just a few clicks. It calculates the geocoded address calling out to a 3rd party service. + Default + + Main picture URL that we'll use as thumbnail + main_picture_url + String + "/sfc/servlet.shepherd/version/download/" + {!get_main_content_version.Id} + + Create Property {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + Flow + + create_property + + 666 + 566 + + upload_picture + + + error_creating_records + + + Address__c + + property_address.street + + + + Baths__c + + number_of_baths + + + + Beds__c + + number_of_beds + + + + Broker__c + + property_broker.recordId + + + + City__c + + property_address.city + + + + Date_Listed__c + + $Flow.CurrentDate + + + + Description__c + + property_description + + + + Location__Latitude__s + + geocode_address.lat + + + + Location__Longitude__s + + geocode_address.lon + + + + Name + + property_name + + + + Price__c + + property_price + + + + State__c + + property_address.province + + + + Status__c + + Available + + + + Tags__c + + property_tags + + + + Zip__c + + property_address.postalCode + + + Property__c + true + + + Retrieve just one of the pictures to be the main one + get_main_content_document + + 666 + 782 + false + + If_content_document_found + + + Error2 + + and + + LinkedEntityId + EqualTo + + create_property + + + true + ContentDocumentLink + true + + + get_main_content_version + + 314 + 998 + false + + if_content_version_found + + + Error3 + + and + + ContentDocumentId + EqualTo + + get_main_content_document.ContentDocumentId + + + + IsLatest + EqualTo + + true + + + true + ContentVersion + true + + + set_main_picture + + 50 + 1214 + + navigate_to_record_detail + + + Error4 + + and + + Id + EqualTo + + create_property + + + + Picture__c + + main_picture_url + + + + Thumbnail__c + + main_picture_url + + + Property__c + + + address + + 666 + 242 + true + true + true + + geocode_address + + + property_address + flowruntime:address + ComponentInstance + UseStoredValues + true + true + + true + true + + + Error2 + + 1194 + 890 + true + true + true + + error2_text + <p>Unknown error retrieving uploaded picture.</p> + DisplayText + + true + true + + + Error3 + + 754 + 1106 + true + true + true + + error3_text + <p><span style="background-color: rgb(255, 255, 255); color: rgb(62, 62, 60);">Unknown error retrieving uploaded picture.</span></p> + DisplayText + + true + true + + + Error4 + + 314 + 1322 + false + true + true + + error4_text + <p><span style="background-color: rgb(255, 255, 255); color: rgb(62, 62, 60);">Unknown error setting picture as Property thumbnail.</span></p> + DisplayText + + true + true + + + Error5 + + 1722 + 458 + true + true + true + + error5_text + <p>Error retrieving geocoded address.</p> + DisplayText + + true + true + + + error_creating_records + + 1458 + 674 + false + true + true + + error + <p>Error creating records. Try again.</p> + DisplayText + + true + true + + + navigate_to_record_detail + + 666 + 1730 + false + true + true + + navigate_to_record_lwc + Hutte:navigateToRecord + ComponentInstance + + recordId + + create_property + + + UseStoredValues + true + true + + true + true + + + new_property + + 666 + 134 + true + true + true + + address + + + property_name + String + Property Name + InputField + UseStoredValues + true + + + property_description + String + Description + InputField + UseStoredValues + false + + + property_broker + flowruntime:lookup + ComponentInstance + + fieldApiName + + Hutte__Broker__c + + + + label + + Broker + + + + objectApiName + + Hutte__Property__c + + + UseStoredValues + true + true + + + property_price + Currency + + 100000.0 + + Price + InputField + UseStoredValues + true + 0 + + true + true + + + property_details + + 666 + 458 + true + true + true + + create_property + + + number_of_beds + Number + + 4.0 + + Number of Bedrooms + InputField + UseStoredValues + false + 0 + + + number_of_baths + Number + + 2.0 + + Number of Bathrooms + InputField + UseStoredValues + false + 0 + + + property_tags + String + Tags + InputField + UseStoredValues + false + + true + true + + + upload_picture + + 666 + 674 + false + true + true + + get_main_content_document + + + property_picture + forceContent:fileUpload + ComponentInstance + + label + + Upload Picture + + + + accept + + .jpg,.png,.gif + + + + recordId + + create_property + + + + multiple + + true + + + UseStoredValues + true + true + + true + true + + + 540 + 0 + + new_property + + + Active + diff --git a/force-app/main/default/lwc/.eslintrc.json b/force-app/main/default/lwc/.eslintrc.json new file mode 100644 index 0000000..0fc06c0 --- /dev/null +++ b/force-app/main/default/lwc/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "extends": ["@salesforce/eslint-config-lwc/recommended"], + "overrides": [ + { + "files": ["*.test.js"], + "rules": { + "@lwc/lwc/no-unexpected-wire-adapter-usages": "off" + }, + "env": { + "node": true + } + } + ] +} diff --git a/force-app/main/default/lwc/barcodeScanner/__tests__/barcodeScanner.test.js b/force-app/main/default/lwc/barcodeScanner/__tests__/barcodeScanner.test.js new file mode 100644 index 0000000..f527601 --- /dev/null +++ b/force-app/main/default/lwc/barcodeScanner/__tests__/barcodeScanner.test.js @@ -0,0 +1,183 @@ +import { createElement } from 'lwc'; +import { getNavigateCalledWith } from 'lightning/navigation'; +import BarcodeScanner from 'c/barcodeScanner'; + +// Mock various barcode functionality from mobileCapabilites.js +import { + resetBarcodeScannerStubs, + setBarcodeScannerAvailable, + setUserCanceledScan, + setBarcodeScanError +} from 'lightning/mobileCapabilities'; + +// Enable spying on toast event data +import { ShowToastEventName } from 'lightning/platformShowToastEvent'; + +describe('c-barcode-scanner-example', () => { + afterEach(() => { + // Reset the JSDOM instance shared across test cases in a single file + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + + // Prevent data saved on mocks from leaking between tests + jest.clearAllMocks(); + + // Reset stubs + resetBarcodeScannerStubs(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous/DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('directs the user to the mobile app when Barcode Scanner is unavailable', async () => { + // Create initial BarcodeScanner element and attach to virtual DOM + const elementBarcodeScanner = createElement( + 'c-barcode-scanner-example', + { is: BarcodeScanner } + ); + document.body.appendChild(elementBarcodeScanner); + + // Mount `Scan QR Code` button and trigger scan of property record ID + const elementScannerDirections = + elementBarcodeScanner.shadowRoot.querySelector( + '[data-test="scanner-directions"]' + ); + + expect(elementScannerDirections).not.toBeNull(); + }); + + it('shows the `Scan QR Code` button when BarcodeScanner is available', async () => { + // Create initial BarcodeScanner element and attach to virtual DOM + const elementBarcodeScanner = createElement( + 'c-barcode-scanner-example', + { is: BarcodeScanner } + ); + // Stub barcodeScanner as available + setBarcodeScannerAvailable(); + + document.body.appendChild(elementBarcodeScanner); + + // Mount `Scan QR Code` button and trigger scan of property record ID + const elementScanQRCodeButton = + elementBarcodeScanner.shadowRoot.querySelector('lightning-button'); + + expect(elementScanQRCodeButton).not.toBeNull(); + }); + + it('navigates to the expected record view when a QR code is correctly scanned', async () => { + // Property record values to compare component output against + const NAV_TYPE = 'standard__recordPage'; + const NAV_ACTION_NAME = 'view'; + const NAV_RECORD_ID = '0031700000pJRRWAA4'; + + // Stub barcodeScanner availability to true + setBarcodeScannerAvailable(); + + // Create initial BarcodeScanner element and attach to virtual DOM + const elementBarcodeScanner = createElement( + 'c-barcode-scanner-example', + { is: BarcodeScanner } + ); + document.body.appendChild(elementBarcodeScanner); + + // Mount `Scan QR Code` button and trigger scan of property record ID + const elementScanQRCodeButton = + elementBarcodeScanner.shadowRoot.querySelector('lightning-button'); + elementScanQRCodeButton.click(); + + // Wait for async scan function to settle + await flushPromises(); + + // Get data the NavigationMixin was called with + const { pageReference } = getNavigateCalledWith(); + + // Confirm redirection to expected property record + expect(pageReference.type).toBe(NAV_TYPE); + expect(pageReference.attributes.actionName).toBe(NAV_ACTION_NAME); + expect(pageReference.attributes.recordId).toBe(NAV_RECORD_ID); + }); + + it('triggers an error toast notification when the user cancels the scan', async () => { + // Stub barcodeScanner as available + setBarcodeScannerAvailable(); + + // Mock user canceling the scan + setUserCanceledScan(); + + // Mock handler for toast event + const toastEventSpy = jest.fn(); + + // Create initial BarcodeScanner element and attach to virtual DOM + const elementBarcodeScanner = createElement( + 'c-barcode-scanner-example', + { is: BarcodeScanner } + ); + document.body.appendChild(elementBarcodeScanner); + + // Add toast event listener to component + elementBarcodeScanner.addEventListener( + ShowToastEventName, + toastEventSpy + ); + + // Mount `Scan QR Code` button and trigger scan of property record ID + const elementScanQRCodeButton = + elementBarcodeScanner.shadowRoot.querySelector('lightning-button'); + elementScanQRCodeButton.click(); + + // Wait for element to mount + await flushPromises(); + + // Check that cancelation toast was triggered + + // Check if toast event has been fired + expect(toastEventSpy).toHaveBeenCalled(); + expect(toastEventSpy.mock.calls[0][0].detail.title).toBe( + 'Scanning Canceled' + ); + }); + + it('shows an error toast when there was a problem with the scan', async () => { + // Stub barcodeScanner as available + setBarcodeScannerAvailable(); + + // Mock scan erroring out + setBarcodeScanError(); + + // Mock handler for toast event + const toastEventSpy = jest.fn(); + + // Create initial BarcodeScanner element and attach to virtual DOM + const elementBarcodeScanner = createElement( + 'c-barcode-scanner-example', + { + is: BarcodeScanner + } + ); + document.body.appendChild(elementBarcodeScanner); + + // Add toast event listener to component + elementBarcodeScanner.addEventListener( + ShowToastEventName, + toastEventSpy + ); + + // Mount `Scan QR Code` button and trigger scan of property record ID + const elementScanQRCodeButton = + elementBarcodeScanner.shadowRoot.querySelector('lightning-button'); + elementScanQRCodeButton.click(); + + // Wait for element to mount + await flushPromises(); + + // Check that generic BarcodeScanner toast was triggered + expect(toastEventSpy).toHaveBeenCalled(); + expect(toastEventSpy.mock.calls[0][0].detail.title).toBe( + 'Barcode Scanner Error' + ); + }); +}); diff --git a/force-app/main/default/lwc/barcodeScanner/barcodeScanner.html b/force-app/main/default/lwc/barcodeScanner/barcodeScanner.html new file mode 100644 index 0000000..ce1f7e4 --- /dev/null +++ b/force-app/main/default/lwc/barcodeScanner/barcodeScanner.html @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/barcodeScanner/barcodeScanner.js b/force-app/main/default/lwc/barcodeScanner/barcodeScanner.js new file mode 100644 index 0000000..bf7c0be --- /dev/null +++ b/force-app/main/default/lwc/barcodeScanner/barcodeScanner.js @@ -0,0 +1,80 @@ +import { LightningElement } from 'lwc'; +import { NavigationMixin } from 'lightning/navigation'; +import { ShowToastEvent } from 'lightning/platformShowToastEvent'; +import { getBarcodeScanner } from 'lightning/mobileCapabilities'; + +export default class BarcodeScanner extends NavigationMixin(LightningElement) { + myScanner; + scanButtonEnabled = false; + scannedQrCode = ''; + + // When the component is initialized, determine whether to enable the Scan button + connectedCallback() { + this.myScanner = getBarcodeScanner(); + if (this.myScanner?.isAvailable()) { + this.scanButtonEnabled = true; + } + } + + async handleBeginScanClick() { + // Reset scannedQrCode to empty string before starting a new scan + this.scannedQrCode = ''; + + // Make sure BarcodeScanner is available before trying to use it + // Scan QR Code button also disabled when scanner unavailable + if (this.myScanner?.isAvailable()) { + const scanningOptions = { + barcodeTypes: [this.myScanner.barcodeTypes.QR], + instructionText: 'Scan a QR Code', + successText: 'Scanning complete.' + }; + + // Try starting the scanning process, then using the result to navigate to a property record + try { + const captureResult = await this.myScanner.beginCapture(scanningOptions); + + // Extract QR code data + this.scannedQrCode = captureResult.value; + + // Navigate to the records page of the property with extracted ID + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + recordId: this.scannedQrCode, + objectApiName: 'Hutte__Property__c', + actionName: 'view' + } + }); + } catch (error) { + // There was an error while scanning + // We chose to handle errors with toasts to stay in line with the mobile experience + // The user canceled the scan + if (error.code === 'userDismissedScanner') { + this.dispatchEvent( + new ShowToastEvent({ + title: 'Scanning Canceled', + message: 'Scanning session canceled.', + mode: 'sticky' + }) + ); + } + + // There was some other kind of error + else { + // Inform the user we ran into something unexpected + this.dispatchEvent( + new ShowToastEvent({ + title: 'Barcode Scanner Error', + message: 'There was a problem scanning the QR code: ' + error.message, + variant: 'error', + mode: 'sticky' + }) + ); + } + } finally { + // Close capture process regardless of whether we completed successfully or had an error + this.myScanner.endCapture(); + } + } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/barcodeScanner/barcodeScanner.js-meta.xml b/force-app/main/default/lwc/barcodeScanner/barcodeScanner.js-meta.xml new file mode 100644 index 0000000..399a37a --- /dev/null +++ b/force-app/main/default/lwc/barcodeScanner/barcodeScanner.js-meta.xml @@ -0,0 +1,17 @@ + + + 61.0 + true + Barcode Scanner + + lightning__AppPage + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/brokerCard/__tests__/brokerCard.test.js b/force-app/main/default/lwc/brokerCard/__tests__/brokerCard.test.js new file mode 100644 index 0000000..527b6e5 --- /dev/null +++ b/force-app/main/default/lwc/brokerCard/__tests__/brokerCard.test.js @@ -0,0 +1,181 @@ +import { createElement } from 'lwc'; +import BrokerCard from 'c/brokerCard'; +import { getNavigateCalledWith } from 'lightning/navigation'; +import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; + +// Mock realistic data +const mockGetPropertyRecord = require('./data/getPropertyRecord.json'); + +const BROKER_ID = 'a003h000003xlBiAAI'; + +const BROKER_FIELDS_INPUT = [ + { + fieldApiName: 'Name', + objectApiName: 'Broker__c' + }, + { + fieldApiName: 'Phone__c', + objectApiName: 'Broker__c' + }, + { + fieldApiName: 'Mobile_Phone__c', + objectApiName: 'Broker__c' + }, + { + fieldApiName: 'Email__c', + objectApiName: 'Broker__c' + } +]; + +describe('c-broker-card', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + + // Prevent data saved on mocks from leaking between tests + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. This is needed for promise + // timing. + async function flushPromises() { + return Promise.resolve(); + } + + describe('broker record form', () => { + it('gets property data from wire service', async () => { + // Create element + const element = createElement('c-broker-card', { + is: BrokerCard + }); + document.body.appendChild(element); + + // Emit data from @wire + getRecord.emit(mockGetPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const propertyEl = element.shadowRoot.querySelector( + 'lightning-record-form' + ); + expect(getFieldValue).toHaveBeenCalled(); + expect(propertyEl.recordId).toBe(BROKER_ID); + }); + + it('renders lightning-record-form with given input values', async () => { + // Create element + const element = createElement('c-broker-card', { + is: BrokerCard + }); + document.body.appendChild(element); + + // Emit data from @wire + getRecord.emit(mockGetPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const propertyEl = element.shadowRoot.querySelector( + 'lightning-record-form' + ); + expect(propertyEl.fields).toEqual(BROKER_FIELDS_INPUT); + expect(propertyEl.recordId).toBe(BROKER_ID); + }); + }); + + describe('navigate to broker record', () => { + it('navigates to record view', async () => { + // Nav param values to test later + const NAV_TYPE = 'standard__recordPage'; + const NAV_OBJECT_API_NAME = 'Property__c'; + const NAV_ACTION_NAME = 'view'; + const NAV_RECORD_ID = BROKER_ID; + + // Create initial lwc element and attach to virtual DOM + const element = createElement('c-broker-card', { + is: BrokerCard + }); + document.body.appendChild(element); + + // Simulate the data sent over wire adapter to hydrate the wired property + getRecord.emit(mockGetPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Get handle to view button and fire click event + const buttonEl = element.shadowRoot.querySelector( + 'lightning-button-icon' + ); + buttonEl.click(); + + const { pageReference } = getNavigateCalledWith(); + // Verify component called with correct event type and params + expect(pageReference.type).toBe(NAV_TYPE); + expect(pageReference.attributes.objectApiName).toBe( + NAV_OBJECT_API_NAME + ); + expect(pageReference.attributes.actionName).toBe(NAV_ACTION_NAME); + expect(pageReference.attributes.recordId).toBe(NAV_RECORD_ID); + }); + }); + + describe('error panel', () => { + it('renders error if data is not retrieved successfully', async () => { + const WIRE_ERROR = 'Something bad happened'; + + // Create element and attach to virtual DOM + const element = createElement('c-broker-card', { + is: BrokerCard + }); + document.body.appendChild(element); + + getRecord.error(WIRE_ERROR); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const errorPanelEl = + element.shadowRoot.querySelector('c-error-panel'); + expect(errorPanelEl).not.toBeNull(); + expect(errorPanelEl.errors.body).toBe(WIRE_ERROR); + expect(errorPanelEl.friendlyMessage).toBe('Error retrieving data'); + }); + }); + + it('is accessible when property returned', async () => { + const element = createElement('c-broker-card', { + is: BrokerCard + }); + + document.body.appendChild(element); + + // Emit data from @wire + getRecord.emit(mockGetPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + await expect(element).toBeAccessible(); + }); + + it('is accessible when error returned', async () => { + const WIRE_ERROR = 'Something bad happened'; + + // Create element and attach to virtual DOM + const element = createElement('c-broker-card', { + is: BrokerCard + }); + document.body.appendChild(element); + + getRecord.error(WIRE_ERROR); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/brokerCard/__tests__/data/getPropertyRecord.json b/force-app/main/default/lwc/brokerCard/__tests__/data/getPropertyRecord.json new file mode 100644 index 0000000..31c18bb --- /dev/null +++ b/force-app/main/default/lwc/brokerCard/__tests__/data/getPropertyRecord.json @@ -0,0 +1,18 @@ +{ + "apiName": "Property__c", + "childRelationships": {}, + "eTag": "e724fda6d93b891f98c7e0b6b3d7686c", + "fields": { + "Broker__c": { + "displayValue": null, + "value": "a003h000003xlBiAAI" + } + }, + "id": "a013h000009HEM7AAO", + "lastModifiedById": "00540000032Tm3AAE", + "lastModifiedDate": "2020-07-15T19:56:23.000Z", + "recordTypeId": "012000000000000AAA", + "recordTypeInfo": null, + "systemModstamp": "2020-07-15T19:56:23.000Z", + "weakEtag": 1594842983000 +} diff --git a/force-app/main/default/lwc/brokerCard/brokerCard.html b/force-app/main/default/lwc/brokerCard/brokerCard.html new file mode 100644 index 0000000..9fca4d0 --- /dev/null +++ b/force-app/main/default/lwc/brokerCard/brokerCard.html @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/brokerCard/brokerCard.js b/force-app/main/default/lwc/brokerCard/brokerCard.js new file mode 100644 index 0000000..f246a9a --- /dev/null +++ b/force-app/main/default/lwc/brokerCard/brokerCard.js @@ -0,0 +1,36 @@ +import { LightningElement, api, wire } from 'lwc'; +import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; +import { NavigationMixin } from 'lightning/navigation'; + +import BROKER_FIELD from '@salesforce/schema/Property__c.Broker__c'; +import NAME_FIELD from '@salesforce/schema/Broker__c.Name'; +import PHONE_FIELD from '@salesforce/schema/Broker__c.Phone__c'; +import MOBILE_PHONE_FIELD from '@salesforce/schema/Broker__c.Mobile_Phone__c'; +import EMAIL_FIELD from '@salesforce/schema/Broker__c.Email__c'; + +const PROPERTY_FIELDS = [BROKER_FIELD]; +const BROKER_FIELDS = [NAME_FIELD, PHONE_FIELD, MOBILE_PHONE_FIELD, EMAIL_FIELD]; + +export default class BrokerCard extends NavigationMixin(LightningElement) { + @api recordId; + + brokerFields = BROKER_FIELDS; + + @wire(getRecord, { recordId: '$recordId', fields: PROPERTY_FIELDS }) + property; + + get brokerId() { + return getFieldValue(this.property.data, BROKER_FIELD); + } + + handleNavigateToRecord() { + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + recordId: this.brokerId, + objectApiName: 'Hutte__Property__c', + actionName: 'view' + } + }); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/brokerCard/brokerCard.js-meta.xml b/force-app/main/default/lwc/brokerCard/brokerCard.js-meta.xml new file mode 100644 index 0000000..30cec35 --- /dev/null +++ b/force-app/main/default/lwc/brokerCard/brokerCard.js-meta.xml @@ -0,0 +1,20 @@ + + + 61.0 + true + Broker Card + + lightning__RecordPage + + + + + Property__c + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/daysOnMarket/__tests__/data/getRecord.json b/force-app/main/default/lwc/daysOnMarket/__tests__/data/getRecord.json new file mode 100644 index 0000000..145201f --- /dev/null +++ b/force-app/main/default/lwc/daysOnMarket/__tests__/data/getRecord.json @@ -0,0 +1,20 @@ +{ + "apiName": "Property__c", + "childRelationships": {}, + "id": "a015I000002taYUQAY", + "lastModifiedById": "0054I000001RjtIQAS", + "lastModifiedDate": "2020-06-09T07:48:54.000Z", + "recordTypeId": "012000000000000AAA", + "recordTypeInfo": null, + "systemModstamp": "2020-06-09T07:48:55.000Z", + "fields": { + "Date_Listed__c": { + "displayValue": "30/5/2020", + "value": "2020-05-30" + }, + "Days_On_Market__c": { + "displayValue": null, + "value": 18 + } + } +} diff --git a/force-app/main/default/lwc/daysOnMarket/__tests__/daysOnMarket.test.js b/force-app/main/default/lwc/daysOnMarket/__tests__/daysOnMarket.test.js new file mode 100644 index 0000000..7cbb93d --- /dev/null +++ b/force-app/main/default/lwc/daysOnMarket/__tests__/daysOnMarket.test.js @@ -0,0 +1,255 @@ +import { createElement } from 'lwc'; +import DaysOnMarket from 'c/daysOnMarket'; +import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; +import { + subscribe, + MessageContext, + publish, + unsubscribe +} from 'lightning/messageService'; +import PROPERTYSELECTEDMC from '@salesforce/messageChannel/PropertySelected__c'; +import DATE_LISTED_FIELD from '@salesforce/schema/Property__c.Date_Listed__c'; +import DAYS_ON_MARKET_FIELD from '@salesforce/schema/Property__c.Days_On_Market__c'; + +const MAX_DAYS_CHART = 90; + +const mockGetRecord = require('./data/getRecord.json'); + +describe('c-days-on-market', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + + // Prevent data saved on mocks from leaking between tests + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('renders error if no property is selected', () => { + // Create initial element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + document.body.appendChild(element); + + const errorPanelElement = + element.shadowRoot.querySelector('c-error-panel'); + expect(errorPanelElement.friendlyMessage).toBe( + 'Select a property to see days on the market' + ); + }); + + it('registers the LMS subscriber during the component lifecycle', () => { + // Create initial element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + document.body.appendChild(element); + + // Validate if pubsub got registered after connected to the DOM + expect(subscribe).toHaveBeenCalled(); + expect(subscribe.mock.calls[0][1]).toBe(PROPERTYSELECTEDMC); + }); + + it('unregisters the LMS subscriber during the component lifecycle', () => { + // Create initial element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + document.body.appendChild(element); + document.body.removeChild(element); + + // Validate if pubsub got unsubscribed after disconnected from the DOM + expect(unsubscribe).toHaveBeenCalled(); + }); + + it('invokes getRecord with the published message payload value', async () => { + // Create element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + document.body.appendChild(element); + + // Simulate pulishing a message using RECORD_SELECTED_CHANNEL message channel + const messagePayload = { propertyId: '001' }; + publish(MessageContext, PROPERTYSELECTEDMC, messagePayload); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // The component subscription should cause getRecord to be invoked. + // Below we test that it is invoked with the messagePayload value + // that was published with the simulated publish invocation above. + const { propertyId, fields } = getRecord.getLastConfig(); + expect(propertyId).toEqual(messagePayload.recordId); + expect(fields).toEqual([DATE_LISTED_FIELD, DAYS_ON_MARKET_FIELD]); + }); + + describe('getRecord @wire data', () => { + function validateHTML(element, type) { + const badgeEl = element.shadowRoot.querySelector( + `div.badge.${type}` + ); + expect(badgeEl).not.toBeNull(); + + const daysDivEl = element.shadowRoot.querySelector('div.days'); + expect(daysDivEl.textContent).toBe( + getFieldValue(mockGetRecord, DAYS_ON_MARKET_FIELD).toString() + ); + + const chartBarEl = element.shadowRoot.querySelector( + `div.bar.${type}` + ); + expect(chartBarEl).not.toBeNull(); + const width = + (getFieldValue(mockGetRecord, DAYS_ON_MARKET_FIELD) / + MAX_DAYS_CHART) * + 100; + expect(chartBarEl.style.width).toBe(`${width}%`); + + const formattedDateTimeEl = element.shadowRoot.querySelector( + 'lightning-formatted-date-time' + ); + expect(formattedDateTimeEl.value).toBe( + getFieldValue(mockGetRecord, DATE_LISTED_FIELD).toString() + ); + } + + describe('renders days on market', () => { + // eslint-disable-next-line jest/expect-expect + it('in normal case', async () => { + // Create element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + element.recordId = '001'; + document.body.appendChild(element); + + // Emit data from @wire + getRecord.emit(mockGetRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Select elements for validation + validateHTML(element, 'normal'); + }); + + // eslint-disable-next-line jest/expect-expect + it('in warning case', async () => { + // Create element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + element.recordId = '001'; + document.body.appendChild(element); + + // Emit data from @wire + mockGetRecord.fields.Days_On_Market__c.value = 48; + getRecord.emit(mockGetRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Select elements for validation + validateHTML(element, 'warning'); + }); + + // eslint-disable-next-line jest/expect-expect + it('in alert case', async () => { + // Create element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + element.recordId = '001'; + document.body.appendChild(element); + + // Emit data from @wire + mockGetRecord.fields.Days_On_Market__c.value = 68; + getRecord.emit(mockGetRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Select elements for validation + validateHTML(element, 'alert'); + }); + }); + }); + describe('getRecord @wire error', () => { + it('renders an error panel when there is an error', async () => { + const APEX_ERROR = { + body: 'Error retrieving records', + ok: false, + status: '400', + statusText: 'Bad Request' + }; + + // Create initial element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + element.recordId = '001'; + document.body.appendChild(element); + + // Emit error from @wire + getRecord.error( + APEX_ERROR.body, + APEX_ERROR.status, + APEX_ERROR.statusText + ); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const errorPanelEl = + element.shadowRoot.querySelector('c-error-panel'); + expect(errorPanelEl).not.toBeNull(); + expect(errorPanelEl.errors).toStrictEqual(APEX_ERROR); + }); + }); + + it('is accessible when property selected', async () => { + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + + element.recordId = '001'; + document.body.appendChild(element); + + // Emit data from @wire + getRecord.emit(mockGetRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + await expect(element).toBeAccessible(); + }); + + it('is accessible when no property selected', async () => { + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); + + it('is accessible when error returned', async () => { + // Create initial element + const element = createElement('c-days-on-market', { + is: DaysOnMarket + }); + element.recordId = '001'; + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/daysOnMarket/daysOnMarket.css b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.css new file mode 100644 index 0000000..549575f --- /dev/null +++ b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.css @@ -0,0 +1,57 @@ +.badge { + text-align: center; + margin-right: var(--lwc-varSpacingXxSmall, 4px); + padding: var(--lwc-varSpacingXSmall, 8px) var(--lwc-varSpacingSmall, 12px); + border-radius: var(--lwc-borderRadiusMedium, 4px); + color: var(--lwc-colorTextInverse, #ffffff); +} + +.badge.alert { + background-color: #c23934; + border: solid var(--lwc-borderWidthThin, 1px) #c23934; +} + +.badge.normal { + background-color: #00716b; + border: solid var(--lwc-borderWidthThin, 1px) #00716b; +} + +.badge.warning { + background-color: #f28c00; + border: solid var(--lwc-borderWidthThin, 1px) #f28c00; +} + +.bar { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + height: 58px; + transition: all 0.5s ease-in-out; + position: absolute; + left: var(--lwc-spacingXxxSmall, 2px); +} + +.bar.normal { + background-color: #00716b; +} + +.bar.warning { + background-color: #f28c00; +} + +.bar.alert { + background-color: #c23934; +} + +.axis { + font-weight: 200; +} + +.axis > div { + height: 60px; + border-bottom: solid var(--lwc-borderWidthThin, 1px) rgb(216, 221, 230); + border-left: solid var(--lwc-borderWidthThin, 1px) rgb(216, 221, 230); +} + +.axis .legend { + margin-top: 60px; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/daysOnMarket/daysOnMarket.html b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.html new file mode 100644 index 0000000..2722438 --- /dev/null +++ b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.html @@ -0,0 +1,43 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/daysOnMarket/daysOnMarket.js b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.js new file mode 100644 index 0000000..c3159b6 --- /dev/null +++ b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.js @@ -0,0 +1,94 @@ +import { LightningElement, api, wire } from 'lwc'; +import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; +import { + subscribe, + unsubscribe, + MessageContext +} from 'lightning/messageService'; +import PROPERTYSELECTEDMC from '@salesforce/messageChannel/PropertySelected__c'; +import DATE_LISTED_FIELD from '@salesforce/schema/Property__c.Date_Listed__c'; +import DAYS_ON_MARKET_FIELD from '@salesforce/schema/Property__c.Days_On_Market__c'; + +const MAX_DAYS_NORMAL_STATUS = 30; +const MAX_DAYS_WARNING_STATUS = 60; +const MAX_DAYS_CHART = 90; + +const FIELDS = [DATE_LISTED_FIELD, DAYS_ON_MARKET_FIELD]; + +export default class DaysOnMarket extends LightningElement { + error; + daysOnMarket; + dateListed; + propertyId; + status; + subscription; + + @wire(MessageContext) + messageContext; + + @wire(getRecord, { recordId: '$propertyId', fields: FIELDS }) + wiredRecord({ error, data }) { + if (data) { + this.error = undefined; + this.dateListed = getFieldValue(data, DATE_LISTED_FIELD); + this.daysOnMarket = getFieldValue(data, DAYS_ON_MARKET_FIELD); + if (this.daysOnMarket < MAX_DAYS_NORMAL_STATUS) { + this.status = 'normal'; + } else if (this.daysOnMarket < MAX_DAYS_WARNING_STATUS) { + this.status = 'warning'; + } else { + this.status = 'alert'; + } + } else if (error) { + this.daysOnMarket = undefined; + this.dateListed = undefined; + this.status = undefined; + this.error = error; + } + } + + @api + get recordId() { + return this.propertyId; + } + + set recordId(propertyId) { + this.propertyId = propertyId; + } + + get hasNoPropertyId() { + return this.propertyId === undefined; + } + + get badgeClass() { + return 'badge ' + this.status; + } + + get barClass() { + return 'bar ' + this.status; + } + + get barStyle() { + const value = (this.daysOnMarket / MAX_DAYS_CHART) * 100; + return 'width:' + value + '%'; + } + + connectedCallback() { + this.subscription = subscribe( + this.messageContext, + PROPERTYSELECTEDMC, + (message) => { + this.handlePropertySelected(message); + } + ); + } + + disconnectedCallback() { + unsubscribe(this.subscription); + this.subscription = null; + } + + handlePropertySelected(message) { + this.propertyId = message.propertyId; + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/daysOnMarket/daysOnMarket.js-meta.xml b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.js-meta.xml new file mode 100644 index 0000000..020d148 --- /dev/null +++ b/force-app/main/default/lwc/daysOnMarket/daysOnMarket.js-meta.xml @@ -0,0 +1,22 @@ + + + 61.0 + true + Days on Market + + lightning__AppPage + lightning__RecordPage + lightning__HomePage + + + + + Property__c + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/errorPanel/__tests__/errorPanel.test.js b/force-app/main/default/lwc/errorPanel/__tests__/errorPanel.test.js new file mode 100644 index 0000000..0413593 --- /dev/null +++ b/force-app/main/default/lwc/errorPanel/__tests__/errorPanel.test.js @@ -0,0 +1,122 @@ +import { createElement } from 'lwc'; +import ErrorPanel from 'c/errorPanel'; + +describe('c-error-panel', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('displays a default friendly message', () => { + const MESSAGE = 'Error retrieving data'; + + // Create initial element + const element = createElement('c-error-panel', { + is: ErrorPanel + }); + document.body.appendChild(element); + + const messageEl = element.shadowRoot.querySelector('h3'); + expect(messageEl.textContent).toBe(MESSAGE); + }); + + it('displays a custom friendly message', () => { + const MESSAGE = 'Errors are bad'; + + // Create initial element + const element = createElement('c-error-panel', { + is: ErrorPanel + }); + element.friendlyMessage = MESSAGE; + document.body.appendChild(element); + + const messageEl = element.shadowRoot.querySelector('h3'); + expect(messageEl.textContent).toBe(MESSAGE); + }); + + it('displays no error details when no errors are passed as parameters', () => { + // Create initial element + const element = createElement('c-error-panel', { + is: ErrorPanel + }); + document.body.appendChild(element); + + const anchorEl = element.shadowRoot.querySelector('a'); + expect(anchorEl).toBeNull(); + }); + + it('displays error details when errors are passed as parameters', async () => { + const ERROR_MESSAGES_INPUT = [ + { statusText: 'First bad error' }, + { statusText: 'Second bad error' } + ]; + const ERROR_MESSAGES_OUTPUT = ['First bad error', 'Second bad error']; + + // Create initial element + const element = createElement('c-error-panel', { + is: ErrorPanel + }); + element.type = 'inlineMessage'; + element.errors = ERROR_MESSAGES_INPUT; + document.body.appendChild(element); + + // Click link to show details + element.shadowRoot.querySelector('a').click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const messageTexts = Array.from( + element.shadowRoot.querySelectorAll('p') + ).map((errorMessage) => (errorMessage = errorMessage.textContent)); + expect(messageTexts).toEqual(ERROR_MESSAGES_OUTPUT); + }); + + it('is accessible when inline message', async () => { + const ERROR_MESSAGES_INPUT = [ + { statusText: 'First bad error' }, + { statusText: 'Second bad error' } + ]; + + const element = createElement('c-error-panel', { + is: ErrorPanel + }); + + element.type = 'inlineMessage'; + element.errors = ERROR_MESSAGES_INPUT; + document.body.appendChild(element); + + // Click link to show details + element.shadowRoot.querySelector('a').click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + await expect(element).toBeAccessible(); + }); + + it('is accessible when no data illustration', async () => { + const ERROR_MESSAGES_INPUT = [ + { statusText: 'First bad error' }, + { statusText: 'Second bad error' } + ]; + + const element = createElement('c-error-panel', { + is: ErrorPanel + }); + + element.type = 'noDataIllustration'; + element.errors = ERROR_MESSAGES_INPUT; + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/errorPanel/errorPanel.js b/force-app/main/default/lwc/errorPanel/errorPanel.js new file mode 100644 index 0000000..5dafd3c --- /dev/null +++ b/force-app/main/default/lwc/errorPanel/errorPanel.js @@ -0,0 +1,28 @@ +import { LightningElement, api } from 'lwc'; +import { reduceErrors } from 'c/ldsUtils'; +import noDataIllustration from './templates/noDataIllustration.html'; +import inlineMessage from './templates/inlineMessage.html'; + +export default class ErrorPanel extends LightningElement { + /** Single or array of LDS errors */ + @api errors; + /** Generic / user-friendly message */ + @api friendlyMessage = 'Error retrieving data'; + /** Type of error message **/ + @api type; + + viewDetails = false; + + get errorMessages() { + return reduceErrors(this.errors); + } + + handleShowDetailsClick() { + this.viewDetails = !this.viewDetails; + } + + render() { + if (this.type === 'inlineMessage') return inlineMessage; + return noDataIllustration; + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/errorPanel/errorPanel.js-meta.xml b/force-app/main/default/lwc/errorPanel/errorPanel.js-meta.xml new file mode 100644 index 0000000..a4a5ed3 --- /dev/null +++ b/force-app/main/default/lwc/errorPanel/errorPanel.js-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/errorPanel/templates/inlineMessage.html b/force-app/main/default/lwc/errorPanel/templates/inlineMessage.html new file mode 100755 index 0000000..aceb4cc --- /dev/null +++ b/force-app/main/default/lwc/errorPanel/templates/inlineMessage.html @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/errorPanel/templates/noDataIllustration.html b/force-app/main/default/lwc/errorPanel/templates/noDataIllustration.html new file mode 100644 index 0000000..eb83302 --- /dev/null +++ b/force-app/main/default/lwc/errorPanel/templates/noDataIllustration.html @@ -0,0 +1,257 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/ldsUtils/__tests__/ldsUtils.test.js b/force-app/main/default/lwc/ldsUtils/__tests__/ldsUtils.test.js new file mode 100644 index 0000000..dfb398a --- /dev/null +++ b/force-app/main/default/lwc/ldsUtils/__tests__/ldsUtils.test.js @@ -0,0 +1,61 @@ +import { reduceErrors } from 'c/ldsUtils'; + +describe('c-lds-utils', () => { + describe('reduceErrors', () => { + it('reduces single error with message in body', () => { + const FULL_ERROR = { body: { message: 'mockError' } }; + const REDUCED_ERROR = [FULL_ERROR.body.message]; + + const reduced = reduceErrors(FULL_ERROR); + + expect(reduced).toStrictEqual(REDUCED_ERROR); + }); + + it('reduces single error with multiple bodies with messages', () => { + const FULL_ERROR = { + body: [{ message: 'mockError1' }, { message: 'mockError2' }] + }; + const REDUCED_ERROR = [ + FULL_ERROR.body[0].message, + FULL_ERROR.body[1].message + ]; + + const reduced = reduceErrors(FULL_ERROR); + + expect(reduced).toStrictEqual(REDUCED_ERROR); + }); + + it('reduces single error message string', () => { + const FULL_ERROR = { message: 'mockError' }; + const REDUCED_ERROR = [FULL_ERROR.message]; + + const reduced = reduceErrors(FULL_ERROR); + + expect(reduced).toStrictEqual(REDUCED_ERROR); + }); + + it('reduces array of error message string', () => { + const FULL_ERROR = [ + { message: 'mockError1' }, + { message: 'mockError2' } + ]; + const REDUCED_ERROR = [ + FULL_ERROR[0].message, + FULL_ERROR[1].message + ]; + + const reduced = reduceErrors(FULL_ERROR); + + expect(reduced).toStrictEqual(REDUCED_ERROR); + }); + + it('reduces single error with unknown shape', () => { + const FULL_ERROR = { statusText: 'mockStatus' }; + const REDUCED_ERROR = [FULL_ERROR.statusText]; + + const reduced = reduceErrors(FULL_ERROR); + + expect(reduced).toStrictEqual(REDUCED_ERROR); + }); + }); +}); diff --git a/force-app/main/default/lwc/ldsUtils/ldsUtils.js b/force-app/main/default/lwc/ldsUtils/ldsUtils.js new file mode 100644 index 0000000..db98851 --- /dev/null +++ b/force-app/main/default/lwc/ldsUtils/ldsUtils.js @@ -0,0 +1,37 @@ +/** + * Reduces one or more LDS errors into a string[] of error messages. + * @param {FetchResponse|FetchResponse[]} errors + * @return {String[]} Error messages + */ +export function reduceErrors(errors) { + if (!Array.isArray(errors)) { + errors = [errors]; + } + + return ( + errors + // Remove null/undefined items + .filter((error) => !!error) + // Extract an error message + .map((error) => { + // UI API read errors + if (Array.isArray(error.body)) { + return error.body.map((e) => e.message); + } + // UI API DML, Apex and network errors + else if (error.body && typeof error.body.message === 'string') { + return error.body.message; + } + // JS errors + else if (typeof error.message === 'string') { + return error.message; + } + // Unknown error shape so try HTTP status text + return error.statusText; + }) + // Flatten + .reduce((prev, curr) => prev.concat(curr), []) + // Remove empty strings + .filter((message) => !!message) + ); +} \ No newline at end of file diff --git a/force-app/main/default/lwc/ldsUtils/ldsUtils.js-meta.xml b/force-app/main/default/lwc/ldsUtils/ldsUtils.js-meta.xml new file mode 100644 index 0000000..be8d172 --- /dev/null +++ b/force-app/main/default/lwc/ldsUtils/ldsUtils.js-meta.xml @@ -0,0 +1,8 @@ + + + 61.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.html b/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.html new file mode 100644 index 0000000..ee44c6a --- /dev/null +++ b/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.html @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.js b/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.js new file mode 100644 index 0000000..a4b83d4 --- /dev/null +++ b/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.js @@ -0,0 +1,31 @@ +import { LightningElement } from 'lwc'; +import { getContactsService } from 'lightning/mobileCapabilities'; + +export default class ListContactsFromDevice extends LightningElement { + contactsService; + deviceContacts; + error; + + async connectedCallback() { + this.contactsService = getContactsService(); + if (this.contactsService.isAvailable()) { + await this.retrieveDeviceContacts(); + } else { + this.error = { message: 'Contact service not available' }; + } + } + + async retrieveDeviceContacts() { + const options = { + permissionRationaleText: + 'Allow access to your contacts to enable contacts processing.' + }; + + try { + this.deviceContacts = + await this.contactsService.getContacts(options); + } catch (error) { + this.error = error; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.js-meta.xml b/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.js-meta.xml new file mode 100644 index 0000000..bc308af --- /dev/null +++ b/force-app/main/default/lwc/listContactsFromDevice/listContactsFromDevice.js-meta.xml @@ -0,0 +1,9 @@ + + + 61.0 + true + Lists Contacts from Device + + lightning__AppPage + + \ No newline at end of file diff --git a/force-app/main/default/lwc/navigateToRecord/__tests__/navigateToRecord.test.js b/force-app/main/default/lwc/navigateToRecord/__tests__/navigateToRecord.test.js new file mode 100644 index 0000000..f6af6a7 --- /dev/null +++ b/force-app/main/default/lwc/navigateToRecord/__tests__/navigateToRecord.test.js @@ -0,0 +1,45 @@ +import { createElement } from 'lwc'; +import NavigateToRecord from 'c/navigateToRecord'; +import { getNavigateCalledWith } from 'lightning/navigation'; + +describe('c-navigate-to-record', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + // Prevent data saved on mocks from leaking between tests + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('navigates to record view', async () => { + // Nav param values to test later + const NAV_TYPE = 'standard__recordPage'; + const NAV_ACTION_NAME = 'view'; + const NAV_RECORD_ID = '0031700000pJRRWAA4'; + + // Create initial lwc element and attach to virtual DOM + const element = createElement('c-navigate-to-record', { + is: NavigateToRecord + }); + + element.recordId = NAV_RECORD_ID; + document.body.appendChild(element); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const { pageReference } = getNavigateCalledWith(); + + // Verify component called with correct event type and params + expect(pageReference.type).toBe(NAV_TYPE); + expect(pageReference.attributes.actionName).toBe(NAV_ACTION_NAME); + expect(pageReference.attributes.recordId).toBe(NAV_RECORD_ID); + }); +}); diff --git a/force-app/main/default/lwc/navigateToRecord/navigateToRecord.html b/force-app/main/default/lwc/navigateToRecord/navigateToRecord.html new file mode 100644 index 0000000..0440d2c --- /dev/null +++ b/force-app/main/default/lwc/navigateToRecord/navigateToRecord.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/navigateToRecord/navigateToRecord.js b/force-app/main/default/lwc/navigateToRecord/navigateToRecord.js new file mode 100644 index 0000000..7ddf9a9 --- /dev/null +++ b/force-app/main/default/lwc/navigateToRecord/navigateToRecord.js @@ -0,0 +1,18 @@ +import { LightningElement, api } from 'lwc'; +import { NavigationMixin } from 'lightning/navigation'; + +export default class NavigateToRecord extends NavigationMixin( + LightningElement +) { + @api recordId; + + connectedCallback() { + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + recordId: this.recordId, + actionName: 'view' + } + }); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/navigateToRecord/navigateToRecord.js-meta.xml b/force-app/main/default/lwc/navigateToRecord/navigateToRecord.js-meta.xml new file mode 100644 index 0000000..f302749 --- /dev/null +++ b/force-app/main/default/lwc/navigateToRecord/navigateToRecord.js-meta.xml @@ -0,0 +1,20 @@ + + + 61.0 + true + Navigate to Record Page + + lightning__FlowScreen + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/paginator/__tests__/paginator.test.js b/force-app/main/default/lwc/paginator/__tests__/paginator.test.js new file mode 100644 index 0000000..0ba2815 --- /dev/null +++ b/force-app/main/default/lwc/paginator/__tests__/paginator.test.js @@ -0,0 +1,144 @@ +import { createElement } from 'lwc'; +import Paginator from 'c/paginator'; + +describe('c-paginator', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('sends "next" event on button click', async () => { + // Create initial element + const element = createElement('c-paginator', { + is: Paginator + }); + // Simulate we are on first page + element.pageNumber = 1; + element.pageSize = 10; + element.totalItemCount = 100; + document.body.appendChild(element); + + // Mock handlers for child events + const handlerNext = jest.fn(); + + // Add event listener to catch child events + element.addEventListener('next', handlerNext); + + // Click the next(>) button + const nextButtonEl = + element.shadowRoot.querySelector('.right-button-icon'); + nextButtonEl.click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Validate if mocked events got fired + expect(handlerNext.mock.calls.length).toBe(1); + + // Validate previous button is hidden + const prevButtonEl = + element.shadowRoot.querySelector('.left-button-icon'); + expect(prevButtonEl).toBeNull(); + }); + + it('sends "previous" event on button click', async () => { + // Create initial element + const element = createElement('c-paginator', { + is: Paginator + }); + // Simulate we are on last page + element.pageNumber = 10; + element.pageSize = 10; + element.totalItemCount = 100; + document.body.appendChild(element); + + // Mock handlers for child events + const handlerPrevious = jest.fn(); + + // Add event listener to catch child events + element.addEventListener('previous', handlerPrevious); + + // Click the Previous(<) button + const prevButtonEl = + element.shadowRoot.querySelector('.left-button-icon'); + prevButtonEl.click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Validate if mocked events got fired + expect(handlerPrevious.mock.calls.length).toBe(1); + + // Validate next button is hidden + const nextButtonEl = + element.shadowRoot.querySelector('.right-button-icon'); + expect(nextButtonEl).toBeNull(); + }); + + it('displays total item count, page number, and number of pages with zero items', () => { + // Create initial element + const element = createElement('c-paginator', { + is: Paginator + }); + //Set the public property values + element.pageNumber = 0; + element.pageSize = 9; + element.totalItemCount = 0; + + document.body.appendChild(element); + + // Query div for validating the display message on component init + const lightningLayoutItemEl = + element.shadowRoot.querySelector('.nav-info'); + //Check for the 0 items message + expect(lightningLayoutItemEl).not.toBeNull(); + expect(lightningLayoutItemEl.textContent).toBe('0 items • page 0 of 0'); + }); + + it('displays total item count, page number, and number of pages with some items', async () => { + // Create initial element + const element = createElement('c-paginator', { + is: Paginator + }); + document.body.appendChild(element); + + //Set the public properties for item count greater than zero + element.pageNumber = 1; + element.pageSize = 9; + element.totalItemCount = 12; + + // Query div for validating the display message on component init + const lightningLayoutItemEl = + element.shadowRoot.querySelector('.nav-info'); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Query div for validating computed style attribute value on public property change + expect(lightningLayoutItemEl).not.toBeNull(); + expect(lightningLayoutItemEl.textContent).toBe( + '12 items • page 1 of 2' + ); + }); + + it('is accessible', async () => { + const element = createElement('c-paginator', { + is: Paginator + }); + + element.pageNumber = 3; + element.pageSize = 9; + element.totalItemCount = 12; + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/paginator/paginator.html b/force-app/main/default/lwc/paginator/paginator.html new file mode 100644 index 0000000..2d78050 --- /dev/null +++ b/force-app/main/default/lwc/paginator/paginator.html @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/paginator/paginator.js b/force-app/main/default/lwc/paginator/paginator.js new file mode 100644 index 0000000..9a6e08b --- /dev/null +++ b/force-app/main/default/lwc/paginator/paginator.js @@ -0,0 +1,36 @@ +import { LightningElement, api } from 'lwc'; + +export default class Paginator extends LightningElement { + /** The current page number. */ + @api pageNumber; + + /** The number of items on a page. */ + @api pageSize; + + /** The total number of items in the list. */ + @api totalItemCount; + + handlePrevious() { + this.dispatchEvent(new CustomEvent('previous')); + } + + handleNext() { + this.dispatchEvent(new CustomEvent('next')); + } + + get currentPageNumber() { + return this.totalItemCount === 0 ? 0 : this.pageNumber; + } + + get isNotFirstPage() { + return this.pageNumber > 1; + } + + get isNotLastPage() { + return this.pageNumber < this.totalPages; + } + + get totalPages() { + return Math.ceil(this.totalItemCount / this.pageSize); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/paginator/paginator.js-meta.xml b/force-app/main/default/lwc/paginator/paginator.js-meta.xml new file mode 100644 index 0000000..a4a5ed3 --- /dev/null +++ b/force-app/main/default/lwc/paginator/paginator.js-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyCarousel/__tests__/data/getPictures.json b/force-app/main/default/lwc/propertyCarousel/__tests__/data/getPictures.json new file mode 100644 index 0000000..9560d65 --- /dev/null +++ b/force-app/main/default/lwc/propertyCarousel/__tests__/data/getPictures.json @@ -0,0 +1,4 @@ +[ + { "Id": "0682F000000igu2QAA", "Title": "pic1" }, + { "Id": "0682F000000igu2QA4", "Title": "pic2" } +] diff --git a/force-app/main/default/lwc/propertyCarousel/__tests__/data/getPropertyRecord.json b/force-app/main/default/lwc/propertyCarousel/__tests__/data/getPropertyRecord.json new file mode 100644 index 0000000..31c18bb --- /dev/null +++ b/force-app/main/default/lwc/propertyCarousel/__tests__/data/getPropertyRecord.json @@ -0,0 +1,18 @@ +{ + "apiName": "Property__c", + "childRelationships": {}, + "eTag": "e724fda6d93b891f98c7e0b6b3d7686c", + "fields": { + "Broker__c": { + "displayValue": null, + "value": "a003h000003xlBiAAI" + } + }, + "id": "a013h000009HEM7AAO", + "lastModifiedById": "00540000032Tm3AAE", + "lastModifiedDate": "2020-07-15T19:56:23.000Z", + "recordTypeId": "012000000000000AAA", + "recordTypeInfo": null, + "systemModstamp": "2020-07-15T19:56:23.000Z", + "weakEtag": 1594842983000 +} diff --git a/force-app/main/default/lwc/propertyCarousel/__tests__/propertyCarousel.test.js b/force-app/main/default/lwc/propertyCarousel/__tests__/propertyCarousel.test.js new file mode 100644 index 0000000..741dadb --- /dev/null +++ b/force-app/main/default/lwc/propertyCarousel/__tests__/propertyCarousel.test.js @@ -0,0 +1,174 @@ +import { createElement } from 'lwc'; +import PropertyCarousel from 'c/propertyCarousel'; +import { getRecord } from 'lightning/uiRecordApi'; +import { processImage } from 'lightning/mediaUtils'; +import { refreshApex } from '@salesforce/apex'; +import getPictures from '@salesforce/apex/PropertyController.getPictures'; +import createFile from '@salesforce/apex/FileUtilities.createFile'; + +// Realistic data with multiple records +const mockGetPictures = require('./data/getPictures.json'); + +// Mock realistic data +const mockGetPropertyRecord = require('./data/getPropertyRecord.json'); + +// Mock getPictures Apex wire adapter +jest.mock( + '@salesforce/apex/PropertyController.getPictures', + () => { + const { + createApexTestWireAdapter + } = require('@salesforce/sfdx-lwc-jest'); + return { + default: createApexTestWireAdapter(jest.fn()) + }; + }, + { virtual: true } +); + +// Mocking createFile imperative Apex method call +jest.mock( + '@salesforce/apex/FileUtilities.createFile', + () => { + return { + default: jest.fn() + }; + }, + { virtual: true } +); + +describe('c-property-carousel', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + describe('@wire data', () => { + it('renders carousel with pictures when property and pictures returned', async () => { + const element = createElement('c-property-carousel', { + is: PropertyCarousel + }); + document.body.appendChild(element); + + // Emit mock property + getRecord.emit(mockGetPropertyRecord); + + // Emit mock pictures + getPictures.emit(mockGetPictures); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const carouselEl = + element.shadowRoot.querySelector('lightning-carousel'); + expect(carouselEl).not.toBeNull(); + const carouselImageEls = element.shadowRoot.querySelectorAll( + 'lightning-carousel-image' + ); + expect(carouselImageEls.length).toBe(mockGetPictures.length); + }); + + it('renders no pictures message when property but no pictures returned', async () => { + const element = createElement('c-property-carousel', { + is: PropertyCarousel + }); + document.body.appendChild(element); + + // Emit mock property + getRecord.emit(mockGetPropertyRecord); + + // Emit no pictures + getPictures.emit(null); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const pEl = element.shadowRoot.querySelector( + 'p.slds-text-align_center' + ); + expect(pEl).not.toBeNull(); + expect(pEl.textContent).toBe( + 'There are currently no pictures for this property.' + ); + }); + + it('renders error when getProperty returns error', async () => { + const element = createElement('c-property-carousel', { + is: PropertyCarousel + }); + document.body.appendChild(element); + + // Emit error + getRecord.error(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const errorPanelEl = + element.shadowRoot.querySelector('c-error-panel'); + expect(errorPanelEl).not.toBeNull(); + }); + + it('renders error when getPictures returns error', async () => { + const element = createElement('c-property-carousel', { + is: PropertyCarousel + }); + document.body.appendChild(element); + + // Emit mock property + getRecord.emit(mockGetPropertyRecord); + + // Emit error + getPictures.error(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const errorPanelEl = + element.shadowRoot.querySelector('c-error-panel'); + expect(errorPanelEl).not.toBeNull(); + }); + }); + describe('lightning-input interactions', () => { + it('calls processImage when a picture is uploaded', async () => { + const element = createElement('c-property-carousel', { + is: PropertyCarousel + }); + document.body.appendChild(element); + + // Emit mock property + getRecord.emit(mockGetPropertyRecord); + + // Emit mock createFile + createFile.mockResolvedValue('A00012345678'); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Simulate input click + const lightningInputEl = + element.shadowRoot.querySelector('lightning-input'); + lightningInputEl.files = [ + new File(['1234'], 'test.jpg', { type: 'image/jpeg' }) + ]; + lightningInputEl.dispatchEvent(new CustomEvent('change')); + + // eslint-disable-next-line @lwc/lwc/no-async-operation + await new Promise((resolve) => setTimeout(() => resolve(), 10)); + + // Assertions + expect(processImage).toHaveBeenCalled(); + expect(createFile).toHaveBeenCalled(); + expect(refreshApex).toHaveBeenCalled(); + }); + }); +}); diff --git a/force-app/main/default/lwc/propertyCarousel/propertyCarousel.html b/force-app/main/default/lwc/propertyCarousel/propertyCarousel.html new file mode 100644 index 0000000..0b221f7 --- /dev/null +++ b/force-app/main/default/lwc/propertyCarousel/propertyCarousel.html @@ -0,0 +1,47 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyCarousel/propertyCarousel.js b/force-app/main/default/lwc/propertyCarousel/propertyCarousel.js new file mode 100644 index 0000000..dc9cb72 --- /dev/null +++ b/force-app/main/default/lwc/propertyCarousel/propertyCarousel.js @@ -0,0 +1,105 @@ +import { LightningElement, wire, api } from 'lwc'; +import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; +import { processImage } from 'lightning/mediaUtils'; +import { refreshApex } from '@salesforce/apex'; +import getPictures from '@salesforce/apex/PropertyController.getPictures'; +import createFile from '@salesforce/apex/FileUtilities.createFile'; + +import ADDRESS_FIELD from '@salesforce/schema/Property__c.Address__c'; +import CITY_FIELD from '@salesforce/schema/Property__c.City__c'; +import DESCRIPTION_FIELD from '@salesforce/schema/Property__c.Description__c'; + +const FIELDS = [ADDRESS_FIELD, CITY_FIELD, DESCRIPTION_FIELD]; + +export default class PropertyCarousel extends LightningElement { + @api recordId; + carouselItems; + pictures; + + @wire(getRecord, { recordId: '$recordId', fields: FIELDS }) + property; + + @wire(getPictures, { propertyId: '$recordId' }) + wiredPictures(pictures) { + this.pictures = pictures; + if (pictures.data) { + const files = pictures.data; + if (Array.isArray(files) && files.length) { + this.carouselItems = files.map((file) => { + return { + title: file.Title, + url: `/sfc/servlet.shepherd/version/download/${file.Id}` + }; + }); + } else { + this.carouselItems = null; + } + } + } + + get address() { + return getFieldValue(this.property.data, ADDRESS_FIELD); + } + + get city() { + return getFieldValue(this.property.data, CITY_FIELD); + } + + get description() { + return getFieldValue(this.property.data, DESCRIPTION_FIELD); + } + + get errors() { + const errors = [this.property.error, this.pictures.error].filter( + (error) => error + ); + return errors.length ? errors : null; + } + + // As this app is accessible on mobile, let's resize/compress the images for a better UX + // If you don't need compression, use lightning-file-upload instead + async handleFilesSelected(event) { + try { + const options = { + resizeMode: 'fill', + resizeStrategy: 'reduce', + targetWidth: 500, + targetHeight: 500, + compressionQuality: 0.75, + imageSmoothingEnabled: true, + preserveTransparency: false, + backgroundColor: 'white' + }; + + // Process each file individually to allow partial uploads succeed + /* eslint-disable no-await-in-loop */ + for (const file of event.target.files) { + // Compress and resize image + const blob = await processImage(file, options); + + // Convert to base64 + const base64data = await this.blobToBase64(blob); + + // Create file attached to record + await createFile({ + base64data: base64data, + filename: file.name, + recordId: this.recordId + }); + + // Refresh pictures to incorporate uploaded file + refreshApex(this.pictures); + } + } catch (error) { + console.error('Error compressing and creating file: ', error); + } + } + + async blobToBase64(blob) { + return new Promise((resolve) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(reader.result.split(',')[1]); // Remove Data-URL declaration + reader.readAsDataURL(blob); + }); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyCarousel/propertyCarousel.js-meta.xml b/force-app/main/default/lwc/propertyCarousel/propertyCarousel.js-meta.xml new file mode 100644 index 0000000..ccae37e --- /dev/null +++ b/force-app/main/default/lwc/propertyCarousel/propertyCarousel.js-meta.xml @@ -0,0 +1,20 @@ + + + 61.0 + true + Property Carousel + + lightning__RecordPage + + + + + Property__c + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyFilter/__tests__/propertyFilter.test.js b/force-app/main/default/lwc/propertyFilter/__tests__/propertyFilter.test.js new file mode 100644 index 0000000..5b5a146 --- /dev/null +++ b/force-app/main/default/lwc/propertyFilter/__tests__/propertyFilter.test.js @@ -0,0 +1,275 @@ +import { createElement } from 'lwc'; +import PropertyFilter from 'c/propertyFilter'; +import { publish } from 'lightning/messageService'; +import FILTERSCHANGEMC from '@salesforce/messageChannel/FiltersChange__c'; + +const MAX_PRICE = 1200000; + +const DEFAULT_SEARCH_CRITERIA = { + searchKey: '', + maxPrice: MAX_PRICE, + minBedrooms: 0, + minBathrooms: 0 +}; + +describe('c-property-filter', () => { + beforeAll(() => { + // We use fake timers as setTimeout is used in the JavaScript file. + jest.useFakeTimers(); + }); + + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('fires the change event on new search input', async () => { + // Create initial element + const element = createElement('c-property-filter', { + is: PropertyFilter + }); + document.body.appendChild(element); + + // Query lightning-input element + const lightningInputEl = + element.shadowRoot.querySelector('lightning-input'); + lightningInputEl.dispatchEvent( + new CustomEvent('change', { + detail: { + value: 'Boston' + } + }) + ); + + // Run all fake timers. + jest.runAllTimers(); + + const SEARCH_CRITERIA = { + searchKey: 'Boston', + maxPrice: MAX_PRICE, + minBedrooms: 0, + minBathrooms: 0 + }; + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Was publish called and was it called with the correct params? + expect(publish).toHaveBeenCalledWith( + undefined, + FILTERSCHANGEMC, + SEARCH_CRITERIA + ); + }); + + it('fires the change event on Max Price slider input', async () => { + // Create initial element + const element = createElement('c-property-filter', { + is: PropertyFilter + }); + document.body.appendChild(element); + + // Query lightning-input element + const lightningSliderEl = + element.shadowRoot.querySelector('lightning-slider'); + lightningSliderEl.dispatchEvent( + new CustomEvent('change', { + detail: { + value: 60000 + } + }) + ); + + // Run all fake timers. + jest.runAllTimers(); + + const SEARCH_CRITERIA = { + searchKey: '', + maxPrice: 60000, + minBedrooms: 0, + minBathrooms: 0 + }; + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Was publish called and was it called with the correct params? + expect(publish).toHaveBeenCalledWith( + undefined, + FILTERSCHANGEMC, + SEARCH_CRITERIA + ); + }); + + it('fires the change event on Bedrooms slider input', async () => { + // Create initial element + const element = createElement('c-property-filter', { + is: PropertyFilter + }); + document.body.appendChild(element); + + // Query lightning-input element + const lightningSliderEl = + element.shadowRoot.querySelectorAll('lightning-slider')[1]; + lightningSliderEl.dispatchEvent( + new CustomEvent('change', { + detail: { + value: 2 + } + }) + ); + + // Run all fake timers. + jest.runAllTimers(); + + const SEARCH_CRITERIA = { + searchKey: '', + maxPrice: MAX_PRICE, + minBedrooms: 2, + minBathrooms: 0 + }; + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Was publish called and was it called with the correct params? + expect(publish).toHaveBeenCalledWith( + undefined, + FILTERSCHANGEMC, + SEARCH_CRITERIA + ); + }); + + it('fires the change event on Bathrooms slider input', async () => { + // Create initial element + const element = createElement('c-property-filter', { + is: PropertyFilter + }); + document.body.appendChild(element); + + // Query lightning-input element + const lightningSliderEl = + element.shadowRoot.querySelectorAll('lightning-slider')[2]; + lightningSliderEl.dispatchEvent( + new CustomEvent('change', { + detail: { + value: 2 + } + }) + ); + + // Run all fake timers. + jest.runAllTimers(); + + const SEARCH_CRITERIA = { + searchKey: '', + maxPrice: MAX_PRICE, + minBedrooms: 0, + minBathrooms: 2 + }; + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Was publish called and was it called with the correct params? + expect(publish).toHaveBeenCalledWith( + undefined, + FILTERSCHANGEMC, + SEARCH_CRITERIA + ); + }); + + it('fires change event when reset button is clicked', async () => { + // Create initial element + const element = createElement('c-property-filter', { + is: PropertyFilter + }); + document.body.appendChild(element); + + // Click reset button + const lightningButtonEl = + element.shadowRoot.querySelector('lightning-button'); + lightningButtonEl.click(); + // Run all fake timers. + jest.runAllTimers(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Was publish called and was it called with the correct params? + expect(publish).toHaveBeenCalledWith( + undefined, + FILTERSCHANGEMC, + DEFAULT_SEARCH_CRITERIA + ); + }); + + it('resets to default values when reset button is clicked', async () => { + // Create initial element + const element = createElement('c-property-filter', { + is: PropertyFilter + }); + document.body.appendChild(element); + + // Set inital form values + let searchKeyEl = element.shadowRoot.querySelector('lightning-input'); + searchKeyEl.dispatchEvent( + new CustomEvent('change', { + detail: { + value: 'someValue' + } + }) + ); + let sliderEls = element.shadowRoot.querySelectorAll('lightning-slider'); + sliderEls[0].dispatchEvent( + new CustomEvent('change', { + detail: { + value: 1 + } + }) + ); + sliderEls[1].dispatchEvent( + new CustomEvent('change', { + detail: { + value: 2 + } + }) + ); + sliderEls[2].dispatchEvent( + new CustomEvent('change', { + detail: { + value: 3 + } + }) + ); + + // Click reset button + const lightningButtonEl = + element.shadowRoot.querySelector('lightning-button'); + lightningButtonEl.click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Check for default searchkey value + searchKeyEl = element.shadowRoot.querySelector('lightning-input'); + expect(searchKeyEl.value).toBe(DEFAULT_SEARCH_CRITERIA.searchKey); + + sliderEls = element.shadowRoot.querySelectorAll('lightning-slider'); + // Check for default maxPrice value + expect(sliderEls[0].value).toBe(DEFAULT_SEARCH_CRITERIA.maxPrice); + // Check for default minBedrooms value + expect(sliderEls[1].value).toBe(DEFAULT_SEARCH_CRITERIA.minBedrooms); + // Check for default minBathrooms value + expect(sliderEls[2].value).toBe(DEFAULT_SEARCH_CRITERIA.minBathrooms); + }); +}); diff --git a/force-app/main/default/lwc/propertyFilter/propertyFilter.html b/force-app/main/default/lwc/propertyFilter/propertyFilter.html new file mode 100644 index 0000000..29a7d22 --- /dev/null +++ b/force-app/main/default/lwc/propertyFilter/propertyFilter.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyFilter/propertyFilter.js b/force-app/main/default/lwc/propertyFilter/propertyFilter.js new file mode 100644 index 0000000..9867ec1 --- /dev/null +++ b/force-app/main/default/lwc/propertyFilter/propertyFilter.js @@ -0,0 +1,61 @@ +import { LightningElement, wire } from 'lwc'; +import { publish, MessageContext } from 'lightning/messageService'; +import FILTERSCHANGEMC from '@salesforce/messageChannel/FiltersChange__c'; + +const DELAY = 350; +const MAX_PRICE = 1200000; + +export default class PropertyFilter extends LightningElement { + searchKey = ''; + maxPrice = MAX_PRICE; + minBedrooms = 0; + minBathrooms = 0; + + @wire(MessageContext) + messageContext; + + handleReset() { + this.searchKey = ''; + this.maxPrice = MAX_PRICE; + this.minBedrooms = 0; + this.minBathrooms = 0; + this.fireChangeEvent(); + } + + handleSearchKeyChange(event) { + this.searchKey = event.detail.value; + this.fireChangeEvent(); + } + + handleMaxPriceChange(event) { + this.maxPrice = event.detail.value; + this.fireChangeEvent(); + } + + handleMinBedroomsChange(event) { + this.minBedrooms = event.detail.value; + this.fireChangeEvent(); + } + + handleMinBathroomsChange(event) { + this.minBathrooms = event.detail.value; + this.fireChangeEvent(); + } + + fireChangeEvent() { + // Debouncing this method: Do not actually fire the event as long as this function is + // being called within a delay of DELAY. This is to avoid a very large number of Apex + // method calls in components listening to this event. + window.clearTimeout(this.delayTimeout); + // eslint-disable-next-line @lwc/lwc/no-async-operation + this.delayTimeout = setTimeout(() => { + const filters = { + searchKey: this.searchKey, + maxPrice: this.maxPrice, + minBedrooms: this.minBedrooms, + minBathrooms: this.minBathrooms + }; + publish(this.messageContext, FILTERSCHANGEMC, filters); + }, DELAY); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyFilter/propertyFilter.js-meta.xml b/force-app/main/default/lwc/propertyFilter/propertyFilter.js-meta.xml new file mode 100644 index 0000000..f9ebd3a --- /dev/null +++ b/force-app/main/default/lwc/propertyFilter/propertyFilter.js-meta.xml @@ -0,0 +1,17 @@ + + + 61.0 + true + Property Filter + + lightning__AppPage + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyListMap/__tests__/propertyListMap.test.js b/force-app/main/default/lwc/propertyListMap/__tests__/propertyListMap.test.js new file mode 100644 index 0000000..18a6ee2 --- /dev/null +++ b/force-app/main/default/lwc/propertyListMap/__tests__/propertyListMap.test.js @@ -0,0 +1,220 @@ +import { createElement } from 'lwc'; +import PropertyListMap from 'c/propertyListMap'; +import getPagedPropertyList from '@salesforce/apex/PropertyController.getPagedPropertyList'; + +import { subscribe } from 'lightning/messageService'; +import FILTERS_CHANGED from '@salesforce/messageChannel/FiltersChange__c'; + +import { ShowToastEventName } from 'lightning/platformShowToastEvent'; +import { loadScript, loadStyle } from 'lightning/platformResourceLoader'; + +// Mock getPagedPropertyList Apex wire adapter +jest.mock( + '@salesforce/apex/PropertyController.getPagedPropertyList', + () => { + const { + createApexTestWireAdapter + } = require('@salesforce/sfdx-lwc-jest'); + return { + default: createApexTestWireAdapter(jest.fn()) + }; + }, + { virtual: true } +); + +const MOCK_PROPERTIES = { + records: [ + { Id: 'id1', Location__Latitude__s: 10, Location__Longitude__s: 11 }, + { Id: 'id2', Location__Latitude__s: 20, Location__Longitude__s: 21 } + ] +}; + +// Sample error for loadScript error +const LOAD_SCRIPT_ERROR = { + body: { message: 'Mock load script error has occurred' }, + ok: false, + status: 400, + statusText: 'Bad Request' +}; + +const LEAFLET_STUB = { + map: () => ({ + setView: () => {}, + scrollWheelZoom: { + disable: () => {} + }, + removeLayer: () => {} + }), + tileLayer: () => ({ + addTo: () => {} + }), + divIcon: () => {}, + marker: () => ({ + on: () => {}, + bindTooltip: () => {} + }), + layerGroup: () => ({ + addTo: () => {} + }) +}; + +describe('c-property-list-map', () => { + beforeEach(() => { + // Inject Leaflet stub as a global 'L' variable + global.L = LEAFLET_STUB; + }); + + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + // Reset mocks so that every test run has a clean implementation + jest.resetAllMocks(); + // Clear leaflet global + global.L = undefined; + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('registers propertyFilters subscriber during the component lifecycle', () => { + // Create component + const element = createElement('c-property-list-map', { + is: PropertyListMap + }); + document.body.appendChild(element); + + // Validate if subscriber got registered after connected to the DOM + expect(subscribe).toHaveBeenCalled(); + expect(subscribe.mock.calls[0][1]).toBe(FILTERS_CHANGED); + }); + + it('loads the leaflet javascript and css static resources', () => { + // Create component + const element = createElement('c-property-list-map', { + is: PropertyListMap + }); + document.body.appendChild(element); + + // Validation that the loadScript and loadStyle promises + // are called once. + expect(loadScript.mock.calls.length).toBe(1); + expect(loadStyle.mock.calls.length).toBe(1); + + // Validation that the JS and CSS files are passed as parameters. + expect(loadScript.mock.calls[0][1]).toEqual('leafletjs/leaflet.js'); + expect(loadStyle.mock.calls[0][1]).toEqual('leafletjs/leaflet.css'); + }); + + it('fires a toast event if the static resource cannot be loaded', async () => { + loadScript.mockRejectedValue(LOAD_SCRIPT_ERROR); + + // Create component + const element = createElement('c-property-list-map', { + is: PropertyListMap + }); + document.body.appendChild(element); + + // Mock handler for toast event + const handler = jest.fn(); + // Add event listener to catch toast event + element.addEventListener(ShowToastEventName, handler); + + // Wait for any asynchronous DOM updates + // We wait twice here in order to ensure that style and script are loaded + await flushPromises(); + await flushPromises(); + + // Check if toast event has been fired + expect(handler).toHaveBeenCalled(); + expect(handler.mock.calls[0][0].detail.title).toBe( + 'Error while loading Leaflet' + ); + expect(handler.mock.calls[0][0].detail.variant).toBe('error'); + }); + + it('fires a toast event when properties cannot be retrieved', async () => { + // Create component + const element = createElement('c-property-list-map', { + is: PropertyListMap + }); + document.body.appendChild(element); + + // Mock handler for toast event + const handler = jest.fn(); + // Add event listener to catch toast event + element.addEventListener(ShowToastEventName, handler); + + // Emit error from @wire + getPagedPropertyList.error(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Check if toast event has been fired + expect(handler).toHaveBeenCalled(); + expect(handler.mock.calls[0][0].detail.title).toBe( + 'Error loading properties' + ); + expect(handler.mock.calls[0][0].detail.variant).toBe('error'); + }); + + it('updates map when properties are received', async () => { + // Mock leaflet and add it as a global 'L' variable + const markerMock = jest.fn(() => ({ + on: () => {}, + bindTooltip: () => {} + })); + const layerGroupAddToMock = jest.fn(); + const leafletMock = { + map: () => ({ + setView: () => {}, + scrollWheelZoom: { + disable: () => {} + }, + removeLayer: () => {} + }), + tileLayer: () => ({ + addTo: () => {} + }), + divIcon: () => {}, + marker: markerMock, + layerGroup: () => ({ + addTo: layerGroupAddToMock + }) + }; + global.L = leafletMock; + + // Create component + const element = createElement('c-property-list-map', { + is: PropertyListMap + }); + document.body.appendChild(element); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Emit mock properties + getPagedPropertyList.emit(MOCK_PROPERTIES); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Check that markers are set up with property data + expect(markerMock).toHaveBeenCalledTimes( + MOCK_PROPERTIES.records.length + ); + MOCK_PROPERTIES.records.forEach((property, index) => { + expect(markerMock.mock.calls[index][0]).toStrictEqual([ + MOCK_PROPERTIES.records[index].Location__Latitude__s, + MOCK_PROPERTIES.records[index].Location__Longitude__s + ]); + }); + // Check that layer is added to map + expect(layerGroupAddToMock).toHaveBeenCalled(); + }); +}); diff --git a/force-app/main/default/lwc/propertyListMap/propertyListMap.css b/force-app/main/default/lwc/propertyListMap/propertyListMap.css new file mode 100644 index 0000000..1126d1a --- /dev/null +++ b/force-app/main/default/lwc/propertyListMap/propertyListMap.css @@ -0,0 +1,34 @@ +.map { + height: 550px; +} + +.tooltip-picture { + position: relative; + width: 150px; + height: 150px; + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +.tooltip-picture .lower-third { + position: absolute; + /* @sldsValidatorIgnore */ + bottom: 0; + /* @sldsValidatorIgnore */ + left: 0; + /* @sldsValidatorIgnore */ + right: 0; + background-color: rgba(0, 0, 0, 0.5); + color: white; + padding: 0.15rem; +} + +.lower-third h1 { + font-weight: bold; + /* @sldsValidatorIgnore */ + white-space: nowrap; + overflow: hidden; + /* @sldsValidatorIgnore */ + text-overflow: ellipsis; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyListMap/propertyListMap.html b/force-app/main/default/lwc/propertyListMap/propertyListMap.html new file mode 100644 index 0000000..1dcaa61 --- /dev/null +++ b/force-app/main/default/lwc/propertyListMap/propertyListMap.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyListMap/propertyListMap.js b/force-app/main/default/lwc/propertyListMap/propertyListMap.js new file mode 100644 index 0000000..6fde1a5 --- /dev/null +++ b/force-app/main/default/lwc/propertyListMap/propertyListMap.js @@ -0,0 +1,170 @@ +/* global L */ +import { LightningElement, wire } from 'lwc'; +import { publish, subscribe, unsubscribe, MessageContext } from 'lightning/messageService'; +import FILTERS_CHANGED from '@salesforce/messageChannel/FiltersChange__c'; +import PROPERTY_SELECTED from '@salesforce/messageChannel/PropertySelected__c'; +import { ShowToastEvent } from 'lightning/platformShowToastEvent'; +import { loadScript, loadStyle } from 'lightning/platformResourceLoader'; +import LEAFLET from '@salesforce/resourceUrl/leafletjs'; +import getPagedPropertyList from '@salesforce/apex/PropertyController.getPagedPropertyList'; + +const LEAFLET_NOT_LOADED = 0; +const LEAFLET_LOADING = 1; +const LEAFLET_READY = 2; + +export default class PropertyListMap extends LightningElement { + properties = []; + + // Map + leafletState = LEAFLET_NOT_LOADED; + map; + propertyLayer; + + // Filters + searchKey = ''; + maxPrice = null; + minBedrooms = null; + minBathrooms = null; + pageNumber = null; + pageSize = null; + + @wire(MessageContext) + messageContext; + + @wire(getPagedPropertyList, { + searchKey: '$searchKey', + maxPrice: '$maxPrice', + minBedrooms: '$minBedrooms', + minBathrooms: '$minBathrooms', + pageSize: '$pageSize', + pageNumber: '$pageNumber' + }) + wiredProperties({ error, data }) { + if (data) { + this.properties = data.records; + // Display properties on map + this.displayProperties(); + } else if (error) { + this.properties = []; + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error loading properties', + message: error.message, + variant: 'error' + }) + ); + } + } + + connectedCallback() { + this.subscription = subscribe(this.messageContext, FILTERS_CHANGED, (message) => { + this.handleFilterChange(message); + }); + } + + disconnectedCallback() { + unsubscribe(this.subscription); + this.subscription = null; + } + + async renderedCallback() { + if (this.leafletState === LEAFLET_NOT_LOADED) { + await this.initializeLeaflet(); + } + } + + async initializeLeaflet() { + try { + // Leaflet is loading + this.leafletState = LEAFLET_LOADING; + + // Load resource files + await Promise.all([loadScript(this, `${LEAFLET}/leaflet.js`), loadStyle(this, `${LEAFLET}/leaflet.css`)]); + + // Configure map + const mapElement = this.template.querySelector('.map'); + this.map = L.map(mapElement, { + zoomControl: true, + tap: false + // eslint-disable-next-line no-magic-numbers + }); + this.map.setView([42.356045, -71.08565], 13); + this.map.scrollWheelZoom.disable(); + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© OpenStreetMap' + }).addTo(this.map); + + // Leaflet is ready + this.leafletState = LEAFLET_READY; + + // Display properties + this.displayProperties(); + } catch (error) { + const message = error.message || error.body.message; + this.dispatchEvent( + new ShowToastEvent({ + title: 'Error while loading Leaflet', + message, + variant: 'error' + }) + ); + } + } + + displayProperties() { + // Stop if leaflet isn't ready yet + if (this.leafletState !== LEAFLET_READY) { + return; + } + + // Remove previous property layer form map if it exits + if (this.propertyLayer) { + this.map.removeLayer(this.propertyLayer); + } + + // Prepare property icon + const icon = L.divIcon({ + className: 'my-div-icon', + html: '' + }); + + // Prepare click handler for property marker + const markerClickHandler = (event) => { + // Send message using the Lightning Message Service + const message = { propertyId: event.target.propertyId }; + publish(this.messageContext, PROPERTY_SELECTED, message); + }; + + // Prepare property markers + const markers = this.properties.map((property) => { + const latLng = [property.Hutte__Location__Latitude__s, property.Hutte__Location__Longitude__s]; + const tooltipMarkup = this.getTooltipMarkup(property); + const marker = L.marker(latLng, { icon }); + marker.propertyId = property.Id; + marker.on('click', markerClickHandler); + marker.bindTooltip(tooltipMarkup, { offset: [45, -40] }); + return marker; + }); + + // Create a layer with property markers and add it to map + this.propertyLayer = L.layerGroup(markers); + this.propertyLayer.addTo(this.map); + } + + handleFilterChange(filters) { + this.searchKey = filters.searchKey; + this.maxPrice = filters.maxPrice; + this.minBedrooms = filters.minBedrooms; + this.minBathrooms = filters.minBathrooms; + } + + getTooltipMarkup(property) { + return `
+
+

${property.Name}

+

Beds: ${property.Hutte__Beds__c} - Baths: ${property.Hutte__Baths__c}

+
+
`; + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyListMap/propertyListMap.js-meta.xml b/force-app/main/default/lwc/propertyListMap/propertyListMap.js-meta.xml new file mode 100644 index 0000000..3553aa6 --- /dev/null +++ b/force-app/main/default/lwc/propertyListMap/propertyListMap.js-meta.xml @@ -0,0 +1,9 @@ + + + 61.0 + true + Property List Map + + lightning__AppPage + + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyLocation/__tests__/data/getRecord.json b/force-app/main/default/lwc/propertyLocation/__tests__/data/getRecord.json new file mode 100644 index 0000000..2aa3814 --- /dev/null +++ b/force-app/main/default/lwc/propertyLocation/__tests__/data/getRecord.json @@ -0,0 +1,20 @@ +{ + "apiName": "Property__c", + "childRelationships": {}, + "id": "a015I000002taYUQAY", + "lastModifiedById": "0054I000001RjtIQAS", + "lastModifiedDate": "2020-06-09T07:48:54.000Z", + "recordTypeId": "012000000000000AAA", + "recordTypeInfo": null, + "systemModstamp": "2020-06-09T07:48:54.000Z", + "fields": { + "Hutte__Location__Latitude__s": { + "displayValue": "37.751", + "value": "37.751" + }, + "Hutte__Location__Longitude__s": { + "displayValue": "-97.822", + "value": "-97.822" + } + } +} diff --git a/force-app/main/default/lwc/propertyLocation/__tests__/propertyLocation.test.js b/force-app/main/default/lwc/propertyLocation/__tests__/propertyLocation.test.js new file mode 100644 index 0000000..ca297c7 --- /dev/null +++ b/force-app/main/default/lwc/propertyLocation/__tests__/propertyLocation.test.js @@ -0,0 +1,135 @@ +import { createElement } from 'lwc'; +import PropertyLocation from 'c/propertyLocation'; +import { getRecord } from 'lightning/uiRecordApi'; +import { setDeviceLocationServiceAvailable } from 'lightning/mobileCapabilities'; +import { mockGeolocation } from '../../../../../test/jest-mocks/global/navigator'; + +// Realistic property record +const mockPropertyRecord = require('./data/getRecord.json'); + +const checkDistanceCalculation = (element) => { + const latitudeEl = element.shadowRoot.querySelector( + 'div.location .latitude' + ); + expect(latitudeEl).not.toBe(null); + const longitudeEl = element.shadowRoot.querySelector( + 'div.location .longitude' + ); + expect(longitudeEl).not.toBe(null); + const formattedNumberEl = element.shadowRoot.querySelector( + 'div.location lightning-formatted-number' + ); + expect(formattedNumberEl).not.toBe(null); + + // Compare with coordinates in mobileCapabilities.js mock + expect(latitudeEl.textContent.trim()).toBe('42.361145'); + expect(longitudeEl.textContent.trim()).toBe('-71.057083'); + // Distance between mocked property and mocked location + expect(formattedNumberEl.value).toBe(1444.43371701009); +}; + +describe('c-property-location', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('renders an error panel when no location services are available', async () => { + const element = createElement('c-property-location', { + is: PropertyLocation + }); + + document.body.appendChild(element); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const panelEl = element.shadowRoot.querySelector('c-error-panel'); + expect(panelEl).not.toBeNull(); + }); + + it('renders an error panel when getRecord returns an error', async () => { + const element = createElement('c-property-location', { + is: PropertyLocation + }); + + document.body.appendChild(element); + + // Simulate error + getRecord.error(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const panelEl = element.shadowRoot.querySelector('c-error-panel'); + expect(panelEl).not.toBeNull(); + }); + + // eslint-disable-next-line jest/expect-expect + it('renders coordinates and distance when browser location is available', async () => { + // Simulate browser location + global.navigator.geolocation = mockGeolocation; + + const element = createElement('c-property-location', { + is: PropertyLocation + }); + element.recordId = mockPropertyRecord.id; + document.body.appendChild(element); + + // Simulate property selection + getRecord.emit(mockPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + checkDistanceCalculation(element); + }); + + // eslint-disable-next-line jest/expect-expect + it('renders coordinates and distance when device location is available', async () => { + // Simulate device location is available + setDeviceLocationServiceAvailable(true); + + const element = createElement('c-property-location', { + is: PropertyLocation + }); + element.recordId = mockPropertyRecord.id; + document.body.appendChild(element); + + // Simulate property selection + getRecord.emit(mockPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + checkDistanceCalculation(element); + }); + + it('is accessible when panel is shown', async () => { + // Simulate device location is available + setDeviceLocationServiceAvailable(true); + + const element = createElement('c-property-location', { + is: PropertyLocation + }); + element.recordId = mockPropertyRecord.id; + document.body.appendChild(element); + + // Simulate property selection + getRecord.emit(mockPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/propertyLocation/propertyLocation.html b/force-app/main/default/lwc/propertyLocation/propertyLocation.html new file mode 100644 index 0000000..e14e416 --- /dev/null +++ b/force-app/main/default/lwc/propertyLocation/propertyLocation.html @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyLocation/propertyLocation.js b/force-app/main/default/lwc/propertyLocation/propertyLocation.js new file mode 100644 index 0000000..cd1a5fd --- /dev/null +++ b/force-app/main/default/lwc/propertyLocation/propertyLocation.js @@ -0,0 +1,85 @@ +import { LightningElement, wire, api } from 'lwc'; +import { getLocationService } from 'lightning/mobileCapabilities'; +import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; + +// Using hardcoded fields due to LWC bug +const LATITUDE_FIELD = 'Hutte__Property__c.Hutte__Location__Latitude__s'; +const LONGITUDE_FIELD = 'Hutte__Property__c.Hutte__Location__Longitude__s'; + +const fields = [LATITUDE_FIELD, LONGITUDE_FIELD]; + +export default class PropertyLocation extends LightningElement { + error; + deviceLocationService; + distance; + location; + @api recordId; + + @wire(getRecord, { recordId: '$recordId', fields }) + wiredProperty({ data, error }) { + if (data) { + this.property = data; + this.calculateDistance(); + } else if (error) { + this.error = error; + this.property = undefined; + } + } + + async connectedCallback() { + this.deviceLocationService = getLocationService(); + if (this.deviceLocationService.isAvailable()) { + // Running on the Salesforce mobile app on a device + await this.calculateLocationFromMobileDevice(); + } else if (navigator.geolocation) { + // Running on a browser + this.calculateLocationFromBrowser(); + } else { + this.error = { message: 'No location services available' }; + } + } + + async calculateLocationFromMobileDevice() { + try { + this.location = await this.deviceLocationService.getCurrentPosition({ + enableHighAccuracy: true + }); + this.calculateDistance(); + } catch (error) { + this.error = error; + } + } + + calculateLocationFromBrowser() { + navigator.geolocation.getCurrentPosition( + (result) => { + this.location = result; + this.calculateDistance(); + }, + (error) => { + this.error = error; + } + ); + } + + calculateDistance() { + if (this.location && this.property) { + const latitude1 = this.location.coords.latitude; + const latitude2 = getFieldValue(this.property, LATITUDE_FIELD); + const longitude1 = this.location.coords.longitude; + const longitude2 = getFieldValue(this.property, LONGITUDE_FIELD); + + // Haversine formula + const deg2rad = (deg) => (deg * Math.PI) / 180.0; + const earthRadius = 6371; // Radius of the earth in km + const dLat = deg2rad(latitude2 - latitude1); // deg2rad below + const dLon = deg2rad(longitude2 - longitude1); + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(deg2rad(latitude1)) * Math.cos(deg2rad(latitude2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + const d = earthRadius * c; + this.distance = d / 1.609344; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyLocation/propertyLocation.js-meta.xml b/force-app/main/default/lwc/propertyLocation/propertyLocation.js-meta.xml new file mode 100644 index 0000000..8b7c715 --- /dev/null +++ b/force-app/main/default/lwc/propertyLocation/propertyLocation.js-meta.xml @@ -0,0 +1,20 @@ + + + 61.0 + true + Property Location + + lightning__RecordPage + + + + + Property__c + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyMap/__tests__/data/propertyRecord.json b/force-app/main/default/lwc/propertyMap/__tests__/data/propertyRecord.json new file mode 100644 index 0000000..40fa1ce --- /dev/null +++ b/force-app/main/default/lwc/propertyMap/__tests__/data/propertyRecord.json @@ -0,0 +1,26 @@ +{ + "apiName": "Property__c", + "fields": { + "Name": { + "displayValue": null, + "value": "Stunning Colonial" + }, + "Address__c": { + "displayValue": null, + "value": "127 Endicott St" + }, + "City__c": { + "displayValue": null, + "value": "Boston" + }, + "Hutte__Location__Latitude__s": { + "displayValue": null, + "value": "10" + }, + "Hutte__Location__Longitude__s": { + "displayValue": null, + "value": "10" + } + }, + "id": "a013h000009HEM7AAO" +} diff --git a/force-app/main/default/lwc/propertyMap/__tests__/propertyMap.test.js b/force-app/main/default/lwc/propertyMap/__tests__/propertyMap.test.js new file mode 100644 index 0000000..94407c5 --- /dev/null +++ b/force-app/main/default/lwc/propertyMap/__tests__/propertyMap.test.js @@ -0,0 +1,96 @@ +import { createElement } from 'lwc'; +import PropertyMap from 'c/propertyMap'; +import { getRecord } from 'lightning/uiRecordApi'; + +// Realistic property record +const mockPropertyRecord = require('./data/propertyRecord.json'); +const EXPECTED_MAP_MARKERS = [ + { + location: { + Latitude: mockPropertyRecord.fields.Location__Latitude__s.value, + Longitude: mockPropertyRecord.fields.Location__Longitude__s.value + }, + title: `${mockPropertyRecord.fields.Name.value}`, + description: `Address: ${mockPropertyRecord.fields.Address__c.value}`, + mapIcon: { + path: 'M1472 992v480q0 26-19 45t-45 19h-384v-384h-256v384h-384q-26 0-45-19t-19-45v-480q0-1 .5-3t.5-3l575-474 575 474q1 2 1 6zm223-69l-62 74q-8 9-21 11h-3q-13 0-21-7l-692-577-692 577q-12 8-24 7-13-2-21-11l-62-74q-8-10-7-23.5t11-21.5l719-599q32-26 76-26t76 26l244 204v-195q0-14 9-23t23-9h192q14 0 23 9t9 23v408l219 182q10 8 11 21.5t-7 23.5z', + fillColor: '#f28b00', + fillOpacity: 1, + strokeWeight: 1, + scale: 0.02 + } + } +]; + +describe('c-property-map', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('renders an error panel when no property is selected', async () => { + const element = createElement('c-property-map', { + is: PropertyMap + }); + + document.body.appendChild(element); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const panelEl = element.shadowRoot.querySelector('c-error-panel'); + expect(panelEl).not.toBeNull(); + }); + + it('renders a map when a property is selected', async () => { + const element = createElement('c-property-map', { + is: PropertyMap + }); + document.body.appendChild(element); + + // Simulate property selection + getRecord.emit(mockPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const mapEl = element.shadowRoot.querySelector('lightning-map'); + expect(mapEl).not.toBeNull(); + expect(mapEl.mapMarkers).toStrictEqual(EXPECTED_MAP_MARKERS); + }); + + it('is accessible when property is selected', async () => { + const element = createElement('c-property-map', { + is: PropertyMap + }); + + document.body.appendChild(element); + + // Simulate property selection + getRecord.emit(mockPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + await expect(element).toBeAccessible(); + }); + + it('is accessible when property is not selected', async () => { + const element = createElement('c-property-map', { + is: PropertyMap + }); + + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/propertyMap/propertyMap.html b/force-app/main/default/lwc/propertyMap/propertyMap.html new file mode 100644 index 0000000..3b5aa91 --- /dev/null +++ b/force-app/main/default/lwc/propertyMap/propertyMap.html @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyMap/propertyMap.js b/force-app/main/default/lwc/propertyMap/propertyMap.js new file mode 100644 index 0000000..c2d2f9a --- /dev/null +++ b/force-app/main/default/lwc/propertyMap/propertyMap.js @@ -0,0 +1,78 @@ +import { LightningElement, api, wire } from 'lwc'; +import { getRecord } from 'lightning/uiRecordApi'; +import { subscribe, unsubscribe, MessageContext } from 'lightning/messageService'; +import PROPERTYSELECTEDMC from '@salesforce/messageChannel/PropertySelected__c'; + +const fields = [ + 'Hutte__Property__c.Name', + 'Hutte__Property__c.Hutte__Address__c', + 'Hutte__Property__c.Hutte__City__c', + 'Hutte__Property__c.Hutte__Location__Latitude__s', + 'Hutte__Property__c.Hutte__Location__Longitude__s' +]; + +export default class PropertyMap extends LightningElement { + address; + error; + markers; + propertyId; + subscription = null; + zoomLevel = 14; + + @wire(MessageContext) + messageContext; + + @wire(getRecord, { recordId: '$propertyId', fields }) + wiredRecord({ error, data }) { + if (data) { + this.error = undefined; + const property = data.fields; + this.address = `${property.Hutte__Address__c.value}, ${property.Hutte__City__c.value}`; + this.markers = [ + { + location: { + Latitude: property.Hutte__Location__Latitude__s.value, + Longitude: property.Hutte__Location__Longitude__s.value + }, + title: `${property.Name.value}`, + description: `Address: ${property.Hutte__Address__c.value}`, + mapIcon: { + path: 'M1472 992v480q0 26-19 45t-45 19h-384v-384h-256v384h-384q-26 0-45-19t-19-45v-480q0-1 .5-3t.5-3l575-474 575 474q1 2 1 6zm223-69l-62 74q-8 9-21 11h-3q-13 0-21-7l-692-577-692 577q-12 8-24 7-13-2-21-11l-62-74q-8-10-7-23.5t11-21.5l719-599q32-26 76-26t76 26l244 204v-195q0-14 9-23t23-9h192q14 0 23 9t9 23v408l219 182q10 8 11 21.5t-7 23.5z', + fillColor: '#f28b00', + fillOpacity: 1, + strokeWeight: 1, + scale: 0.02 + } + } + ]; + } else if (error) { + this.error = error; + this.address = undefined; + this.markers = []; + } + } + + @api + get recordId() { + return this.propertyId; + } + + set recordId(propertyId) { + this.propertyId = propertyId; + } + + connectedCallback() { + this.subscription = subscribe(this.messageContext, PROPERTYSELECTEDMC, (message) => { + this.handlePropertySelected(message); + }); + } + + disconnectedCallback() { + unsubscribe(this.subscription); + this.subscription = null; + } + + handlePropertySelected(message) { + this.propertyId = message.propertyId; + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyMap/propertyMap.js-meta.xml b/force-app/main/default/lwc/propertyMap/propertyMap.js-meta.xml new file mode 100644 index 0000000..cb1c043 --- /dev/null +++ b/force-app/main/default/lwc/propertyMap/propertyMap.js-meta.xml @@ -0,0 +1,27 @@ + + + 61.0 + true + Property Map + + lightning__AppPage + lightning__RecordPage + + + + + + + + + + + Property__c + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertySummary/__tests__/data/getRecord.json b/force-app/main/default/lwc/propertySummary/__tests__/data/getRecord.json new file mode 100644 index 0000000..efe808d --- /dev/null +++ b/force-app/main/default/lwc/propertySummary/__tests__/data/getRecord.json @@ -0,0 +1,20 @@ +{ + "apiName": "Property__c", + "childRelationships": {}, + "id": "a015I000002taYUQAY", + "lastModifiedById": "0054I000001RjtIQAS", + "lastModifiedDate": "2020-06-09T07:48:54.000Z", + "recordTypeId": "012000000000000AAA", + "recordTypeInfo": null, + "systemModstamp": "2020-06-09T07:48:54.000Z", + "fields": { + "Date_Listed__c": { + "displayValue": "30/5/2020", + "value": "2020-05-30" + }, + "Days_On_Market__c": { + "displayValue": null, + "value": 18 + } + } +} diff --git a/force-app/main/default/lwc/propertySummary/__tests__/propertySummary.test.js b/force-app/main/default/lwc/propertySummary/__tests__/propertySummary.test.js new file mode 100644 index 0000000..0b7f792 --- /dev/null +++ b/force-app/main/default/lwc/propertySummary/__tests__/propertySummary.test.js @@ -0,0 +1,99 @@ +import { createElement } from 'lwc'; +import PropertySummary from 'c/propertySummary'; +import { getRecord } from 'lightning/uiRecordApi'; + +// Realistic property record +const mockPropertyRecord = require('./data/getRecord.json'); + +describe('c-property-summary', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('renders an error panel when no property is selected', async () => { + const element = createElement('c-property-summary', { + is: PropertySummary + }); + + document.body.appendChild(element); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const panelEl = element.shadowRoot.querySelector('c-error-panel'); + expect(panelEl).not.toBeNull(); + }); + + it('renders an error panel when getRecord returns an error', async () => { + const element = createElement('c-property-summary', { + is: PropertySummary + }); + + document.body.appendChild(element); + + // Simulate error + getRecord.error(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const panelEl = element.shadowRoot.querySelector('c-error-panel'); + expect(panelEl).not.toBeNull(); + }); + + it('renders a lightning-record-form when a property is selected', async () => { + const element = createElement('c-property-summary', { + is: PropertySummary + }); + element.recordId = mockPropertyRecord.id; + document.body.appendChild(element); + + // Simulate property selection + getRecord.emit(mockPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const formEl = element.shadowRoot.querySelector( + 'lightning-record-form' + ); + expect(formEl).not.toBeNull(); + expect(formEl.recordId).toStrictEqual(mockPropertyRecord.id); + }); + + it('is accessible when property is selected', async () => { + const element = createElement('c-property-summary', { + is: PropertySummary + }); + + document.body.appendChild(element); + + // Simulate property selection + getRecord.emit(mockPropertyRecord); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + await expect(element).toBeAccessible(); + }); + + it('is accessible when property is not selected', async () => { + const element = createElement('c-property-summary', { + is: PropertySummary + }); + + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/propertySummary/propertySummary.html b/force-app/main/default/lwc/propertySummary/propertySummary.html new file mode 100644 index 0000000..0f9ac71 --- /dev/null +++ b/force-app/main/default/lwc/propertySummary/propertySummary.html @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertySummary/propertySummary.js b/force-app/main/default/lwc/propertySummary/propertySummary.js new file mode 100644 index 0000000..cb73bed --- /dev/null +++ b/force-app/main/default/lwc/propertySummary/propertySummary.js @@ -0,0 +1,73 @@ +import { LightningElement, api, wire } from 'lwc'; +import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; +import { NavigationMixin } from 'lightning/navigation'; +import { subscribe, unsubscribe, MessageContext } from 'lightning/messageService'; +import PROPERTYSELECTEDMC from '@salesforce/messageChannel/PropertySelected__c'; +import NAME_FIELD from '@salesforce/schema/Property__c.Name'; +import BED_FIELD from '@salesforce/schema/Property__c.Beds__c'; +import BATH_FIELD from '@salesforce/schema/Property__c.Baths__c'; +import PRICE_FIELD from '@salesforce/schema/Property__c.Price__c'; +import BROKER_FIELD from '@salesforce/schema/Property__c.Broker__c'; +import PICTURE_FIELD from '@salesforce/schema/Property__c.Picture__c'; + +export default class PropertySummary extends NavigationMixin(LightningElement) { + propertyId; + propertyFields = [BED_FIELD, BATH_FIELD, PRICE_FIELD, BROKER_FIELD]; + subscription = null; + + @wire(MessageContext) + messageContext; + + @wire(getRecord, { + recordId: '$propertyId', + fields: [NAME_FIELD, PICTURE_FIELD] + }) + property; + + @api + get recordId() { + return this.propertyId; + } + + set recordId(propertyId) { + this.propertyId = propertyId; + } + + get hasNoPropertyId() { + return this.propertyId === undefined; + } + + get propertyName() { + return getFieldValue(this.property.data, NAME_FIELD); + } + + get pictureURL() { + return getFieldValue(this.property.data, PICTURE_FIELD); + } + + connectedCallback() { + this.subscription = subscribe(this.messageContext, PROPERTYSELECTEDMC, (message) => { + this.handlePropertySelected(message); + }); + } + + disconnectedCallback() { + unsubscribe(this.subscription); + this.subscription = null; + } + + handlePropertySelected(message) { + this.propertyId = message.propertyId; + } + + handleNavigateToRecord() { + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + recordId: this.propertyId, + objectApiName: 'Hutte__Property__c', + actionName: 'view' + } + }); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertySummary/propertySummary.js-meta.xml b/force-app/main/default/lwc/propertySummary/propertySummary.js-meta.xml new file mode 100644 index 0000000..c4aa467 --- /dev/null +++ b/force-app/main/default/lwc/propertySummary/propertySummary.js-meta.xml @@ -0,0 +1,27 @@ + + + 61.0 + true + Property Summary + + lightning__AppPage + lightning__RecordPage + + + + + + + + + + + Property__c + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTile/__tests__/propertyTile.small.test.js b/force-app/main/default/lwc/propertyTile/__tests__/propertyTile.small.test.js new file mode 100644 index 0000000..440d877 --- /dev/null +++ b/force-app/main/default/lwc/propertyTile/__tests__/propertyTile.small.test.js @@ -0,0 +1,66 @@ +import { createElement } from 'lwc'; +import PropertyTile from 'c/propertyTile'; +import { getNavigateCalledWith } from 'lightning/navigation'; + +const PROPERTY = { + City__c: 'Some City', + Beds__c: '3', + Baths__c: '1', + Price__c: '450000', + Thumbnail__c: 'some-property.jpg', + Id: '12345' +}; + +// Mock small formFactor -> Currently this test resides +// in a different file because there is no way to reassign the mock dynamically +jest.mock( + '@salesforce/client/formFactor', + () => { + return { default: 'Small' }; + }, + { virtual: true } +); + +describe('c-property-tile', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('Navigates to property record page on click for Small formFactor', async () => { + const NAV_TYPE = 'standard__recordPage'; + const NAV_ACTION_NAME = 'view'; + const NAV_OBJECT_API_NAME = 'Property__c'; + + const element = createElement('c-property-tile', { + is: PropertyTile + }); + element.property = PROPERTY; + document.body.appendChild(element); + + const anchorEl = element.shadowRoot.querySelector('a'); + anchorEl.click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Get data the NavigationMixin was called with + const { pageReference } = getNavigateCalledWith(); + + // Confirm redirection to expected property record + expect(pageReference.type).toBe(NAV_TYPE); + expect(pageReference.attributes.actionName).toBe(NAV_ACTION_NAME); + expect(pageReference.attributes.objectApiName).toBe( + NAV_OBJECT_API_NAME + ); + expect(pageReference.attributes.recordId).toBe(PROPERTY.Id); + }); +}); diff --git a/force-app/main/default/lwc/propertyTile/__tests__/propertyTile.test.js b/force-app/main/default/lwc/propertyTile/__tests__/propertyTile.test.js new file mode 100644 index 0000000..9bf9f29 --- /dev/null +++ b/force-app/main/default/lwc/propertyTile/__tests__/propertyTile.test.js @@ -0,0 +1,97 @@ +import { createElement } from 'lwc'; +import PropertyTile from 'c/propertyTile'; + +const PROPERTY = { + Name: 'My House', + City__c: 'Some City', + Beds__c: '3', + Baths__c: '1', + Price__c: '450000', + Thumbnail__c: 'some-property.jpg', + Id: '12345' +}; + +describe('c-property-tile', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('displays a property in the tile', () => { + const element = createElement('c-property-tile', { + is: PropertyTile + }); + element.property = PROPERTY; + document.body.appendChild(element); + + const headerEl = element.shadowRoot.querySelector('.truncate'); + expect(headerEl.textContent).toBe( + `${PROPERTY.City__c} • ${PROPERTY.Name}` + ); + + const paragraphEl = element.shadowRoot.querySelector('p'); + expect(paragraphEl.textContent).toBe( + `Beds: ${PROPERTY.Beds__c} - Baths: ${PROPERTY.Baths__c}` + ); + + const priceEl = element.shadowRoot.querySelector( + 'lightning-formatted-number' + ); + expect(priceEl.value).toBe(PROPERTY.Price__c); + }); + + it('displays the correct background image in the tile', () => { + const element = createElement('c-property-tile', { + is: PropertyTile + }); + element.property = PROPERTY; + document.body.appendChild(element); + + const backgroundEl = element.shadowRoot.querySelector('.tile'); + expect(backgroundEl.style.backgroundImage).toBe( + `url(${PROPERTY.Thumbnail__c})` + ); + }); + + it('Fires the property selected event on click for non Small formFactors', async () => { + const element = createElement('c-property-tile', { + is: PropertyTile + }); + element.property = PROPERTY; + document.body.appendChild(element); + + // Mock handler for child event + const handler = jest.fn(); + element.addEventListener('selected', handler); + + const anchorEl = element.shadowRoot.querySelector('a'); + anchorEl.click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Validate if event got fired + expect(handler).toHaveBeenCalled(); + const selectEvent = handler.mock.calls[0][0]; + expect(selectEvent.detail).toBe(PROPERTY.Id); + }); + + it('is accessible', async () => { + const element = createElement('c-property-tile', { + is: PropertyTile + }); + + element.property = PROPERTY; + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/propertyTile/propertyTile.css b/force-app/main/default/lwc/propertyTile/propertyTile.css new file mode 100644 index 0000000..8b9e0d1 --- /dev/null +++ b/force-app/main/default/lwc/propertyTile/propertyTile.css @@ -0,0 +1,26 @@ +.tile { + position: relative; + height: 220px; + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +.lower-third { + position: absolute; + /* @sldsValidatorIgnore */ + bottom: 0; + /* @sldsValidatorIgnore */ + left: 0; + /* @sldsValidatorIgnore */ + right: 0; + background-color: rgba(0, 0, 0, 0.5); +} + +.truncate { + /* @sldsValidatorIgnore */ + white-space: nowrap; + overflow: hidden; + /* @sldsValidatorIgnore */ + text-overflow: ellipsis; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTile/propertyTile.html b/force-app/main/default/lwc/propertyTile/propertyTile.html new file mode 100644 index 0000000..4b4f24c --- /dev/null +++ b/force-app/main/default/lwc/propertyTile/propertyTile.html @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTile/propertyTile.js b/force-app/main/default/lwc/propertyTile/propertyTile.js new file mode 100644 index 0000000..a9fc6bb --- /dev/null +++ b/force-app/main/default/lwc/propertyTile/propertyTile.js @@ -0,0 +1,32 @@ +import { LightningElement, api } from 'lwc'; +import FORM_FACTOR from '@salesforce/client/formFactor'; +import { NavigationMixin } from 'lightning/navigation'; + +export default class PropertyTile extends NavigationMixin(LightningElement) { + @api property; + formFactor = FORM_FACTOR; + + handlePropertySelected() { + if (FORM_FACTOR === 'Small') { + // In Phones, navigate to property record page directly + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + recordId: this.property.Id, + objectApiName: 'Hutte__Property__c', + actionName: 'view' + } + }); + } else { + // In other devices, send message to other cmps on the page + const selectedEvent = new CustomEvent('selected', { + detail: this.property.Id + }); + this.dispatchEvent(selectedEvent); + } + } + + get backgroundImageStyle() { + return `background-image:url(${this.property.Hutte__Thumbnail__c})`; + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTile/propertyTile.js-meta.xml b/force-app/main/default/lwc/propertyTile/propertyTile.js-meta.xml new file mode 100644 index 0000000..a4a5ed3 --- /dev/null +++ b/force-app/main/default/lwc/propertyTile/propertyTile.js-meta.xml @@ -0,0 +1,5 @@ + + + 61.0 + false + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTileList/__tests__/data/getPagedPropertyList.json b/force-app/main/default/lwc/propertyTileList/__tests__/data/getPagedPropertyList.json new file mode 100644 index 0000000..2c5d2c3 --- /dev/null +++ b/force-app/main/default/lwc/propertyTileList/__tests__/data/getPagedPropertyList.json @@ -0,0 +1,106 @@ +{ + "pageNumber": 1, + "pageSize": 9, + "records": [ + { + "Id": "a012F000009ovH1QAI", + "Address__c": "127 Endicott St", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 450000, + "Baths__c": 1, + "Beds__c": 3, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house07sq.jpg" + }, + { + "Id": "a012F000009ovH2QAI", + "Address__c": "48 Brattle st", + "City__c": "Cambridge", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 450000, + "Baths__c": 4, + "Beds__c": 5, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house10sq.jpg" + }, + { + "Id": "a012F000009ovH3QAI", + "Address__c": "121 Harborwalk", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 450000, + "Baths__c": 3, + "Beds__c": 3, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house09sq.jpg" + }, + { + "Id": "a012F000009ovH4QAI", + "Address__c": "640 Harrison Ave", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 650000, + "Baths__c": 2, + "Beds__c": 2, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house08sq.jpg" + }, + { + "Id": "a012F000009ovH5QAI", + "Address__c": "95 Gloucester St", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 690000, + "Baths__c": 3, + "Beds__c": 3, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house11sq.jpg" + }, + { + "Id": "a012F000009ovH0QAI", + "Address__c": "448 Hanover St", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 725000, + "Baths__c": 2, + "Beds__c": 4, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house06sq.jpg" + }, + { + "Id": "a012F000009ovGxQAI", + "Address__c": "72 Francis st", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 825000, + "Baths__c": 4, + "Beds__c": 5, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house03sq.jpg" + }, + { + "Id": "a012F000009ovH6QAI", + "Address__c": "145 Commonwealth Ave", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 845000, + "Baths__c": 3, + "Beds__c": 4, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house12sq.jpg" + }, + { + "Id": "a012F000009ovGzQAI", + "Address__c": "110 Baxter Street", + "City__c": "Boston", + "State__c": "MA", + "Description__c": "Lorem ipsum dolor sit amet", + "Price__c": 850000, + "Baths__c": 2, + "Beds__c": 3, + "Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house05sq.jpg" + } + ], + "totalItemCount": 12 +} diff --git a/force-app/main/default/lwc/propertyTileList/__tests__/propertyTileList.test.js b/force-app/main/default/lwc/propertyTileList/__tests__/propertyTileList.test.js new file mode 100644 index 0000000..17a8166 --- /dev/null +++ b/force-app/main/default/lwc/propertyTileList/__tests__/propertyTileList.test.js @@ -0,0 +1,134 @@ +import { createElement } from 'lwc'; +import PropertyTileList from 'c/propertyTileList'; +import getPagedPropertyList from '@salesforce/apex/PropertyController.getPagedPropertyList'; +import { publish, subscribe, MessageContext } from 'lightning/messageService'; +import FILTERSCHANGEMC from '@salesforce/messageChannel/FiltersChange__c'; +import PROPERTYSELECTEDMC from '@salesforce/messageChannel/PropertySelected__c'; + +// Realistic data with multiple records +const mockgetPagedPropertyList = require('./data/getPagedPropertyList.json'); + +// Mock getPagedPropertyList Apex wire adapter +jest.mock( + '@salesforce/apex/PropertyController.getPagedPropertyList', + () => { + const { + createApexTestWireAdapter + } = require('@salesforce/sfdx-lwc-jest'); + return { + default: createApexTestWireAdapter(jest.fn()) + }; + }, + { virtual: true } +); + +describe('c-property-tile-list', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + describe('@wire data', () => { + it('renders properties when data returned', async () => { + const element = createElement('c-property-tile-list', { + is: PropertyTileList + }); + document.body.appendChild(element); + + // Emit mock properties + getPagedPropertyList.emit(mockgetPagedPropertyList); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const propertyTileEls = + element.shadowRoot.querySelectorAll('c-property-tile'); + expect(propertyTileEls.length).toBe( + mockgetPagedPropertyList.records.length + ); + }); + + it('renders error panel when error returned', async () => { + const element = createElement('c-property-tile-list', { + is: PropertyTileList + }); + document.body.appendChild(element); + + // Emit error + getPagedPropertyList.error(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const errorPanelEl = + element.shadowRoot.querySelector('c-error-panel'); + expect(errorPanelEl).not.toBeNull(); + }); + }); + + it('registers propertyFilters subscriber during the component lifecycle', () => { + const element = createElement('c-property-tile-list', { + is: PropertyTileList + }); + document.body.appendChild(element); + + // Validate if subscriber got registered after connected to the DOM + expect(subscribe).toHaveBeenCalled(); + expect(subscribe.mock.calls[0][1]).toBe(FILTERSCHANGEMC); + }); + + it('invokes getPagedPropertyList with the propertyFilters message payload value', async () => { + const element = createElement('c-property-tile-list', { + is: PropertyTileList + }); + document.body.appendChild(element); + + // Simulate pulishing a message using FILTERSCHANGEMC message channel + const messagePayload = { + searchKey: 'victorian', + maxPrice: 400000, + minBedrooms: 4, + minBathrooms: 2 + }; + publish(MessageContext, FILTERSCHANGEMC, messagePayload); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // The component subscription should cause getRecord to be invoked. + // Below we test that it is invoked with the messagePayload value + // that was published with the simulated publish invocation above. + const receivedPayload = getPagedPropertyList.getLastConfig(); + expect(receivedPayload.searchKey).toBe(messagePayload.searchKey); + expect(receivedPayload.maxPrice).toBe(messagePayload.maxPrice); + expect(receivedPayload.minBedrooms).toBe(messagePayload.minBedrooms); + expect(receivedPayload.minBathrooms).toBe(messagePayload.minBathrooms); + }); + + it('sends propertySelected event when c-property-tile selected', async () => { + const element = createElement('c-property-tile-list', { + is: PropertyTileList + }); + document.body.appendChild(element); + getPagedPropertyList.emit(mockgetPagedPropertyList); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + const propertyTile = + element.shadowRoot.querySelector('c-property-tile'); + propertyTile.dispatchEvent(new CustomEvent('selected')); + expect(publish).toHaveBeenCalledWith(undefined, PROPERTYSELECTEDMC, { + propertyId: null + }); + }); +}); diff --git a/force-app/main/default/lwc/propertyTileList/propertyTileList.css b/force-app/main/default/lwc/propertyTileList/propertyTileList.css new file mode 100644 index 0000000..64ee5c6 --- /dev/null +++ b/force-app/main/default/lwc/propertyTileList/propertyTileList.css @@ -0,0 +1,7 @@ +c-property-tile { + min-width: 220px; +} + +c-property-tile:hover { + box-shadow: 4px 5px 5px #9d9fa0; +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTileList/propertyTileList.html b/force-app/main/default/lwc/propertyTileList/propertyTileList.html new file mode 100644 index 0000000..7d9cea9 --- /dev/null +++ b/force-app/main/default/lwc/propertyTileList/propertyTileList.html @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTileList/propertyTileList.js b/force-app/main/default/lwc/propertyTileList/propertyTileList.js new file mode 100644 index 0000000..1ac164b --- /dev/null +++ b/force-app/main/default/lwc/propertyTileList/propertyTileList.js @@ -0,0 +1,70 @@ +import { LightningElement, wire } from 'lwc'; +import { + publish, + subscribe, + unsubscribe, + MessageContext +} from 'lightning/messageService'; +import FILTERSCHANGEMC from '@salesforce/messageChannel/FiltersChange__c'; +import PROPERTYSELECTEDMC from '@salesforce/messageChannel/PropertySelected__c'; +import getPagedPropertyList from '@salesforce/apex/PropertyController.getPagedPropertyList'; + +const PAGE_SIZE = 9; + +export default class PropertyTileList extends LightningElement { + pageNumber = 1; + pageSize = PAGE_SIZE; + + searchKey = ''; + maxPrice = 9999999; + minBedrooms = 0; + minBathrooms = 0; + + @wire(MessageContext) + messageContext; + + @wire(getPagedPropertyList, { + searchKey: '$searchKey', + maxPrice: '$maxPrice', + minBedrooms: '$minBedrooms', + minBathrooms: '$minBathrooms', + pageSize: '$pageSize', + pageNumber: '$pageNumber' + }) + properties; + + connectedCallback() { + this.subscription = subscribe( + this.messageContext, + FILTERSCHANGEMC, + (message) => { + this.handleFilterChange(message); + } + ); + } + + disconnectedCallback() { + unsubscribe(this.subscription); + this.subscription = null; + } + + handleFilterChange(filters) { + this.searchKey = filters.searchKey; + this.maxPrice = filters.maxPrice; + this.minBedrooms = filters.minBedrooms; + this.minBathrooms = filters.minBathrooms; + } + + handlePreviousPage() { + this.pageNumber = this.pageNumber - 1; + } + + handleNextPage() { + this.pageNumber = this.pageNumber + 1; + } + + handlePropertySelected(event) { + const message = { propertyId: event.detail }; + publish(this.messageContext, PROPERTYSELECTEDMC, message); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTileList/propertyTileList.js-meta.xml b/force-app/main/default/lwc/propertyTileList/propertyTileList.js-meta.xml new file mode 100644 index 0000000..9270748 --- /dev/null +++ b/force-app/main/default/lwc/propertyTileList/propertyTileList.js-meta.xml @@ -0,0 +1,17 @@ + + + 61.0 + true + Property Tile List + + lightning__AppPage + + + + + + + + + + \ No newline at end of file diff --git a/force-app/main/default/lwc/sampleDataImporter/__tests__/sampleDataImporter.test.js b/force-app/main/default/lwc/sampleDataImporter/__tests__/sampleDataImporter.test.js new file mode 100644 index 0000000..4bbd9b0 --- /dev/null +++ b/force-app/main/default/lwc/sampleDataImporter/__tests__/sampleDataImporter.test.js @@ -0,0 +1,115 @@ +import { createElement } from 'lwc'; +import SampleDataImporter from 'c/sampleDataImporter'; +import { ShowToastEventName } from 'lightning/platformShowToastEvent'; +import importSampleData from '@salesforce/apex/SampleDataController.importSampleData'; + +// Mocking imperative Apex method call +jest.mock( + '@salesforce/apex/SampleDataController.importSampleData', + () => { + return { + default: jest.fn() + }; + }, + { virtual: true } +); + +// Sample data for imperative Apex call +const APEX_OPERATION_SUCCESS = null; + +// Sample error for imperative Apex call +const APEX_OPERATION_ERROR = { + message: 'An internal server error has occurred' +}; + +describe('c-sample-data-importer', () => { + afterEach(() => { + // The jsdom instance is shared across test cases in a single file so reset the DOM + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + + // Prevent data saved on mocks from leaking between tests + jest.clearAllMocks(); + }); + + // Helper function to wait until the microtask queue is empty. + // Used when having to wait for asynchronous DOM updates. + async function flushPromises() { + return Promise.resolve(); + } + + it('fires success event when importSampleData runs successfully', async () => { + // Assign mock value for resolved Apex promise + importSampleData.mockResolvedValue(APEX_OPERATION_SUCCESS); + + // Create initial element + const element = createElement('c-sample-data-importer', { + is: SampleDataImporter + }); + document.body.appendChild(element); + + // Mock handler for toast event + const handler = jest.fn(); + // Add event listener to catch toast event + element.addEventListener(ShowToastEventName, handler); + + // Select button for executing Apex call + const buttonEl = element.shadowRoot.querySelector('lightning-button'); + buttonEl.click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Check if toast event has been fired + expect(handler).toHaveBeenCalled(); + expect(handler.mock.calls[0][0].detail.variant).toBe('success'); + expect(handler.mock.calls[0][0].detail.title).toBe('Success'); + expect(handler.mock.calls[0][0].detail.message).toBe( + 'Sample data successfully imported' + ); + }); + + it('fires error event when importSampleData runs with error', async () => { + // Assign mock value for resolved Apex promise + importSampleData.mockRejectedValue(APEX_OPERATION_ERROR); + + // Create initial element + const element = createElement('c-sample-data-importer', { + is: SampleDataImporter + }); + document.body.appendChild(element); + + // Mock handler for toast event + const handler = jest.fn(); + // Add event listener to catch toast event + element.addEventListener(ShowToastEventName, handler); + + // Select button for executing Apex call + const buttonEl = element.shadowRoot.querySelector('lightning-button'); + buttonEl.click(); + + // Wait for any asynchronous DOM updates + await flushPromises(); + + // Check if toast event has been fired + expect(handler).toHaveBeenCalled(); + expect(handler.mock.calls[0][0].detail.variant).toBe('error'); + expect(handler.mock.calls[0][0].detail.title).toBe( + 'Error while importing data' + ); + expect(handler.mock.calls[0][0].detail.message).toBe( + APEX_OPERATION_ERROR.message + ); + }); + + it('is accessible', async () => { + const element = createElement('c-sample-data-importer', { + is: SampleDataImporter + }); + + document.body.appendChild(element); + + await expect(element).toBeAccessible(); + }); +}); diff --git a/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.html b/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.html new file mode 100644 index 0000000..5c85454 --- /dev/null +++ b/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.html @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.js b/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.js new file mode 100644 index 0000000..760f337 --- /dev/null +++ b/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.js @@ -0,0 +1,25 @@ +import { LightningElement } from 'lwc'; +import { ShowToastEvent } from 'lightning/platformShowToastEvent'; +import importSampleData from '@salesforce/apex/SampleDataController.importSampleData'; + +export default class SampleDataImporter extends LightningElement { + handleImportSampleData() { + importSampleData() + .then(() => { + const evt = new ShowToastEvent({ + title: 'Success', + message: 'Sample data successfully imported', + variant: 'success' + }); + this.dispatchEvent(evt); + }) + .catch((e) => { + const evt = new ShowToastEvent({ + title: 'Error while importing data', + message: e.message, + variant: 'error' + }); + this.dispatchEvent(evt); + }); + } +} \ No newline at end of file diff --git a/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.js-meta.xml b/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.js-meta.xml new file mode 100644 index 0000000..a258006 --- /dev/null +++ b/force-app/main/default/lwc/sampleDataImporter/sampleDataImporter.js-meta.xml @@ -0,0 +1,9 @@ + + + 61.0 + true + Sample Property Importer + + lightning__AppPage + + \ No newline at end of file diff --git a/force-app/main/default/messageChannels/FiltersChange.messageChannel-meta.xml b/force-app/main/default/messageChannels/FiltersChange.messageChannel-meta.xml new file mode 100644 index 0000000..332e2e4 --- /dev/null +++ b/force-app/main/default/messageChannels/FiltersChange.messageChannel-meta.xml @@ -0,0 +1,21 @@ + + + true + + Search Key + searchKey + + + Max Price + maxPrice + + + Minimum number of Bedrooms + minBedrooms + + + Minimum number of Bathrooms + minBathrooms + + Filters Change Message Channel + diff --git a/force-app/main/default/messageChannels/PropertySelected.messageChannel-meta.xml b/force-app/main/default/messageChannels/PropertySelected.messageChannel-meta.xml new file mode 100644 index 0000000..1226ff1 --- /dev/null +++ b/force-app/main/default/messageChannels/PropertySelected.messageChannel-meta.xml @@ -0,0 +1,9 @@ + + + true + + Property Id + propertyId + + Property Selected Message Channel + diff --git a/force-app/main/default/objects/Broker__c/Broker__c.object-meta.xml b/force-app/main/default/objects/Broker__c/Broker__c.object-meta.xml new file mode 100644 index 0000000..385ff44 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/Broker__c.object-meta.xml @@ -0,0 +1,165 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Default + + + View + Large + Default + + + View + Small + Default + + false + Broker_Compact + Deployed + false + true + false + false + false + true + true + true + true + Private + + + + Text + + Brokers + + ReadWrite + Public + diff --git a/force-app/main/default/objects/Broker__c/compactLayouts/Broker_Compact.compactLayout-meta.xml b/force-app/main/default/objects/Broker__c/compactLayouts/Broker_Compact.compactLayout-meta.xml new file mode 100644 index 0000000..1975fa1 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/compactLayouts/Broker_Compact.compactLayout-meta.xml @@ -0,0 +1,10 @@ + + + Broker_Compact + Name + Title__c + Phone__c + Mobile_Phone__c + Email__c + + diff --git a/force-app/main/default/objects/Broker__c/fields/Broker_Id__c.field-meta.xml b/force-app/main/default/objects/Broker__c/fields/Broker_Id__c.field-meta.xml new file mode 100644 index 0000000..97bae1d --- /dev/null +++ b/force-app/main/default/objects/Broker__c/fields/Broker_Id__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Broker_Id__c + true + + 18 + false + 0 + false + Number + false + diff --git a/force-app/main/default/objects/Broker__c/fields/Email__c.field-meta.xml b/force-app/main/default/objects/Broker__c/fields/Email__c.field-meta.xml new file mode 100644 index 0000000..45ab92b --- /dev/null +++ b/force-app/main/default/objects/Broker__c/fields/Email__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Email__c + false + The email address of your broker + + false + false + Email + false + diff --git a/force-app/main/default/objects/Broker__c/fields/Mobile_Phone__c.field-meta.xml b/force-app/main/default/objects/Broker__c/fields/Mobile_Phone__c.field-meta.xml new file mode 100644 index 0000000..0f57f49 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/fields/Mobile_Phone__c.field-meta.xml @@ -0,0 +1,8 @@ + + + Mobile_Phone__c + + false + false + Phone + diff --git a/force-app/main/default/objects/Broker__c/fields/Phone__c.field-meta.xml b/force-app/main/default/objects/Broker__c/fields/Phone__c.field-meta.xml new file mode 100644 index 0000000..56f9ae6 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/fields/Phone__c.field-meta.xml @@ -0,0 +1,8 @@ + + + Phone__c + + false + false + Phone + diff --git a/force-app/main/default/objects/Broker__c/fields/Picture_IMG__c.field-meta.xml b/force-app/main/default/objects/Broker__c/fields/Picture_IMG__c.field-meta.xml new file mode 100644 index 0000000..1ee98c4 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/fields/Picture_IMG__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Picture_IMG__c + false + IMAGE( Picture__c , "picture" , 150, 150) + BlankAsZero + + false + false + Text + false + diff --git a/force-app/main/default/objects/Broker__c/fields/Picture__c.field-meta.xml b/force-app/main/default/objects/Broker__c/fields/Picture__c.field-meta.xml new file mode 100644 index 0000000..c596e64 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/fields/Picture__c.field-meta.xml @@ -0,0 +1,8 @@ + + + Picture__c + + false + false + Url + diff --git a/force-app/main/default/objects/Broker__c/fields/Title__c.field-meta.xml b/force-app/main/default/objects/Broker__c/fields/Title__c.field-meta.xml new file mode 100644 index 0000000..88d88c8 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/fields/Title__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Title__c + false + + 30 + false + false + Text + false + diff --git a/force-app/main/default/objects/Broker__c/listViews/All.listView-meta.xml b/force-app/main/default/objects/Broker__c/listViews/All.listView-meta.xml new file mode 100644 index 0000000..f957a40 --- /dev/null +++ b/force-app/main/default/objects/Broker__c/listViews/All.listView-meta.xml @@ -0,0 +1,7 @@ + + + All + NAME + Everything + + diff --git a/force-app/main/default/objects/Property__c/Property__c.object-meta.xml b/force-app/main/default/objects/Property__c/Property__c.object-meta.xml new file mode 100644 index 0000000..9a51b3e --- /dev/null +++ b/force-app/main/default/objects/Property__c/Property__c.object-meta.xml @@ -0,0 +1,167 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Default + + + View + Large + Default + + + View + Small + Default + + false + Property_Compact_Layout + Deployed + true + true + true + true + false + true + true + true + true + Private + + + + false + false + Text + + Properties + + ReadWrite + Public + diff --git a/force-app/main/default/objects/Property__c/compactLayouts/Property_Compact_Layout.compactLayout-meta.xml b/force-app/main/default/objects/Property__c/compactLayouts/Property_Compact_Layout.compactLayout-meta.xml new file mode 100644 index 0000000..bbe1071 --- /dev/null +++ b/force-app/main/default/objects/Property__c/compactLayouts/Property_Compact_Layout.compactLayout-meta.xml @@ -0,0 +1,10 @@ + + + Property_Compact_Layout + Name + City__c + Price__c + Beds__c + Baths__c + + diff --git a/force-app/main/default/objects/Property__c/fields/Address__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Address__c.field-meta.xml new file mode 100644 index 0000000..5fbb048 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Address__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Address__c + false + + 100 + false + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/fields/Assessed_Value__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Assessed_Value__c.field-meta.xml new file mode 100644 index 0000000..bbeddad --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Assessed_Value__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Assessed_Value__c + + 18 + false + 0 + false + false + false + Currency + diff --git a/force-app/main/default/objects/Property__c/fields/Baths__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Baths__c.field-meta.xml new file mode 100644 index 0000000..107b031 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Baths__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Baths__c + false + + 2 + false + 0 + false + false + false + Number + false + diff --git a/force-app/main/default/objects/Property__c/fields/Beds__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Beds__c.field-meta.xml new file mode 100644 index 0000000..3adbb35 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Beds__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Beds__c + false + + 2 + false + 0 + false + false + false + Number + false + diff --git a/force-app/main/default/objects/Property__c/fields/Broker__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Broker__c.field-meta.xml new file mode 100644 index 0000000..9eafffe --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Broker__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Broker__c + SetNull + + Broker__c + Properties + Properties + false + false + false + false + Lookup + diff --git a/force-app/main/default/objects/Property__c/fields/City__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/City__c.field-meta.xml new file mode 100644 index 0000000..c3ccc00 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/City__c.field-meta.xml @@ -0,0 +1,13 @@ + + + City__c + false + + 50 + false + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/fields/Date_Agreement__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Date_Agreement__c.field-meta.xml new file mode 100644 index 0000000..f4d60c9 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Date_Agreement__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Date_Agreement__c + + false + false + false + false + Date + diff --git a/force-app/main/default/objects/Property__c/fields/Date_Closed__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Date_Closed__c.field-meta.xml new file mode 100644 index 0000000..fcfc112 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Date_Closed__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Date_Closed__c + + false + false + false + false + Date + diff --git a/force-app/main/default/objects/Property__c/fields/Date_Contracted__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Date_Contracted__c.field-meta.xml new file mode 100644 index 0000000..76c6e4c --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Date_Contracted__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Date_Contracted__c + + false + false + false + false + Date + diff --git a/force-app/main/default/objects/Property__c/fields/Date_Listed__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Date_Listed__c.field-meta.xml new file mode 100644 index 0000000..b2dd9ca --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Date_Listed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Date_Listed__c + TODAY() - 10 + + false + false + false + false + Date + diff --git a/force-app/main/default/objects/Property__c/fields/Date_Pre_Market__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Date_Pre_Market__c.field-meta.xml new file mode 100644 index 0000000..165555b --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Date_Pre_Market__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Date_Pre_Market__c + + false + false + false + false + Date + diff --git a/force-app/main/default/objects/Property__c/fields/Days_On_Market__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Days_On_Market__c.field-meta.xml new file mode 100644 index 0000000..43095ad --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Days_On_Market__c.field-meta.xml @@ -0,0 +1,15 @@ + + + Days_On_Market__c + false + TODAY() - Date_Listed__c + BlankAsZero + + 18 + false + 0 + false + false + Number + false + diff --git a/force-app/main/default/objects/Property__c/fields/Description__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Description__c.field-meta.xml new file mode 100644 index 0000000..3df16b2 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Description__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Description__c + + 500 + false + false + false + LongTextArea + 3 + diff --git a/force-app/main/default/objects/Property__c/fields/Location__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Location__c.field-meta.xml new file mode 100644 index 0000000..3deb1ef --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Location__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Location__c + true + + false + 7 + false + false + false + Location + diff --git a/force-app/main/default/objects/Property__c/fields/Picture_IMG__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Picture_IMG__c.field-meta.xml new file mode 100644 index 0000000..1be1f9e --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Picture_IMG__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Picture_IMG__c + false + if(ISBLANK(Picture__c), '', IMAGE(Picture__c, "Picture")) + BlankAsZero + + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/fields/Picture__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Picture__c.field-meta.xml new file mode 100644 index 0000000..6340e23 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Picture__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Picture__c + + false + false + false + false + Url + diff --git a/force-app/main/default/objects/Property__c/fields/Price_Sold__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Price_Sold__c.field-meta.xml new file mode 100644 index 0000000..565dae8 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Price_Sold__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Price_Sold__c + + 8 + false + 0 + false + false + false + Currency + diff --git a/force-app/main/default/objects/Property__c/fields/Price__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Price__c.field-meta.xml new file mode 100644 index 0000000..621f854 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Price__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Price__c + + 8 + false + 0 + true + true + false + Currency + diff --git a/force-app/main/default/objects/Property__c/fields/Record_Link__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Record_Link__c.field-meta.xml new file mode 100644 index 0000000..a186ead --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Record_Link__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Record_Link__c + false + LEFT($Api.Partner_Server_URL_260, FIND( '/services', $Api.Partner_Server_URL_260))+ Id + BlankAsZero + + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/fields/State__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/State__c.field-meta.xml new file mode 100644 index 0000000..286d042 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/State__c.field-meta.xml @@ -0,0 +1,13 @@ + + + State__c + false + + 20 + false + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/fields/Status__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Status__c.field-meta.xml new file mode 100644 index 0000000..a663176 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Status__c.field-meta.xml @@ -0,0 +1,41 @@ + + + Status__c + + false + true + false + false + Picklist + + true + + false + + Contracted + false + + + + Pre Market + false + + + + Available + false + + + + Under Agreement + false + + + + Closed + false + + + + + diff --git a/force-app/main/default/objects/Property__c/fields/Tags__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Tags__c.field-meta.xml new file mode 100644 index 0000000..8fc32b7 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Tags__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Tags__c + false + + 255 + false + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/fields/Thumbnail_IMG__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Thumbnail_IMG__c.field-meta.xml new file mode 100644 index 0000000..2882ef9 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Thumbnail_IMG__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Thumbnail_IMG__c + false + if(ISBLANK(Thumbnail__c), "", IMAGE(Thumbnail__c, "Picture", 200, 200)) + BlankAsZero + + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/fields/Thumbnail__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Thumbnail__c.field-meta.xml new file mode 100644 index 0000000..48048c7 --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Thumbnail__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Thumbnail__c + + false + false + false + false + Url + diff --git a/force-app/main/default/objects/Property__c/fields/Zip__c.field-meta.xml b/force-app/main/default/objects/Property__c/fields/Zip__c.field-meta.xml new file mode 100644 index 0000000..283915b --- /dev/null +++ b/force-app/main/default/objects/Property__c/fields/Zip__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Zip__c + false + + 10 + false + false + false + false + Text + false + diff --git a/force-app/main/default/objects/Property__c/listViews/All.listView-meta.xml b/force-app/main/default/objects/Property__c/listViews/All.listView-meta.xml new file mode 100644 index 0000000..576f82e --- /dev/null +++ b/force-app/main/default/objects/Property__c/listViews/All.listView-meta.xml @@ -0,0 +1,11 @@ + + + All + NAME + City__c + Beds__c + Price__c + Status__c + Everything + + diff --git a/force-app/main/default/permissionsets/dreamhouse.permissionset-meta.xml b/force-app/main/default/permissionsets/dreamhouse.permissionset-meta.xml new file mode 100644 index 0000000..61d8f2d --- /dev/null +++ b/force-app/main/default/permissionsets/dreamhouse.permissionset-meta.xml @@ -0,0 +1,219 @@ + + + + Dreamhouse + true + + + PagedResult + true + + + PropertyController + true + + + SampleDataController + true + + + true + Broker__c.Broker_Id__c + true + + + true + Broker__c.Email__c + true + + + true + Broker__c.Mobile_Phone__c + true + + + true + Broker__c.Phone__c + true + + + false + Broker__c.Picture_IMG__c + true + + + true + Broker__c.Picture__c + true + + + true + Broker__c.Title__c + true + + + true + Property__c.Address__c + true + + + true + Property__c.Assessed_Value__c + true + + + true + Property__c.Baths__c + true + + + true + Property__c.Beds__c + true + + + true + Property__c.Broker__c + true + + + true + Property__c.City__c + true + + + true + Property__c.Date_Agreement__c + true + + + true + Property__c.Date_Closed__c + true + + + true + Property__c.Date_Contracted__c + true + + + true + Property__c.Date_Listed__c + true + + + true + Property__c.Date_Pre_Market__c + true + + + false + Property__c.Days_On_Market__c + true + + + true + Property__c.Description__c + true + + + true + Property__c.Location__c + true + + + false + Property__c.Picture_IMG__c + true + + + true + Property__c.Picture__c + true + + + true + Property__c.Price_Sold__c + true + + + true + Property__c.Price__c + true + + + false + Property__c.Record_Link__c + true + + + true + Property__c.State__c + true + + + true + Property__c.Status__c + true + + + true + Property__c.Tags__c + true + + + false + Property__c.Thumbnail_IMG__c + true + + + true + Property__c.Thumbnail__c + true + + + true + Property__c.Zip__c + true + + false + + + true + true + true + true + true + Broker__c + true + + + true + true + true + true + true + Property__c + true + + + Broker__c + Visible + + + Property_Explorer + Visible + + + Property_Finder + Visible + + + Property__c + Visible + + + Settings + Visible + + diff --git a/force-app/main/default/remoteSiteSettings/nominatim_openstreetmap.remoteSite-meta.xml b/force-app/main/default/remoteSiteSettings/nominatim_openstreetmap.remoteSite-meta.xml new file mode 100644 index 0000000..43dc76c --- /dev/null +++ b/force-app/main/default/remoteSiteSettings/nominatim_openstreetmap.remoteSite-meta.xml @@ -0,0 +1,6 @@ + + + false + true + https://nominatim.openstreetmap.org + diff --git a/force-app/main/default/staticresources/leafletjs.resource-meta.xml b/force-app/main/default/staticresources/leafletjs.resource-meta.xml new file mode 100644 index 0000000..3f3975f --- /dev/null +++ b/force-app/main/default/staticresources/leafletjs.resource-meta.xml @@ -0,0 +1,6 @@ + + + Private + application/zip + JS library that renders maps + diff --git a/force-app/main/default/staticresources/leafletjs/images/layers-2x.png b/force-app/main/default/staticresources/leafletjs/images/layers-2x.png new file mode 100644 index 0000000..200c333 Binary files /dev/null and b/force-app/main/default/staticresources/leafletjs/images/layers-2x.png differ diff --git a/force-app/main/default/staticresources/leafletjs/images/layers.png b/force-app/main/default/staticresources/leafletjs/images/layers.png new file mode 100644 index 0000000..1a72e57 Binary files /dev/null and b/force-app/main/default/staticresources/leafletjs/images/layers.png differ diff --git a/force-app/main/default/staticresources/leafletjs/images/marker-icon-2x.png b/force-app/main/default/staticresources/leafletjs/images/marker-icon-2x.png new file mode 100644 index 0000000..88f9e50 Binary files /dev/null and b/force-app/main/default/staticresources/leafletjs/images/marker-icon-2x.png differ diff --git a/force-app/main/default/staticresources/leafletjs/images/marker-icon.png b/force-app/main/default/staticresources/leafletjs/images/marker-icon.png new file mode 100644 index 0000000..950edf2 Binary files /dev/null and b/force-app/main/default/staticresources/leafletjs/images/marker-icon.png differ diff --git a/force-app/main/default/staticresources/leafletjs/images/marker-shadow.png b/force-app/main/default/staticresources/leafletjs/images/marker-shadow.png new file mode 100644 index 0000000..9fd2979 Binary files /dev/null and b/force-app/main/default/staticresources/leafletjs/images/marker-shadow.png differ diff --git a/force-app/main/default/staticresources/leafletjs/leaflet.css b/force-app/main/default/staticresources/leafletjs/leaflet.css new file mode 100644 index 0000000..2961b76 --- /dev/null +++ b/force-app/main/default/staticresources/leafletjs/leaflet.css @@ -0,0 +1,661 @@ +/* required styles */ + +.leaflet-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Prevents IE11 from highlighting tiles in blue */ +.leaflet-tile::selection { + background: transparent; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg { + max-width: none !important; + max-height: none !important; + } +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer, +.leaflet-container .leaflet-tile { + max-width: none !important; + max-height: none !important; + width: auto; + padding: 0; + } + +.leaflet-container img.leaflet-tile { + /* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */ + mix-blend-mode: plus-lighter; +} + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + } +svg.leaflet-zoom-animated { + will-change: transform; +} + +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; + } +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive, +svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline-offset: 1px; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; + font-size: 12px; + font-size: 0.75rem; + line-height: 1.5; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover, +.leaflet-bar a:focus { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(images/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(images/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + font-size: 13px; + font-size: 1.08333em; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +/* Default icon URLs */ +.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ + background-image: url(images/marker-icon.png); + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.8); + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + line-height: 1.4; + } +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover, +.leaflet-control-attribution a:focus { + text-decoration: underline; + } +.leaflet-attribution-flag { + display: inline !important; + vertical-align: baseline !important; + width: 1em; + height: 0.6669em; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + white-space: nowrap; + -moz-box-sizing: border-box; + box-sizing: border-box; + background: rgba(255, 255, 255, 0.8); + text-shadow: 1px 1px #fff; + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 24px 13px 20px; + line-height: 1.3; + font-size: 13px; + font-size: 1.08333em; + min-height: 1px; + } +.leaflet-popup-content p { + margin: 17px 0; + margin: 1.3em 0; + } +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-top: -1px; + margin-left: -20px; + overflow: hidden; + pointer-events: none; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + pointer-events: auto; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + border: none; + text-align: center; + width: 24px; + height: 24px; + font: 16px/24px Tahoma, Verdana, sans-serif; + color: #757575; + text-decoration: none; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover, +.leaflet-container a.leaflet-popup-close-button:focus { + color: #585858; + } +.leaflet-popup-scrolled { + overflow: auto; + } + +.leaflet-oldie .leaflet-popup-content-wrapper { + -ms-zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + } + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + } +.leaflet-tooltip.leaflet-interactive { + cursor: pointer; + pointer-events: auto; + } +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; + } + +/* Printing */ + +@media print { + /* Prevent printers from removing background-images of controls. */ + .leaflet-control { + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } + } diff --git a/force-app/main/default/staticresources/leafletjs/leaflet.js b/force-app/main/default/staticresources/leafletjs/leaflet.js new file mode 100644 index 0000000..a3bf693 --- /dev/null +++ b/force-app/main/default/staticresources/leafletjs/leaflet.js @@ -0,0 +1,6 @@ +/* @preserve + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).leaflet={})}(this,function(t){"use strict";function l(t){for(var e,i,n=1,o=arguments.length;n=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.xe.y&&n.y=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.late.lng&&n.lng","http://www.w3.org/2000/svg"===(Wt.firstChild&&Wt.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Wt,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Ft=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Ft,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Ft,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=F(e),o=0,s=n.length;othis.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!We(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;sthis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,i.noMoveStart||!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){if(!this._preventClick){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;se.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section,e=(this._preventClick=!0,S(t,"click",O),this.expand(),this);setTimeout(function(){k(t,"click",O),e._preventClick=!1})}})),qe=B.extend({options:{position:"topleft",zoomInText:'',zoomInTitle:"Zoom in",zoomOutText:'',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ge=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new qe,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280'+(b.inlineSvg?' ':"")+"Leaflet"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ke).addTo(this)}),B.Layers=Ve,B.Zoom=qe,B.Scale=Ge,B.Attribution=Ke,Ue.layers=function(t,e,i){return new Ve(t,e,i)},Ue.zoom=function(t){return new qe(t)},Ue.scale=function(t){return new Ge(t)},Ue.attribution=function(t){return new Ke(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Ye=b.touch?"touchstart mousedown":"mousedown",Xe=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Xe._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Xe._dragging===this&&this.finishDrag():Xe._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Xe._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1e&&(i.push(t[n]),o=n);oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i}function ri(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||yi.prototype._containsPoint.call(this,t,!0)}});var wi=ci.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;es.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Ii=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Bi,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ci||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof fi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Ai.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Ai.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Ai.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Ai.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Di=Ni.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Wi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Vi("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Vi("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Vi("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Vi("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},qi=b.vml?Vi:ct,Gi=Wi.extend({_initContainer:function(){this._container=qi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=qi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Wi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=qi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Ki(t){return b.svg||b.vml?new Gi(t):null}b.vml&&Gi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Ui(t)||Ki(t)}});var Yi=xi.extend({initialize:function(t,e){xi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Gi.create=qi,Gi.pointsToPath=dt,wi.geometryToLayer=bi,wi.coordsToLatLng=Li,wi.coordsToLatLngs=Ti,wi.latLngToCoords=Mi,wi.latLngsToCoords=zi,wi.getFeature=Ci,wi.asFeature=Zi,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Xe(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)e.getMaxZoom()&&1 + + Private + application/json + Sample data used to initialize Broker__c records + diff --git a/force-app/main/default/staticresources/sample_data_contacts.json b/force-app/main/default/staticresources/sample_data_contacts.json new file mode 100644 index 0000000..79e47c2 --- /dev/null +++ b/force-app/main/default/staticresources/sample_data_contacts.json @@ -0,0 +1,32 @@ +[ + { + "FirstName": "Brad", + "LastName": "Holmes", + "Phone": "617-555-0143", + "Email": "bholmes@goodmail.com" + }, + { + "FirstName": "Leslie", + "LastName": "Martin", + "Phone": "617-555-0112", + "Email": "leslie@pentagon.com" + }, + { + "FirstName": "July", + "LastName": "Walker", + "Phone": "617-555-0170", + "Email": "julywalker@brain.com" + }, + { + "FirstName": "Anna", + "LastName": "Jones", + "Phone": "617-555-0181", + "Email": "annaj@mymail.com" + }, + { + "FirstName": "John", + "LastName": "Connor", + "Phone": "617-555-0133", + "Email": "jconnor@goodmail.com" + } +] \ No newline at end of file diff --git a/force-app/main/default/staticresources/sample_data_contacts.resource-meta.xml b/force-app/main/default/staticresources/sample_data_contacts.resource-meta.xml new file mode 100644 index 0000000..1e39c0a --- /dev/null +++ b/force-app/main/default/staticresources/sample_data_contacts.resource-meta.xml @@ -0,0 +1,6 @@ + + + Private + application/json + Sample data used to initialize Contact records + diff --git a/force-app/main/default/staticresources/sample_data_properties.json b/force-app/main/default/staticresources/sample_data_properties.json new file mode 100644 index 0000000..e8108b1 --- /dev/null +++ b/force-app/main/default/staticresources/sample_data_properties.json @@ -0,0 +1,242 @@ +[ + { + "Name": "Stunning Victorian", + "Hutte__Address__c": "18 Henry St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "01742", + "Hutte__Price__c": 975000, + "Hutte__Beds__c": 4, + "Hutte__Baths__c": 3, + "Hutte__Location__Longitude__s": -71.11095, + "Hutte__Location__Latitude__s": 42.35663, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house01.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house01sq.jpg", + "Hutte__Tags__c": "victorian", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 1 + }, + "Hutte__Status__c": "Available" + }, + { + "Name": "Ultimate Sophistication", + "Hutte__Address__c": "24 Pearl St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 1200000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.10869, + "Hutte__Location__Latitude__s": 42.359103, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house02.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house02sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 2 + }, + "Hutte__Status__c": "Contracted" + }, + { + "Name": "Modern City Living", + "Hutte__Address__c": "72 Francis St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 825000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.106827, + "Hutte__Location__Latitude__s": 42.335435, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house03.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house03sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 3 + }, + "Hutte__Status__c": "Pre Market" + }, + { + "Name": "Stunning Colonial", + "Hutte__Address__c": "32 Prince St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 930000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.110448, + "Hutte__Location__Latitude__s": 42.360642, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house04.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house04sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 4 + }, + "Hutte__Status__c": "Available" + }, + { + "Name": "Waterfront in the City", + "Hutte__Address__c": "110 Baxter Street", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 850000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 2, + "Hutte__Location__Longitude__s": -71.084454, + "Hutte__Location__Latitude__s": 42.368168, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house05.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house05sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 5 + }, + "Hutte__Status__c": "Closed" + }, + { + "Name": "Quiet Retreat", + "Hutte__Address__c": "448 Hanover St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 725000, + "Hutte__Beds__c": 4, + "Hutte__Baths__c": 2, + "Hutte__Location__Longitude__s": -71.052617, + "Hutte__Location__Latitude__s": 42.366855, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house06.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house06sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 6 + }, + "Hutte__Status__c": "Contracted" + }, + { + "Name": "City Living", + "Hutte__Address__c": "127 Endicott St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 450000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 1, + "Hutte__Location__Longitude__s": -71.057352, + "Hutte__Location__Latitude__s": 42.365003, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house07.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house07sq.jpg", + "Hutte__Tags__c": "colonial", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 7 + }, + "Hutte__Status__c": "Available" + }, + { + "Name": "Heart of Harvard Square", + "Hutte__Address__c": "48 Brattle St", + "Hutte__City__c": "Cambridge", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 450000, + "Hutte__Beds__c": 5, + "Hutte__Baths__c": 4, + "Hutte__Location__Longitude__s": -71.121653, + "Hutte__Location__Latitude__s": 42.374117, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house10.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house10sq.jpg", + "Hutte__Tags__c": "victorian", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 8 + }, + "Hutte__Status__c": "Under Agreement" + }, + { + "Name": "Seaport District Retreat", + "Hutte__Address__c": "121 Harborwalk", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 450000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 3, + "Hutte__Location__Longitude__s": -71.049327, + "Hutte__Location__Latitude__s": 42.35695, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house09.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house09sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 1 + }, + "Hutte__Status__c": "Available" + }, + { + "Name": "Contemporary City Living", + "Hutte__Address__c": "640 Harrison Ave", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 650000, + "Hutte__Beds__c": 2, + "Hutte__Baths__c": 2, + "Hutte__Location__Longitude__s": -71.068781, + "Hutte__Location__Latitude__s": 42.339892, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house08.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house08sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 2 + }, + "Hutte__Status__c": "Available" + }, + { + "Name": "Architectural Details", + "Hutte__Address__c": "95 Gloucester St", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 690000, + "Hutte__Beds__c": 3, + "Hutte__Baths__c": 3, + "Hutte__Location__Latitude__s": 42.349693, + "Hutte__Location__Longitude__s": -71.084407, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house11.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house11sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 3 + }, + "Hutte__Status__c": "Available" + }, + { + "Name": "Contemporary Luxury", + "Hutte__Address__c": "145 Commonwealth Ave", + "Hutte__City__c": "Boston", + "Hutte__State__c": "MA", + "Hutte__Zip__c": "02420", + "Hutte__Price__c": 845000, + "Hutte__Beds__c": 4, + "Hutte__Baths__c": 3, + "Hutte__Location__Latitude__s": 42.352466, + "Hutte__Location__Longitude__s": -71.075311, + "Hutte__Picture__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house12.jpg", + "Hutte__Thumbnail__c": "https://s3-us-west-2.amazonaws.com/dev-or-devrl-s3-bucket/sample-apps/realty/house12sq.jpg", + "Hutte__Tags__c": "contemporary", + "Hutte__Description__c": "Lorem ipsum dolor sit amet", + "Hutte__Broker__r": { + "Hutte__Broker_Id__c": 4 + }, + "Hutte__Status__c": "Available" + } +] \ No newline at end of file diff --git a/force-app/main/default/staticresources/sample_data_properties.resource-meta.xml b/force-app/main/default/staticresources/sample_data_properties.resource-meta.xml new file mode 100644 index 0000000..ba43675 --- /dev/null +++ b/force-app/main/default/staticresources/sample_data_properties.resource-meta.xml @@ -0,0 +1,6 @@ + + + Private + application/json + Sample data used to initialize Property__c records + diff --git a/force-app/main/default/tabs/Broker__c.tab-meta.xml b/force-app/main/default/tabs/Broker__c.tab-meta.xml new file mode 100644 index 0000000..cad40e6 --- /dev/null +++ b/force-app/main/default/tabs/Broker__c.tab-meta.xml @@ -0,0 +1,5 @@ + + + true + Custom15: People + diff --git a/force-app/main/default/tabs/Property_Explorer.tab-meta.xml b/force-app/main/default/tabs/Property_Explorer.tab-meta.xml new file mode 100644 index 0000000..cf77167 --- /dev/null +++ b/force-app/main/default/tabs/Property_Explorer.tab-meta.xml @@ -0,0 +1,7 @@ + + + Created by Lightning App Builder + Property_Explorer + + Custom39: Telescope + diff --git a/force-app/main/default/tabs/Property_Finder.tab-meta.xml b/force-app/main/default/tabs/Property_Finder.tab-meta.xml new file mode 100644 index 0000000..41e5369 --- /dev/null +++ b/force-app/main/default/tabs/Property_Finder.tab-meta.xml @@ -0,0 +1,7 @@ + + + Created by Lightning App Builder + Property_Finder + + Custom78: Map + diff --git a/force-app/main/default/tabs/Property__c.tab-meta.xml b/force-app/main/default/tabs/Property__c.tab-meta.xml new file mode 100644 index 0000000..e9a3cf4 --- /dev/null +++ b/force-app/main/default/tabs/Property__c.tab-meta.xml @@ -0,0 +1,5 @@ + + + true + Custom85: Real Estate Sign + diff --git a/force-app/main/default/tabs/Settings.tab-meta.xml b/force-app/main/default/tabs/Settings.tab-meta.xml new file mode 100644 index 0000000..87d437c --- /dev/null +++ b/force-app/main/default/tabs/Settings.tab-meta.xml @@ -0,0 +1,7 @@ + + + Created by Lightning App Builder + Settings + + Custom19: Wrench + diff --git a/force-app/test/jest-mocks/apex.js b/force-app/test/jest-mocks/apex.js new file mode 100644 index 0000000..a7c2fb9 --- /dev/null +++ b/force-app/test/jest-mocks/apex.js @@ -0,0 +1 @@ +export const refreshApex = jest.fn(() => Promise.resolve()); diff --git a/force-app/test/jest-mocks/global/navigator.js b/force-app/test/jest-mocks/global/navigator.js new file mode 100644 index 0000000..b2989fa --- /dev/null +++ b/force-app/test/jest-mocks/global/navigator.js @@ -0,0 +1,15 @@ +// Mock browser geolocation service this way: +// import { mockGeolocation } from '../../../../../test/jest-mocks/global/navigator'; +// navigator.geolocation = mockGeolocation; +export const mockGeolocation = { + getCurrentPosition: jest.fn().mockImplementation((success) => + Promise.resolve( + success({ + coords: { + latitude: 42.361145, + longitude: -71.057083 + } + }) + ) + ) +}; diff --git a/force-app/test/jest-mocks/lightning/mediaUtils.js b/force-app/test/jest-mocks/lightning/mediaUtils.js new file mode 100644 index 0000000..cef4085 --- /dev/null +++ b/force-app/test/jest-mocks/lightning/mediaUtils.js @@ -0,0 +1 @@ +export const processImage = jest.fn(() => Promise.resolve(new Blob())); diff --git a/force-app/test/jest-mocks/lightning/messageService.js b/force-app/test/jest-mocks/lightning/messageService.js new file mode 100644 index 0000000..501a4d7 --- /dev/null +++ b/force-app/test/jest-mocks/lightning/messageService.js @@ -0,0 +1,25 @@ +/** + * For the original lightning/messageService (LMS) stub that comes by default with + * @salesforce/sfdx-lwc-jest, see: + * https://github.com/salesforce/sfdx-lwc-jest/blob/master/src/lightning-stubs/messageService/messageService.js + */ +export const APPLICATION_SCOPE = Symbol('APPLICATION_SCOPE'); +export const createMessageChannel = jest.fn(); +export const createMessageContext = jest.fn(); +export const MessageContext = jest.fn(); +export const releaseMessageContext = jest.fn(); +export const unsubscribe = jest.fn(); +// LMS stub implementation that lets you test a single message handler on a single channel +var _messageChannel = null; +var _messageHandler = null; +export const publish = jest.fn((messageContext, messageChannel, message) => { + if (_messageHandler && _messageChannel === messageChannel) { + _messageHandler(message); + } +}); +export const subscribe = jest.fn( + (messageContext, messageChannel, messageHandler) => { + _messageChannel = messageChannel; + _messageHandler = messageHandler; + } +); diff --git a/force-app/test/jest-mocks/lightning/mobileCapabilities.js b/force-app/test/jest-mocks/lightning/mobileCapabilities.js new file mode 100644 index 0000000..79d1a4a --- /dev/null +++ b/force-app/test/jest-mocks/lightning/mobileCapabilities.js @@ -0,0 +1,91 @@ +// ~~~~~ MOCK getLocationService ~~~~~ + +// To stub getLocationService.isAvailable(), add the following to your test: +// import { setDeviceLocationServiceAvailable } from 'lightning/mobileCapabilities'; +// setDeviceLocationServiceAvailable(true); + +let _deviceLocationServiceAvailable = false; + +export const getLocationService = jest.fn().mockImplementation(() => { + return { + isAvailable: jest.fn().mockReturnValue(_deviceLocationServiceAvailable), + getCurrentPosition: jest.fn().mockImplementation(() => + Promise.resolve({ + coords: { + latitude: 42.361145, + longitude: -71.057083 + } + }) + ) + }; +}); + +export const setDeviceLocationServiceAvailable = (value = true) => { + _deviceLocationServiceAvailable = value; +}; + +// ~~~~~ MOCK getBarcodeScanner ~~~~~ + +// To stub getBarcodeScanner.isAvailable(), add the following to your test: +// import { setBarcodeScannerAvailable } from 'lightning/mobileCapabilities'; +// setBarcodeScannerAvailable(true); + +// Mock getBarcodeScanner stubs that can be altered from within test files +let _barcodeScannerAvailable = false; +let _userCanceledScan = false; +let _scanThrewAnError = false; + +// Reset all BarcodeScanner stubs to false +export const resetBarcodeScannerStubs = () => { + _barcodeScannerAvailable = false; + _userCanceledScan = false; + _scanThrewAnError = false; +}; + +// Enables us to stub getBarcodeScanner.isAvailable() to a desired value (or true) from within the component test +export const setBarcodeScannerAvailable = (value = true) => { + _barcodeScannerAvailable = value; +}; + +// Enables us to mock user canceling (or not canceling) a scan from within the component test +export const setUserCanceledScan = (value = true) => { + _userCanceledScan = value; +}; + +// Enables us to mock there being an error (or not) from within the component test +export const setBarcodeScanError = (value = true) => { + _scanThrewAnError = value; +}; + +// Jest mock getBarcodeScanner that returns expected values/"functionality" for all methods and properties accessed in barcodeScanner.js +export const getBarcodeScanner = jest.fn().mockImplementation(() => { + return { + isAvailable: jest.fn().mockReturnValue(_barcodeScannerAvailable), + barcodeTypes: jest + .fn() + .mockReturnValue({ QR: _barcodeScannerAvailable }), + beginCapture: jest.fn().mockImplementation(() => { + // NB: Simultaneously initialising & throwing an Error (e.g. `throw new Error`) will exclude options + // See https://rollbar.com/guides/javascript/how-to-throw-exceptions-in-javascript + + let error; + + if (_userCanceledScan) { + error = new Error('User canceled scan'); + error.code = 'userDismissedScanner'; + } + + // ELSE if instead of plain IF to ensure only one error type is assigned + else if (_scanThrewAnError) { + error = new Error('There was a problem scanning the code'); + error.code = 'unknownReason'; + } + + if (error) throw error; + + // Return scan result + return Promise.resolve({ value: '0031700000pJRRWAA4' }); + }), + endCapture: jest.fn().mockReturnValue(_barcodeScannerAvailable) + }; +}); diff --git a/force-app/test/jest-mocks/lightning/navigation.js b/force-app/test/jest-mocks/lightning/navigation.js new file mode 100644 index 0000000..9aad987 --- /dev/null +++ b/force-app/test/jest-mocks/lightning/navigation.js @@ -0,0 +1,41 @@ +/** + * For the original lightning/navigation mock that comes by default with + * @salesforce/sfdx-lwc-jest, see: + * https://github.com/salesforce/sfdx-lwc-jest/blob/master/src/lightning-stubs/navigation/navigation.js + */ +export const CurrentPageReference = jest.fn(); + +let _navigatePageReference, _generatePageReference, _replace; + +const Navigate = Symbol('Navigate'); +const GenerateUrl = Symbol('GenerateUrl'); +export const NavigationMixin = (Base) => { + return class extends Base { + [Navigate](pageReference, replace) { + _navigatePageReference = pageReference; + _replace = replace; + } + [GenerateUrl](pageReference) { + _generatePageReference = pageReference; + return new Promise((resolve) => resolve('https://www.example.com')); + } + }; +}; +NavigationMixin.Navigate = Navigate; +NavigationMixin.GenerateUrl = GenerateUrl; + +/* + * Tests do not have access to the internals of this mixin used by the + * component under test so save a reference to the arguments the Navigate method is + * invoked with and provide access with this function. + */ +export const getNavigateCalledWith = () => { + return { + pageReference: _navigatePageReference, + replace: _replace + }; +}; + +export const getGenerateUrlCalledWith = () => ({ + pageReference: _generatePageReference +}); diff --git a/force-app/test/jest-mocks/lightning/platformShowToastEvent.js b/force-app/test/jest-mocks/lightning/platformShowToastEvent.js new file mode 100644 index 0000000..cb500b7 --- /dev/null +++ b/force-app/test/jest-mocks/lightning/platformShowToastEvent.js @@ -0,0 +1,18 @@ +/** + * For the original lightning/platformShowToastEvent mock that comes by default with + * @salesforce/sfdx-lwc-jest, see: + * https://github.com/salesforce/sfdx-lwc-jest/blob/master/src/lightning-stubs/platformShowToastEvent/platformShowToastEvent.js + */ + +export const ShowToastEventName = 'lightning__showtoast'; + +export class ShowToastEvent extends CustomEvent { + constructor(toast) { + super(ShowToastEventName, { + composed: true, + cancelable: true, + bubbles: true, + detail: toast + }); + } +} diff --git a/force-app/test/jest-mocks/schema.js b/force-app/test/jest-mocks/schema.js new file mode 100644 index 0000000..7152632 --- /dev/null +++ b/force-app/test/jest-mocks/schema.js @@ -0,0 +1,5 @@ +export const Property__c = { + objectApiName: 'Property__c', + Date_Listed__c: { fieldApiName: 'Date_Listed__c' }, + Days_On_Market__c: { fieldApiName: 'Days_On_Market__c' } +}; diff --git a/hutte.yml b/hutte.yml new file mode 100644 index 0000000..515ce1f --- /dev/null +++ b/hutte.yml @@ -0,0 +1,21 @@ +version: '1.0' + +# Shell script to run when pushing the source code to the scratch orgs. +# It's a great place to automate tasks like permission set assignments or data loading. +push_script: | + set -euo pipefail # fail fast + sf project deploy start --wait 60 --ignore-conflicts + sf org assign permset --name dreamhouse + sf data tree import -p data/sample-data-plan.json +custom_scripts: + # This scripts will be displayed on the scratch org's page + scratch_org: + 'Export Data': + description: 'Export data using SFDMU' + run: | + set -euo pipefail # fail fast + echo y | sf plugins install sfdmu + sf sfdmu run -p data/sfdmu -s "${SALESFORCE_USERNAME}" -u csvfile --filelog 0 -n + git add data + git commit -m "modified data" + git push origin "${HUTTE_GIT_SOURCE_BRANCH}" diff --git a/package.json b/package.json new file mode 100644 index 0000000..3fa866c --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "salesforce-app", + "private": true, + "version": "1.0.0", + "description": "Salesforce App", + "scripts": { + "lint": "eslint **/{aura,lwc}/**", + "test": "npm run test:unit", + "test:unit": "sfdx-lwc-jest", + "test:unit:watch": "sfdx-lwc-jest --watch", + "test:unit:debug": "sfdx-lwc-jest --debug", + "test:unit:coverage": "sfdx-lwc-jest --coverage", + "prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"", + "prettier:verify": "prettier --list-different \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"", + "postinstall": "husky install", + "precommit": "lint-staged" + }, + "devDependencies": { + "@lwc/eslint-plugin-lwc": "^1.1.2", + "@prettier/plugin-xml": "^3.2.2", + "@salesforce/eslint-config-lwc": "^3.2.3", + "@salesforce/eslint-plugin-aura": "^2.0.0", + "@salesforce/eslint-plugin-lightning": "^1.0.0", + "@salesforce/sfdx-lwc-jest": "^1.1.0", + "eslint": "^8.11.0", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-jest": "^26.1.2", + "husky": "^8.0.3", + "lint-staged": "^12.3.7", + "prettier": "^3.1.0", + "prettier-plugin-apex": "^2.0.1" + }, + "lint-staged": { + "**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}": [ + "prettier --write" + ], + "**/{aura,lwc}/**": [ + "eslint" + ] + } +} diff --git a/release.config.mjs b/release.config.mjs new file mode 100644 index 0000000..1864f48 --- /dev/null +++ b/release.config.mjs @@ -0,0 +1,29 @@ +import { readFileSync } from 'node:fs'; + +const packageName = JSON.parse(readFileSync('sfdx-project.json', 'utf8')).packageDirectories.find( + (packageDirectory) => packageDirectory.default +).package; + +/** + * @type {import('semantic-release').GlobalConfig} + */ +export default { + plugins: [ + '@semantic-release/commit-analyzer', + '@semantic-release/release-notes-generator', + [ + '@semantic-release/exec', + { + shell: '/bin/bash', + // create package version for default package directory + publishCmd: `sf package version create --package "${packageName}" --version-number "\${nextRelease.version}.NEXT" --installation-key-bypass --code-coverage --wait 30 --json`, + // output package version id for GitHub Actions + // promote package version + successCmd: `echo "packageVersionId=\${releases[0].result.SubscriberPackageVersionId}" >> "\${process.env.GITHUB_OUTPUT}"; + echo "version=\${releases[0].result.VersionNumber}" >> "\${process.env.GITHUB_OUTPUT}"; + sf package version promote --package "\${releases[0].result.SubscriberPackageVersionId}" --no-prompt --json` + } + ], + '@semantic-release/github' + ] +}; diff --git a/scripts/addnamespaceToData.sh b/scripts/addnamespaceToData.sh new file mode 100755 index 0000000..aadd0a2 --- /dev/null +++ b/scripts/addnamespaceToData.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Directory containing JSON files +DATA_DIR="data" + +# Define the namespace prefix +NAMESPACE="Hutte__" + +# Function to process JSON files +process_json_files() { + echo "Looking for JSON files in $DATA_DIR" + + # List files in the data directory for debugging + ls -l "$DATA_DIR" + + for file in "$DATA_DIR"/*.json; do + # Check if the file exists + if [[ -f $file ]]; then + echo "Processing $file" + + # Use jq to transform the JSON + jq 'walk( + if type == "object" then + with_entries( + if (.key | test("__c$|__s$")) then + .key |= "Hutte__" + . + elif (.value | type == "string" and test("__c$|__s$")) then + .value |= "Hutte__" + . + else + . + end + ) + elif type == "array" then + map( + if type == "string" and test("__c$|__s$") then + "Hutte__" + . + else + . + end + ) + else + . + end + )' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" + else + echo "No JSON files found in $DATA_DIR" + fi + done +} + +# Call the function to process JSON files +process_json_files + +echo "Processing complete." diff --git a/scripts/addnamespaceToLWC.sh b/scripts/addnamespaceToLWC.sh new file mode 100755 index 0000000..368d583 --- /dev/null +++ b/scripts/addnamespaceToLWC.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Define the namespace prefix +NAMESPACE="Hutte__" + +# Define the directory containing the LWC files +LWC_DIR="force-app/main/default/lwc" + +# Find all .js, .html, and .js-meta.xml files in the LWC directory and iterate through them +find "$LWC_DIR" -type f \( -name "*.js" -o -name "*.html" -o -name "*.js-meta.xml" \) | while read -r FILE; do + # Use sed to add the namespace prefix to words ending with __c or __s + sed -i.bak -E "s/([a-zA-Z0-9_]+\.)?([a-zA-Z0-9_]+)(__[cs])/\1$NAMESPACE\2\3/g" "$FILE" + # Remove the backup file created by sed (optional) + rm "${FILE}.bak" + echo "Processed: $FILE" +done + +echo "Namespace prefixing completed." diff --git a/scripts/apex/hello.apex b/scripts/apex/hello.apex new file mode 100644 index 0000000..47121d5 --- /dev/null +++ b/scripts/apex/hello.apex @@ -0,0 +1,10 @@ +// Use .apex files to store anonymous Apex. +// You can execute anonymous Apex in VS Code by selecting the +// apex text and running the command: +// SFDX: Execute Anonymous Apex with Currently Selected Text +// You can also execute the entire file by running the command: +// SFDX: Execute Anonymous Apex with Editor Contents + +string tempvar = 'Enter_your_name_here'; +System.debug('Hello World!'); +System.debug('My name is ' + tempvar); diff --git a/scripts/soql/account.soql b/scripts/soql/account.soql new file mode 100644 index 0000000..10d4b9c --- /dev/null +++ b/scripts/soql/account.soql @@ -0,0 +1,6 @@ +// Use .soql files to store SOQL queries. +// You can execute queries in VS Code by selecting the +// query text and running the command: +// SFDX: Execute SOQL Query with Currently Selected Text + +SELECT Id, Name FROM Account diff --git a/sfdx-project.json b/sfdx-project.json new file mode 100644 index 0000000..7c9780d --- /dev/null +++ b/sfdx-project.json @@ -0,0 +1,19 @@ +{ + "packageDirectories": [ + { + "versionNumber": "0.0.0.NEXT", + "path": "force-app", + "default": false, + "package": "Dreamhut", + "versionDescription": "A second generation managed package based on the Salesforce Dreamhouse sample app", + "ancestorVersion": "HIGHEST" + } + ], + "name": "Dreamhut", + "namespace": "Hutte", + "sfdcLoginUrl": "https://login.salesforce.com", + "sourceApiVersion": "61.0", + "packageAliases": { + "Dreamhut": "0HoS7000000015lKAA" + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..04f6e82 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4715 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.21.4", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.4.tgz#03ae5af150be94392cb5c7ccd97db5a19a5da6aa" + integrity sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.9": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.3.tgz#3febd552541e62b5e883a25eb3effd7c7379db11" + integrity sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ== + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.21.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.3.tgz#5ec09c8803b91f51cc887dedc2654a35852849c9" + integrity sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.3" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.23.2" + "@babel/parser" "^7.23.3" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.3" + "@babel/types" "^7.23.3" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/core@~7.21.0": + version "7.21.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.8.tgz#2a8c7f0f53d60100ba4c32470ba0281c92aa9aa4" + integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.5" + "@babel/helper-compilation-targets" "^7.21.5" + "@babel/helper-module-transforms" "^7.21.5" + "@babel/helpers" "^7.21.5" + "@babel/parser" "^7.21.8" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.21.5" + "@babel/types" "^7.21.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/core@~7.22.8": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.20.tgz#e3d0eed84c049e2a2ae0a64d27b6a37edec385b7" + integrity sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.22.20" + "@babel/helpers" "^7.22.15" + "@babel/parser" "^7.22.16" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.22.20" + "@babel/types" "^7.22.19" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/eslint-parser@~7.22.7": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.22.15.tgz#263f059c476e29ca4972481a17b8b660cb025a34" + integrity sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg== + dependencies: + "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" + eslint-visitor-keys "^2.1.0" + semver "^6.3.1" + +"@babel/generator@^7.21.5", "@babel/generator@^7.22.15", "@babel/generator@^7.23.3", "@babel/generator@^7.23.4", "@babel/generator@^7.7.2": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.4.tgz#4a41377d8566ec18f807f42962a7f3551de83d1c" + integrity sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ== + dependencies: + "@babel/types" "^7.23.4" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.21.5", "@babel/helper-compilation-targets@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" + integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.15" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz#97a61b385e57fe458496fad19f8e63b63c867de4" + integrity sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.15" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20", "@babel/helper-environment-visitor@^7.22.5": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.22.5", "@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.22.15": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz#9263e88cc5e41d39ec18c9a3e0eced59a3e7d366" + integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== + dependencies: + "@babel/types" "^7.23.0" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-imports@~7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.21.5", "@babel/helper-module-transforms@^7.22.20", "@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-replace-supers@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" + integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-member-expression-to-functions" "^7.22.15" + "@babel/helper-optimise-call-expression" "^7.22.5" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" + integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== + +"@babel/helpers@^7.21.5", "@babel/helpers@^7.22.15", "@babel/helpers@^7.23.2": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.4.tgz#7d2cfb969aa43222032193accd7329851facf3c1" + integrity sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.4" + "@babel/types" "^7.23.4" + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8", "@babel/parser@^7.22.15", "@babel/parser@^7.22.16", "@babel/parser@^7.23.3", "@babel/parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.4.tgz#409fbe690c333bb70187e2de4021e1e47a026661" + integrity sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ== + +"@babel/plugin-proposal-class-properties@~7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-object-rest-spread@~7.20.2": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" + integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== + dependencies: + "@babel/compat-data" "^7.20.5" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.20.7" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-decorators@^7.21.0": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.23.3.tgz#a1d351d6c25bfdcf2e16f99b039101bc0ffcb0ca" + integrity sha512-cf7Niq4/+/juY67E0PbgH0TDhLQ5J7zS8C/Q5FFx+DWyrRa9sUQdTXkjqKu8zGvuqr7vw1muKiukseihU+PJDA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" + integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.23.3", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" + integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-commonjs@^7.21.2", "@babel/plugin-transform-modules-commonjs@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz#661ae831b9577e52be57dd8356b734f9700b53b4" + integrity sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA== + dependencies: + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-parameters@^7.20.7": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz#83ef5d1baf4b1072fa6e54b2b0999a7b2527e2af" + integrity sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typescript@^7.23.3": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.4.tgz#da12914d17b3c4b307f32c5fd91fbfdf17d56f86" + integrity sha512-39hCCOl+YUAyMOu6B9SmUTiHUU0t/CxJNUmY3qRdJujbqi+lrQcL11ysYUsAvFWPBdhihrv1z0oRG84Yr3dODQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.15" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-typescript" "^7.23.3" + +"@babel/preset-typescript@^7.21.0": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz#14534b34ed5b6d435aa05f1ae1c5e7adcc01d913" + integrity sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.15" + "@babel/plugin-syntax-jsx" "^7.23.3" + "@babel/plugin-transform-modules-commonjs" "^7.23.3" + "@babel/plugin-transform-typescript" "^7.23.3" + +"@babel/template@^7.20.7", "@babel/template@^7.22.15", "@babel/template@^7.3.3": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.21.5", "@babel/traverse@^7.22.20", "@babel/traverse@^7.23.3", "@babel/traverse@^7.23.4", "@babel/traverse@^7.7.2": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.4.tgz#c2790f7edf106d059a0098770fe70801417f3f85" + integrity sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg== + dependencies: + "@babel/code-frame" "^7.23.4" + "@babel/generator" "^7.23.4" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.4" + "@babel/types" "^7.23.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.5", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3", "@babel/types@^7.23.4", "@babel/types@^7.3.3": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.4.tgz#7206a1810fc512a7f7f7d4dace4cb4c1c9dbfb8e" + integrity sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d" + integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.54.0.tgz#4fab9a2ff7860082c304f750e94acd644cf984cf" + integrity sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ== + +"@hapi/hoek@^9.0.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/topo@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== + dependencies: + "@humanwhocodes/object-schema" "^2.0.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + +"@jest/core@^27.4.7", "@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== + dependencies: + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + +"@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.9" + source-map "^0.6.0" + +"@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== + dependencies: + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== + dependencies: + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" + +"@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.5.1" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@lwc/babel-plugin-component@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/babel-plugin-component/-/babel-plugin-component-2.42.0.tgz#f3c9f83baf0ebf1ae2d71246512a3af46f2e114a" + integrity sha512-JqMM7vxKCUypgxnjxizfSFmm1hPRw8blFIyY1sxiBSrwXhZXTHxtstLRCZkATRsG4dAjj4wQ7SrNRhd7oQXD9Q== + dependencies: + "@babel/helper-module-imports" "~7.18.6" + "@lwc/errors" "2.42.0" + "@lwc/shared" "2.42.0" + line-column "~1.0.2" + +"@lwc/compiler@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/compiler/-/compiler-2.42.0.tgz#f6402f333f3a169dd740f443844a8722c27d5d08" + integrity sha512-0NJFUAFVp4I/TI4GHvSwS86tyv7GuduxHLVsZ0Q42rAdvJmbMBvD8jIlCflhHLgzT0ePSD6pkoq9aKjks03RnQ== + dependencies: + "@babel/core" "~7.21.0" + "@babel/plugin-proposal-class-properties" "~7.18.6" + "@babel/plugin-proposal-object-rest-spread" "~7.20.2" + "@lwc/babel-plugin-component" "2.42.0" + "@lwc/errors" "2.42.0" + "@lwc/shared" "2.42.0" + "@lwc/style-compiler" "2.42.0" + "@lwc/template-compiler" "2.42.0" + +"@lwc/engine-dom@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/engine-dom/-/engine-dom-2.42.0.tgz#91baf6c41cdd55d5a9eccf699317795f7e909ac9" + integrity sha512-yLo+C8MsLfDPrpAiHN8ktdVi2we2z1fryfXNYu9TMIaXwro/Bdw8PMzpIz5Q0E19KruGaAmixAzaLxymhwj2gQ== + +"@lwc/errors@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/errors/-/errors-2.42.0.tgz#91179812ff50d566334a1ae65e0c580d85febb42" + integrity sha512-byCYjSXoV8B3s9d+rPwpQwGZ2y4u6Gh+QJkDT6ZGgcXhBCWeQLPp87rnZdhTau3Da0P7319G+ivOp57smbk/Eg== + +"@lwc/eslint-plugin-lwc@^1.1.2": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@lwc/eslint-plugin-lwc/-/eslint-plugin-lwc-1.7.0.tgz#2d440800dede6fe12acb3f486dce95e34dd55b9d" + integrity sha512-nmyoIFAbUFR5lUEvmHdEqgIqbHquUHjiLBKmrGzocFOu8PKI4jMgZdjI53Wrcn2ddLwBUwLZyEdkcvms3ni00A== + dependencies: + globals "^13.23.0" + minimatch "^9.0.3" + +"@lwc/jest-preset@11.8.0": + version "11.8.0" + resolved "https://registry.yarnpkg.com/@lwc/jest-preset/-/jest-preset-11.8.0.tgz#aaec8b4c4d6a250ed97d8d07978b8e3cdc014138" + integrity sha512-BHb246V3LGm8q1HPYKFEZIgHwgFi8X5lN2R0FZavfyt1lnGhSa4ilS/zpLAgTHhyTOUhXkR4BKTDauCGLl4brw== + dependencies: + "@lwc/jest-resolver" "11.8.0" + "@lwc/jest-serializer" "11.8.0" + "@lwc/jest-transformer" "11.8.0" + +"@lwc/jest-resolver@11.8.0": + version "11.8.0" + resolved "https://registry.yarnpkg.com/@lwc/jest-resolver/-/jest-resolver-11.8.0.tgz#ea17888f1f55a7975d4c1b035cd07173395c3bed" + integrity sha512-mN5tXW1jko671GUE/yZP/xbZ1ECpnZo40dLMzFctIUF9kOmMjRMv/xdsBTtBnI59W2WKMYDs8G7pywdMFBeZvw== + dependencies: + "@lwc/jest-shared" "11.8.0" + +"@lwc/jest-serializer@11.8.0": + version "11.8.0" + resolved "https://registry.yarnpkg.com/@lwc/jest-serializer/-/jest-serializer-11.8.0.tgz#eb520f6e1d4a1a6296af9101b745183387faa7cf" + integrity sha512-bjIywlnvTkfEvBNKOrb/DHMvTw/V78ZSgNwry2eCHcDFI93adj6HkAx+Qq214uprnT/lZUtxosJBTcc/DkjrpA== + dependencies: + pretty-format "^29.5.0" + +"@lwc/jest-shared@11.8.0": + version "11.8.0" + resolved "https://registry.yarnpkg.com/@lwc/jest-shared/-/jest-shared-11.8.0.tgz#dde7b80cca2eb1360a11d735e3da4c98ac036420" + integrity sha512-g4xgbD5+NC75omjZ6YZZ/tJhhrBnFEj2Lx/oY/yLtKUDXRX//PiWmGGcdlUbM5X8T8Bx9VR1wFttlB2Ta26VPQ== + +"@lwc/jest-transformer@11.8.0": + version "11.8.0" + resolved "https://registry.yarnpkg.com/@lwc/jest-transformer/-/jest-transformer-11.8.0.tgz#adcac2c8b1daac9058407e4d33734fe72c8df32e" + integrity sha512-qEyQnw95I7NtFugoTbIRlxN7jXiKCsrEo6ZvMOtyVAAJeKjbv02j+2XCSp15e8usnH5UFNY7DKm2wTxMfr991A== + dependencies: + "@babel/core" "^7.21.3" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-decorators" "^7.21.0" + "@babel/plugin-transform-modules-commonjs" "^7.21.2" + "@babel/preset-typescript" "^7.21.0" + "@lwc/jest-shared" "11.8.0" + babel-preset-jest "^29.5.0" + +"@lwc/module-resolver@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/module-resolver/-/module-resolver-2.42.0.tgz#a52189eb6060dd781eccaeb795ffa53f7e33cf3e" + integrity sha512-pwtgFNm/sNIS7daRnLCNLY4CqO/B31/ZwsqQd3Hs5eaH9iSFrGnoUm4sTVFyLljVAy7CXKdakwkvcj3JKjsO+w== + dependencies: + resolve "~1.22.1" + +"@lwc/shared@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/shared/-/shared-2.42.0.tgz#6ddbaaf6fee1c1bd812723b1101eb08b6e328535" + integrity sha512-YSI9VObp3fJ5yyg6vE4tDRB8dqKRT5ZYmKL03lzQh6+NMcjqv+EyW48Q2pPcv2ghsg0mJHvHBl7+hFGe5Z03OQ== + +"@lwc/style-compiler@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/style-compiler/-/style-compiler-2.42.0.tgz#0ac36abed925cafd7763c384aa351a9af60b6477" + integrity sha512-8p9YKqiNqK9XlblLgHYigRfNFsohmKYl400w/t5uewaMlLx/DoPlxcUmeEhGtibqkGEK7uqnuvLZDsO99Tuylw== + dependencies: + "@lwc/shared" "2.42.0" + postcss "~8.4.20" + postcss-selector-parser "~6.0.11" + postcss-value-parser "~4.2.0" + string.prototype.matchall "^4.0.8" + +"@lwc/synthetic-shadow@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/synthetic-shadow/-/synthetic-shadow-2.42.0.tgz#53332140e75dea1cc2cc20f6c4a9ab0c193de465" + integrity sha512-UgtQqoyoIH8qi2Tv05PuX3FGRjeASyBb8Ylqmn4qed7nCOeek5uUbWh2sX2Ck/lK73qVqk4jiH8xsK9MIrQvoQ== + +"@lwc/template-compiler@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/template-compiler/-/template-compiler-2.42.0.tgz#23a2915b57e1407ce48c3d27605dc79fdbb0717d" + integrity sha512-IMmm50fJUVG4kiX8gVptT6V/amtGMIi1dbcCU7rixjoBxd/F20lhZN3yHSPiWGFmoBWri16cFd+5hu3YYPRJdw== + dependencies: + "@lwc/errors" "2.42.0" + "@lwc/shared" "2.42.0" + acorn "~8.8.2" + astring "~1.8.3" + estree-walker "~2.0.2" + he "~1.2.0" + parse5 "~6.0.1" + +"@lwc/wire-service@2.42.0": + version "2.42.0" + resolved "https://registry.yarnpkg.com/@lwc/wire-service/-/wire-service-2.42.0.tgz#78dfe3612e7e49dcaf9f747008a9d400fefd3093" + integrity sha512-ZUY+8tYRxSYP5Murcb9tHZYXfMas4gNGfnt50Z/FxMX2kEC8Snp6sPyUTV1k4q+zTNu0zJ+WYHVpMgB+QfUc+w== + +"@mdn/browser-compat-data@^5.2.34", "@mdn/browser-compat-data@^5.3.13": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-5.4.2.tgz#96364693d73d9ee6735cf7390dfcc052c8b24c8a" + integrity sha512-KuBlKNjbZyU3jCTNGsJl+accdAZRUVVyMBeIXAUT+oMUQ64Uq2mxKajzonFJOXkhaAvTac+sDtJSLhaOzKIo2Q== + +"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": + version "5.1.1-v1" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" + integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg== + dependencies: + eslint-scope "5.1.1" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@prettier/plugin-xml@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@prettier/plugin-xml/-/plugin-xml-3.2.2.tgz#ccc53d39b333aef140433b62449ea9f74d8e2eb6" + integrity sha512-SoE70SQF1AKIvK7LVK80JcdAe6wrDcbodFFjcoqb1FkOqV0G0oSlgAFDwoRXPqkUE5p/YF2nGsnUbnfm6471sw== + dependencies: + "@xml-tools/parser" "^1.0.11" + +"@salesforce/eslint-config-lwc@^3.2.3": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@salesforce/eslint-config-lwc/-/eslint-config-lwc-3.5.2.tgz#45ae1596a35395cfec7c49736b9c52f8b9aa2b82" + integrity sha512-TqD5pF/OwjNNrms5nn9f6bf630T7WzXuH0RYF1ybsFOYsGQ2vFxD/F5fUNAjdQgLTR0hXK303j8yIw2fwTiOIQ== + dependencies: + "@babel/core" "~7.22.8" + "@babel/eslint-parser" "~7.22.7" + eslint-restricted-globals "~0.2.0" + semver "^7.5.3" + +"@salesforce/eslint-plugin-aura@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@salesforce/eslint-plugin-aura/-/eslint-plugin-aura-2.1.0.tgz#11c65d6190ecfffbc27e06b2d686026784c0b5c5" + integrity sha512-7HfwSBKTHQZQboLoEhkBY7bYR9wTaT+G5jHXGlq8y31hEnNhJXRZ+RERDEwDm1jYa2SV9lE8nMNr0/8EKIGjlQ== + dependencies: + eslint-plugin-compat "^4.0.2" + +"@salesforce/eslint-plugin-lightning@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@salesforce/eslint-plugin-lightning/-/eslint-plugin-lightning-1.0.0.tgz#9ecf80527d83394960ef3c358c790cdfde44f578" + integrity sha512-zk0PKXAcHKHepAG2EOSWlkOTxQM0Aw1CT6+MUxJcM42fCDwH/yPPpGkG3CWtRfmVViODGOwU9ywU2wlkAYcvUQ== + +"@salesforce/sfdx-lwc-jest@^1.1.0": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@salesforce/sfdx-lwc-jest/-/sfdx-lwc-jest-1.4.1.tgz#0dbe131e54dcbe3c37818eff57d9ad4364d43ae7" + integrity sha512-BYKt4FxBJfKkWUKvSC2Yxb+mnIcP+6URbawsX8aeo1pKRnz6TDusiNZE8bR+8ZRWwnmeUC0fzKlZEi3xIqzMRg== + dependencies: + "@lwc/compiler" "2.42.0" + "@lwc/engine-dom" "2.42.0" + "@lwc/jest-preset" "11.8.0" + "@lwc/jest-resolver" "11.8.0" + "@lwc/jest-serializer" "11.8.0" + "@lwc/jest-transformer" "11.8.0" + "@lwc/module-resolver" "2.42.0" + "@lwc/synthetic-shadow" "2.42.0" + "@lwc/wire-service" "2.42.0" + "@salesforce/wire-service-jest-util" "4.0.1" + chalk "^4.1.2" + fast-glob "^3.2.12" + jest "27.4.7" + yargs "~17.6.2" + +"@salesforce/wire-service-jest-util@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@salesforce/wire-service-jest-util/-/wire-service-jest-util-4.0.1.tgz#776d2a8b5dee9a63803e46cde7d511f32ada85ae" + integrity sha512-6u3ZGXDCeRnKSX8WHRpVQAXmGiee6NkhmQb0gXmcPAm8zW/Q7o7lRJNvXKnxnXY7qyiKXVYDQAFKJjtGpaCfjw== + +"@sideway/address@^4.1.3": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^1.7.0": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" + integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.7" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.7.tgz#a7aebf15c7bc0eb9abd638bdb5c0b8700399c9d0" + integrity sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.20.4" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.4.tgz#ec2c06fed6549df8bc0eb4615b683749a4a92e1b" + integrity sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA== + dependencies: + "@babel/types" "^7.20.7" + +"@types/graceful-fs@^4.1.2": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/json-schema@^7.0.9": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/node@*": + version "20.10.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.0.tgz#16ddf9c0a72b832ec4fcce35b8249cf149214617" + integrity sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ== + dependencies: + undici-types "~5.26.4" + +"@types/prettier@^2.1.5": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== + +"@types/semver@^7.3.12": + version "7.5.6" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" + integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^16.0.0": + version "16.0.9" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.9.tgz#ba506215e45f7707e6cbcaf386981155b7ab956e" + integrity sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== + +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@^5.10.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== + dependencies: + "@typescript-eslint/types" "5.62.0" + eslint-visitor-keys "^3.3.0" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@xml-tools/parser@^1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@xml-tools/parser/-/parser-1.0.11.tgz#a118a14099ea5c3c537e4781fad2fc195b57f8ff" + integrity sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA== + dependencies: + chevrotain "7.1.1" + +abab@^2.0.3, abab@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4, acorn@^8.9.0: + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== + +acorn@~8.8.2: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.findlastindex@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + +ast-metadata-inferer@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/ast-metadata-inferer/-/ast-metadata-inferer-0.8.0.tgz#0f94c3425e310d8da45823ab2161142e3f134343" + integrity sha512-jOMKcHht9LxYIEQu+RVd22vtgrPaVCtDRQ/16IGmurdzxvYbDd5ynxjnyrzLnieG96eTcAyaoj/wN/4/1FyyeA== + dependencies: + "@mdn/browser-compat-data" "^5.2.34" + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +astring@~1.8.3: + version "1.8.6" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.8.6.tgz#2c9c157cf1739d67561c56ba896e6948f6b93731" + integrity sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axios@^1.6.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" + integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== + dependencies: + babel-plugin-jest-hoist "^27.5.1" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-jest@^29.5.0: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.21.10, browserslist@^4.21.9: + version "4.22.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" + integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== + dependencies: + caniuse-lite "^1.0.30001541" + electron-to-chromium "^1.4.535" + node-releases "^2.0.13" + update-browserslist-db "^1.0.13" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001524, caniuse-lite@^1.0.30001541: + version "1.0.30001565" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz#a528b253c8a2d95d2b415e11d8b9942acc100c4f" + integrity sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chevrotain@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-7.1.1.tgz#5122814eafd1585a9601f9180a7be9c42d5699c6" + integrity sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw== + dependencies: + regexp-to-ast "0.5.0" + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.16: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^9.3.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decimal.js@^10.2.1: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.4.535: + version "1.4.596" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.596.tgz#6752d1aa795d942d49dfc5d3764d6ea283fab1d7" + integrity sha512-zW3zbZ40Icb2BCWjm47nxwcFGYlIgdXkAx85XDO7cyky9J4QQfq8t0W19/TLZqq3JPQXtlv8BPIGmfa9Jb4scg== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + +es-set-tostringtag@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + dependencies: + get-intrinsic "^1.2.2" + has-tostringtag "^1.0.0" + hasown "^2.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-compat@^4.0.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-compat/-/eslint-plugin-compat-4.2.0.tgz#eeaf80daa1afe495c88a47e9281295acae45c0aa" + integrity sha512-RDKSYD0maWy5r7zb5cWQS+uSPc26mgOzdORJ8hxILmWM7S/Ncwky7BcAtXVY5iRbKjBdHsWU8Yg7hfoZjtkv7w== + dependencies: + "@mdn/browser-compat-data" "^5.3.13" + ast-metadata-inferer "^0.8.0" + browserslist "^4.21.10" + caniuse-lite "^1.0.30001524" + find-up "^5.0.0" + lodash.memoize "^4.1.2" + semver "^7.5.4" + +eslint-plugin-import@^2.25.4: + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.14.2" + +eslint-plugin-jest@^26.1.2: + version "26.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-26.9.0.tgz#7931c31000b1c19e57dbfb71bbf71b817d1bf949" + integrity sha512-TWJxWGp1J628gxh2KhaH1H1paEdgE2J61BBF1I59c6xWeL5+D1BzMxGDN/nXAfX+aSkR5u80K+XhskK6Gwq9ng== + dependencies: + "@typescript-eslint/utils" "^5.10.0" + +eslint-restricted-globals@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.2.0.tgz#7729f326af97bec7a7e56d9f7d9c064b79285c50" + integrity sha512-kwYJALm5KS2QW3Mc1PgObO4V+pTR6RQtRT65L1GQILlEnAhabUQqGAX7/qUjoQR4KZJKehWpBtyDEiDecwmY9A== + +eslint-scope@5.1.1, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.11.0: + version "8.54.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.54.0.tgz#588e0dd4388af91a2e8fa37ea64924074c783537" + integrity sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.3" + "@eslint/js" "8.54.0" + "@humanwhocodes/config-array" "^0.11.13" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== + dependencies: + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.12, fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + +follow-redirects@^1.15.0: + version "1.15.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" + integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0, globals@^13.23.0: + version "13.23.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + +he@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +husky@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" + integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isarray@1.0.0, isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== + dependencies: + isarray "1.0.0" + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== + dependencies: + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.4.7: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== + dependencies: + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== + dependencies: + detect-newline "^3.0.0" + +jest-docblock@^29.0.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + +jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" + +jest-environment-node@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + +jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== + dependencies: + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" + +jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== + dependencies: + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== + +jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== + dependencies: + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" + +jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + +jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + natural-compare "^1.4.0" + pretty-format "^27.5.1" + semver "^7.3.2" + +jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== + dependencies: + "@jest/types" "^27.5.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.5.1" + leven "^3.1.0" + pretty-format "^27.5.1" + +jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== + dependencies: + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.5.1" + string-length "^4.0.1" + +jest-worker@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@27.4.7: + version "27.4.7" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.4.7.tgz#87f74b9026a1592f2da05b4d258e57505f28eca4" + integrity sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg== + dependencies: + "@jest/core" "^27.4.7" + import-local "^3.0.2" + jest-cli "^27.4.7" + +joi@^17.11.0: + version "17.11.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.11.0.tgz#aa9da753578ec7720e6f0ca2c7046996ed04fc1a" + integrity sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" + integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== + +line-column@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/line-column/-/line-column-1.0.2.tgz#d25af2936b6f4849172b312e4792d1d987bc34a2" + integrity sha512-Ktrjk5noGYlHsVnYWh62FLVs4hTb8A3e+vucNZMgPeAOITdshMSgv4cCZQeRDjm7+goqmo6+liZwTXo+U3sVww== + dependencies: + isarray "^1.0.0" + isobject "^2.0.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lint-staged@^12.3.7: + version "12.5.0" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.5.0.tgz#d6925747480ae0e380d13988522f9dd8ef9126e3" + integrity sha512-BKLUjWDsKquV/JuIcoQW4MSAI3ggwEImF1+sB4zaKvyVx1wBk3FsG7UK9bpnmBTN1pm7EH2BBcMwINJzCRv12g== + dependencies: + cli-truncate "^3.1.0" + colorette "^2.0.16" + commander "^9.3.0" + debug "^4.3.4" + execa "^5.1.1" + lilconfig "2.0.5" + listr2 "^4.0.5" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-inspect "^1.12.2" + pidtree "^0.5.0" + string-argv "^0.3.1" + supports-color "^9.2.2" + yaml "^1.10.2" + +listr2@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" + integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.5" + through "^2.3.8" + wrap-ansi "^7.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.17.21, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.6: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nwsapi@^2.2.0: + version "2.2.7" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" + integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + +object-inspect@^1.12.2, object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.groupby@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + +object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@6.0.1, parse5@~6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pidtree@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.5.0.tgz#ad5fbc1de78b8a5f99d6fbdd4f6e4eee21d1aca1" + integrity sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +postcss-selector-parser@~6.0.11: + version "6.0.13" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@~4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@~8.4.20: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-plugin-apex@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/prettier-plugin-apex/-/prettier-plugin-apex-2.0.1.tgz#35bb37fbf7d779f8a83e25ecd02e133a16cd903a" + integrity sha512-S64zate3iXPKiBKHf27YRapIAPPd1wQ/u5IOcWwSHNgoJv15I14HhoUB/WOKXtxFb0ZH5MO1nF8gRGWXLajwlA== + dependencies: + jest-docblock "^29.0.0" + wait-on "^7.0.0" + +prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" + integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== + +pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +pretty-format@^29.5.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +regexp-to-ast@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz#56c73856bee5e1fef7f73a00f1473452ab712a24" + integrity sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw== + +regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" + integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== + +resolve@^1.20.0, resolve@^1.22.4, resolve@~1.22.1: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.5.5, rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.2, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-argv@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.matchall@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" + integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + regexp.prototype.flags "^1.5.0" + set-function-name "^2.0.0" + side-channel "^1.0.4" + +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^9.2.2: + version "9.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.4.0.tgz#17bfcf686288f531db3dea3215510621ccb55954" + integrity sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw== + +supports-hyperlinks@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +throat@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" + integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tough-cookie@^4.0.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +tsconfig-paths@^3.14.2: + version "3.14.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.1.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-to-istanbul@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" + integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +wait-on@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-7.2.0.tgz#d76b20ed3fc1e2bebc051fae5c1ff93be7892928" + integrity sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ== + dependencies: + axios "^1.6.1" + joi "^17.11.0" + lodash "^4.17.21" + minimist "^1.2.8" + rxjs "^7.8.1" + +walker@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@~17.6.2: + version "17.6.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" + integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==