diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..1320b9a --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..4b61082 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,3 @@ +last 2 versions +not dead +> 0.5% \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..db4c6d9 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +dist +node_modules \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..b6b5228 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,36 @@ +{ + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "jest", "prettier", "import"], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended", "prettier"], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "env": { + "es6": true, + "browser": true, + "node": true + }, + "rules": { + "no-debugger": "off", + "no-console": "off", + "object-shorthand": "warn", + "array-callback-return": "warn", + "prefer-destructuring": "warn", + "prefer-arrow-callback": "warn", + "no-duplicate-imports": "warn", + "import/first": "warn", + "eqeqeq": "warn", + "no-unneeded-ternary": "warn", + "no-else-return": "warn", + "spaced-comment": "warn", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-var-requires": "off", + "prettier/prettier": [ + "error", + { + "endOfLine": "auto" + } + ] + } +} diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template_for_mentor.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template_for_mentor.md index ba58e9b..10dbd99 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template_for_mentor.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template_for_mentor.md @@ -1,15 +1,18 @@ 1. Task: [link](https://github.com/rolling-scopes-school/tasks/blob/master/tasks/eCommerce-Application/Sprints/Sprint%231.md) -2. Screenshot: +2. Screenshot: 3. Deploy: [link]() 4. Done 07.08.2023 / deadline 07.08.2023 5. Score: 110 / 110 + #### CrossCheck Criteria (55/55): + - [x] Example (5/5): - (+5) Example. - [x] Example (50/50): - (+50) Example. #### Mentor Evaluation Criteria (55/55): + - [x] Example (5/5): - (+5) Example. - [x] Example (50/50): diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7c881e4..e732f0c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,20 +1,21 @@ -__1. Task__ +**1. Task** _task_title_ -__2. Link in [project](https://github.com/orgs/this-is-this-team/projects/3)__ +**2. Link in [project](https://github.com/orgs/this-is-this-team/projects/3)** _if multiple issues are combined into a single pull request then insert all links (link-1, link-2, etc.)_ [link](_insert_link_here_) -__3. Sprint__ +**3. Sprint** _number_of_sprint_ -__4. Timeline__ +**4. Timeline** Done 01.08.2023 / Deadline 30.08.2023 -__5. Task description and solution__ +**5. Task description and solution** _task_description_and_solution_ -__6. Self Check before Merge__ +**6. Self Check before Merge** + - [ ] Pull request title should follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) - [ ] Reviewers added (elsuppo/MaxLisyanskiy/eugenebalts) - [ ] All commits in pull request should follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..83985be --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged +npm run test \ No newline at end of file diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000..5dcf2f6 --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1 @@ +{ "*.{js,ts}": ["npm run lint:check"], "*": ["npm run prettier:check"] } diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..3c41576 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "printWidth": 120, + "bracketSameLine": false, + "endOfLine": "auto" +} diff --git a/README.md b/README.md index d416b84..0098b50 100644 --- a/README.md +++ b/README.md @@ -1 +1,145 @@ -# eCommerce-Application \ No newline at end of file +# eCommerce-Application _«this is this.»_ + +:earth_americas:`this is this.` is a web application for searching and buying travel tours. +The project is being developed as part of the final task of the course [JavaScript/Front-end (2023Q1)](https://rs.school/js/) from the [RS School](https://rs.school/). +The [`this-is-this team`](https://github.com/this-is-this-team) is working on the project. + +## Commercetools Setup + +
+ .env example +
+
+    CTP_PROJECT_KEY=
+    CTP_CLIENT_SECRET=
+    CTP_CLIENT_ID=
+    CTP_AUTH_URL=
+    CTP_API_URL=
+    CTP_SCOPES=
+  
+
+ +
+ necessary scopes +
+ profile-details + +
+ +## Project Purpose + +- Develop a Single Page Application (SPA) without using frameworks +- Teamwork skills +- Task planning +- Consolidation of knowledge gained on the course + +## Technology Stack + +[![skills](https://skillicons.dev/icons?i=webpack,ts,html,css,scss,jest,git&theme=light)](#technology-stack) eslint prettier eslint + +- **TypeScript** _[docs](https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html)_ +- **Webpack 5** _[docs](https://webpack.js.org/concepts/)_ +- **Jest** _[docs](https://jestjs.io/docs/getting-started)_ +- **SCSS** _[docs](https://sass-lang.com/documentation/)_ +- **CommerceTools API** _[docs](https://docs.commercetools.com/api/general-concepts)_ +- Teamwork tools: + - **Prettier** _[docs](https://prettier.io/docs/en/)_ + - **ESLint** _[docs](https://eslint.org/docs/latest/use/core-concepts)_ + - **Husky** _[docs](https://typicode.github.io/husky/)_ + - **lint-staged** _[docs](https://github.com/okonet/lint-staged)_ + +## Getting Started + +To get a local copy of the project perform the following actions: + +1. Clone the repo + +``` +git clone https://github.com/this-is-this-team/eCommerce-Application.git +``` + +2. Install npm packages + +``` +npm install +``` + +3. Run the project locally + +``` +npm run start +``` + +## Available scripts + +#### Webpack (code building) + +- build development version + +``` +npm run build:dev +``` + +- build production version + +``` +npm run build:prod +``` + +#### Prettier (code formatting) + +- сhecks formatting for all project files + +``` +npm run prettier:check +``` + +- auto fixes formatting for all project files + +``` +npm run prettier:fix +``` + +#### ESLint (code linting) + +- checks linting for all project files + +``` +npm run lint:check +``` + +- auto fixes linting error for all project files + +``` +npm run lint:fix +``` + +#### JEST (code testing) + +- run all `*.test.ts` files for test execution + +``` +npm run test +``` + +
+ ALSO + + Before making a commit an **automated** check is performed for formatting, linting, and code testing using Husky and lint-staged + ``` + npx lint-staged + npm run test + ``` +
diff --git a/jest.config.json b/jest.config.json new file mode 100644 index 0000000..48135e5 --- /dev/null +++ b/jest.config.json @@ -0,0 +1,9 @@ +{ + "preset": "ts-jest", + "testEnvironment": "jsdom", + "moduleFileExtensions": ["ts", "js"], + "testMatch": ["**/__tests__/**/*.+(ts|tsx|js)", "**/?(*.)+(spec|test).+(ts|tsx|js)"], + "moduleNameMapper": { + "^.+\\.(css|less|scss)$": "babel-jest" + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..fc951e9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,16175 @@ +{ + "name": "ecommerce-application", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ecommerce-application", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@commercetools/platform-sdk": "^4.11.0", + "@commercetools/sdk-client-v2": "^2.2.0", + "swiper": "^10.2.0", + "toastify-js": "^1.12.0" + }, + "devDependencies": { + "@babel/core": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@types/jest": "^29.5.3", + "@types/node-fetch": "^2.6.4", + "@types/toastify-js": "^1.12.0", + "@typescript-eslint/eslint-plugin": "^6.2.1", + "babel-loader": "^9.1.3", + "css-loader": "^6.8.1", + "dotenv-webpack": "^8.0.1", + "eslint": "^8.46.0", + "eslint-config-prettier": "^8.9.0", + "eslint-plugin-import": "^2.28.0", + "eslint-plugin-jest": "^27.2.3", + "eslint-plugin-prettier": "^5.0.0", + "eslint-webpack-plugin": "^4.0.1", + "html-webpack-plugin": "^5.5.3", + "husky": "^8.0.3", + "jest": "^29.6.2", + "jest-environment-jsdom": "^29.6.2", + "lint-staged": "^13.2.3", + "mini-css-extract-plugin": "^2.7.6", + "postcss": "^8.4.27", + "postcss-loader": "^7.3.3", + "postcss-preset-env": "^9.1.0", + "prettier": "^3.0.0", + "sass": "^1.64.2", + "sass-loader": "^13.3.2", + "style-loader": "^3.3.3", + "ts-jest": "^29.1.1", + "ts-loader": "^9.4.4", + "typescript": "^5.1.6", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", + "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", + "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz", + "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==", + "dev": true, + "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.5", + "@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" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz", + "integrity": "sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", + "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz", + "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", + "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz", + "integrity": "sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz", + "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz", + "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz", + "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", + "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", + "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz", + "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", + "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", + "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", + "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", + "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", + "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", + "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", + "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", + "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", + "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", + "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", + "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", + "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz", + "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", + "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", + "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", + "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", + "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@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-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.5", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.5", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.5", + "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", + "@babel/plugin-transform-numeric-separator": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", + "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.5", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.5", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", + "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", + "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@commercetools/platform-sdk": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@commercetools/platform-sdk/-/platform-sdk-4.11.0.tgz", + "integrity": "sha512-ftcq6mCxzpIG9wmGpTED6KQCApk4nyURh81J3PRP3d48oCLOrkZSyzDDfvflGoVZQeIcox+YdtyqZoryFrRtmQ==", + "dependencies": { + "@commercetools/sdk-client-v2": "^2.1.6", + "@commercetools/sdk-middleware-auth": "^7.0.0", + "@commercetools/sdk-middleware-http": "^7.0.0", + "@commercetools/sdk-middleware-logger": "^3.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@commercetools/sdk-client-v2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@commercetools/sdk-client-v2/-/sdk-client-v2-2.2.0.tgz", + "integrity": "sha512-/j/hINnuh3gdBeMrHUvuSZo+8nkckCHK3Nu6m3/ZkUqVkamRheU5ve/DlALvYpjs2XS2BdWTs1+Wsyyz1+x6iQ==", + "dependencies": { + "buffer": "^6.0.3", + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@commercetools/sdk-middleware-auth": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@commercetools/sdk-middleware-auth/-/sdk-middleware-auth-7.0.1.tgz", + "integrity": "sha512-XLRm+o3Yd0mkVoyzsOA98PUu0U0ajQdBHMhZ8N2XMOtL4OY8zsgT8ap5JneXV8zWZNiwIYYAYoUDwBlLZh2lAQ==", + "dependencies": { + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@commercetools/sdk-middleware-http": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@commercetools/sdk-middleware-http/-/sdk-middleware-http-7.0.3.tgz", + "integrity": "sha512-vCMYMCla8vJsbmIpFyaq0DrjcIgkJpTsW+yOMupXM/ggR6PeJWav0H1iObGX3rZOpn6ZDJZglgGbFQ/Z0kGrJw==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@commercetools/sdk-middleware-logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@commercetools/sdk-middleware-logger/-/sdk-middleware-logger-3.0.0.tgz", + "integrity": "sha512-DhMXAA2yIch/AaGxy7st85Z1HFmeLtHWGkr9z5rX4xKjan4PHGB/IE5saAR+SNGHhs6+1Lp8vZEHDo3tFqVLmg==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-1.0.4.tgz", + "integrity": "sha512-zXMGsJetbLoXe+gjEES07MEGjL0Uy3hMxmnGtVBrRpVKr5KV9OgCB09zr/vLrsEtoVQTgJFewxaU8IYSAE4tjg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-3.0.0.tgz", + "integrity": "sha512-rBODd1rY01QcenD34QxbQxLc1g+Uh7z1X/uzTHNQzJUnFCT9/EZYI7KWq+j0YfWMXJsRJ8lVkqBcB0R/qLr+yg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-1.1.3.tgz", + "integrity": "sha512-7mJZ8gGRtSQfQKBQFi5N0Z+jzNC0q8bIkwojP1W0w+APzEqHu5wJoGVsvKxVnVklu9F8tW1PikbBRseYnAdv+g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-1.2.3.tgz", + "integrity": "sha512-YaEnCoPTdhE4lPQFH3dU4IEk8S+yCnxS88wMv45JzlnMfZp57hpqA6qf2gX8uv7IJTJ/43u6pTQmhy7hCjlz7g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/color-helpers": "^3.0.0", + "@csstools/css-calc": "^1.1.3" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.3.1.tgz", + "integrity": "sha512-xrvsmVUtefWMWQsGgFffqWSK03pZ1vfDki4IVIIUxxDKnGBzqNgv0A7SB1oXtVNEkcVO8xi1ZrTL29HhSu5kGA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^2.2.0" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.0.tgz", + "integrity": "sha512-wErmsWCbsmig8sQKkM6pFhr/oPha1bHfvxsUY5CYSQxwyhA9Ulrs8EqCgClhg4Tgg2XapVstGqSVcz0xOYizZA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.3.tgz", + "integrity": "sha512-ATul1u+pic4aVpstgueqxEv4MsObEbszAxfTXpx9LHaeD3LAh+wFqdCteyegWmjk0k5rkSCAvIOaJe9U3DD09w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-4.0.0.tgz", + "integrity": "sha512-dVPVVqQG0FixjM9CG/+8eHTsCAxRKqmNh6H69IpruolPlnEF1611f2AoLK8TijTSAsqBSclKd4WHs1KUb/LdJw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-specificity": "^3.0.0", + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-3.0.1.tgz", + "integrity": "sha512-+vrvCQeUifpMeyd42VQ3JPWGQ8cO19+TnGbtfq1SDSgZzRapCQO4aK9h/jhMOKPnxGzbA57oS0aHgP/12N9gSQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.2.2", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/postcss-progressive-custom-properties": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-2.0.1.tgz", + "integrity": "sha512-Z5cXkLiccKIVcUTe+fAfjUD7ZUv0j8rq3dSoBpM6I49dcw+50318eYrwUZa3nyb4xNx7ntNNUPmesAc87kPE2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.2.2", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/postcss-progressive-custom-properties": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-exponential-functions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-1.0.0.tgz", + "integrity": "sha512-FPndJ/7oGlML7/4EhLi902wGOukO0Nn37PjwOQGc0BhhjQPy3np3By4d3M8s9Cfmp9EHEKgUHRN2DQ5HLT/hTw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^1.1.3", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-3.0.0.tgz", + "integrity": "sha512-ntkGj+1uDa/u6lpjPxnkPcjJn7ChO/Kcy08YxctOZI7vwtrdYvFhmE476dq8bj1yna306+jQ9gzXIG/SWfOaRg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-4.0.1.tgz", + "integrity": "sha512-IHeFIcksjI8xKX7PWLzAyigM3UvJdZ4btejeNa7y/wXxqD5dyPPZuY55y8HGTrS6ETVTRqfIznoCPtTzIX7ygQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.2.2", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/postcss-progressive-custom-properties": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-3.0.1.tgz", + "integrity": "sha512-FYe2K8EOYlL1BUm2HTXVBo6bWAj0xl4khOk6EFhQHy/C5p3rlr8OcetzQuwMeNQ3v25nB06QTgqUHoOUwoEqhA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.2.2", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-3.0.0.tgz", + "integrity": "sha512-FH3+zfOfsgtX332IIkRDxiYLmgwyNk49tfltpC6dsZaO4RV2zWY6x9VMIC5cjvmjlDO7DIThpzqaqw2icT8RbQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^3.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-4.0.0.tgz", + "integrity": "sha512-0I6siRcDymG3RrkNTSvHDMxTQ6mDyYE8awkcaHNgtYacd43msl+4ZWDfQ1yZQ/viczVWjqJkLmPiRHSgxn5nZA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-specificity": "^3.0.0", + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-2.0.0.tgz", + "integrity": "sha512-Wki4vxsF6icRvRz8eF9bPpAvwaAt0RHwhVOyzfoFg52XiIMjb6jcbHkGxwpJXP4DVrnFEwpwmrz5aTRqOW82kg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-2.0.0.tgz", + "integrity": "sha512-lCQ1aX8c5+WI4t5EoYf3alTzJNNocMqTb+u1J9CINdDhFh1fjovqK+0aHalUHsNstZmzFPNzIkU4Mb3eM9U8SA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-2.0.1.tgz", + "integrity": "sha512-R5s19SscS7CHoxvdYNMu2Y3WDwG4JjdhsejqjunDB1GqfzhtHSvL7b5XxCkUWqm2KRl35hI6kJ4HEaCDd/3BXg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-tokenizer": "^2.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.0.6.tgz", + "integrity": "sha512-BmwKkqEzzQz6D+5ctoacsiGrq4kVgd1PMEPwkwdR0qFaL2C2nguGsWG87xEw+HIts/2yxhIPTm7Jp3DQq+wn3Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^1.1.3", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/media-query-list-parser": "^2.1.3" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.1.tgz", + "integrity": "sha512-UvMYxXT3R011whbxzRwLx7d7eNGyVsnZo7waAmf10ZGnT34XidY+rsdFnk6OdFwuG6FYqw3/tptQEAZOmUgvLw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/media-query-list-parser": "^2.1.3" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-3.0.0.tgz", + "integrity": "sha512-HsB66aDWAouOwD/GcfDTS0a7wCuVWaTpXcjl5VKP0XvFxDiU+r0T8FG7xgb6ovZNZ+qzvGIwRM+CLHhDgXrYgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-3.0.0.tgz", + "integrity": "sha512-6Nw55PRXEKEVqn3bzA8gRRPYxr5tf5PssvcE5DRA/nAxKgKtgNZMCHCSd1uxTCWeyLnkf6h5tYRSB0P1Vh/K/A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-3.0.1.tgz", + "integrity": "sha512-3TIz+dCPlQPzz4yAEYXchUpfuU2gRYK4u1J+1xatNX85Isg4V+IbLyppblWLV4Vb6npFF8qsHN17rNuxOIy/6w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.2.2", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/postcss-progressive-custom-properties": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-3.0.0.tgz", + "integrity": "sha512-2/D3CCL9DN2xhuUTP8OKvKnaqJ1j4yZUxuGLsCUOQ16wnDAuMLKLkflOmZF5tsPh/02VPeXRmqIN+U595WAulw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-2.0.1.tgz", + "integrity": "sha512-9B8br/7q0bjD1fV3yE22izjc7Oy5hDbDgwdFEz207cdJHYC9yQneJzP3H+/w3RgC7uyfEVhyyhkGRx5YAfJtmg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.2.2", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/postcss-progressive-custom-properties": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-3.0.0.tgz", + "integrity": "sha512-GFNVsD97OuEcfHmcT0/DAZWAvTM/FFBDQndIOLawNc1Wq8YqpZwBdHa063Lq+Irk7azygTT+Iinyg3Lt76p7rg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-3.0.1.tgz", + "integrity": "sha512-y1sykToXorFE+5cjtp//xAMWEAEple0kcZn2QhzEFIZDDNvGOCp5JvvmmPGsC3eDlj6yQp70l9uXZNLnimEYfA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^1.1.3", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-3.0.0.tgz", + "integrity": "sha512-BAa1MIMJmEZlJ+UkPrkyoz3DC7kLlIl2oDya5yXgvUrelpwxddgz8iMp69qBStdXwuMyfPx46oZcSNx8Z0T2eA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/color-helpers": "^3.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-3.0.1.tgz", + "integrity": "sha512-hW+JPv0MPQfWC1KARgvJI6bisEUFAZWSvUNq/khGCupYV/h6Z9R2ZFz0Xc633LXBst0ezbXpy7NpnPurSx5Klw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-calc": "^1.1.3", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-3.0.0.tgz", + "integrity": "sha512-P0JD1WHh3avVyKKRKjd0dZIjCEeaBer8t1BbwGMUDtSZaLhXlLNBqZ8KkqHzYWXOJgHleXAny2/sx8LYl6qhEA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz", + "integrity": "sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.13" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", + "dev": true, + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", + "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.2.tgz", + "integrity": "sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.6.2", + "jest-util": "^29.6.2", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.2.tgz", + "integrity": "sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.6.2", + "@jest/reporters": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.6.2", + "jest-haste-map": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.6.2", + "jest-resolve-dependencies": "^29.6.2", + "jest-runner": "^29.6.2", + "jest-runtime": "^29.6.2", + "jest-snapshot": "^29.6.2", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", + "jest-watcher": "^29.6.2", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.2", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.2.tgz", + "integrity": "sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/node": "*", + "jest-mock": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.2.tgz", + "integrity": "sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg==", + "dev": true, + "dependencies": { + "expect": "^29.6.2", + "jest-snapshot": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.2.tgz", + "integrity": "sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.2.tgz", + "integrity": "sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.1", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.6.2", + "jest-mock": "^29.6.2", + "jest-util": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.2.tgz", + "integrity": "sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.6.2", + "@jest/expect": "^29.6.2", + "@jest/types": "^29.6.1", + "jest-mock": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.2.tgz", + "integrity": "sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "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-message-util": "^29.6.2", + "jest-util": "^29.6.2", + "jest-worker": "^29.6.2", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz", + "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.6.2", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz", + "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.0.tgz", + "integrity": "sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.2.tgz", + "integrity": "sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw==", + "dev": true, + "dependencies": { + "@jest/console": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz", + "integrity": "sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.6.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.2", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.2.tgz", + "integrity": "sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.1", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.2", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.6.2", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "29.6.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.1.tgz", + "integrity": "sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgr/utils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", + "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "fast-glob": "^3.3.0", + "is-glob": "^4.0.3", + "open": "^9.1.0", + "picocolors": "^1.0.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@pkgr/utils/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@pkgr/utils/node_modules/open": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, + "dependencies": { + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.1.tgz", + "integrity": "sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true + }, + "node_modules/@types/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.11", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz", + "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.3.tgz", + "integrity": "sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", + "dev": true + }, + "node_modules/@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", + "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/toastify-js": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@types/toastify-js/-/toastify-js-1.12.0.tgz", + "integrity": "sha512-fqpDHaKhFukN9KRm24bbH0wozvHmSwjvkaLjBUrWcSfSS4zysIwTYqNLG3XbSNhRlsTNRNLGS23tp/VhPwsfHQ==", + "dev": true + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", + "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.2.1.tgz", + "integrity": "sha512-iZVM/ALid9kO0+I81pnp1xmYiFyqibAHzrqX4q5YvvVEyJqY+e6rfTXSCsc2jUxGNqJqTfFSSij/NFkZBiBzLw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.2.1", + "@typescript-eslint/type-utils": "6.2.1", + "@typescript-eslint/utils": "6.2.1", + "@typescript-eslint/visitor-keys": "6.2.1", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.2.1.tgz", + "integrity": "sha512-Ld+uL1kYFU8e6btqBFpsHkwQ35rw30IWpdQxgOqOh4NfxSDH6uCkah1ks8R/RgQqI5hHPXMaLy9fbFseIe+dIg==", + "dev": true, + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.2.1", + "@typescript-eslint/types": "6.2.1", + "@typescript-eslint/typescript-estree": "6.2.1", + "@typescript-eslint/visitor-keys": "6.2.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "peer": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "peer": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.2.1.tgz", + "integrity": "sha512-UCqBF9WFqv64xNsIEPfBtenbfodPXsJ3nPAr55mGPkQIkiQvgoWNo+astj9ZUfJfVKiYgAZDMnM6dIpsxUMp3Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.2.1", + "@typescript-eslint/visitor-keys": "6.2.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.2.1.tgz", + "integrity": "sha512-fTfCgomBMIgu2Dh2Or3gMYgoNAnQm3RLtRp+jP7A8fY+LJ2+9PNpi5p6QB5C4RSP+U3cjI0vDlI3mspAkpPVbQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.2.1", + "@typescript-eslint/utils": "6.2.1", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.2.1.tgz", + "integrity": "sha512-528bGcoelrpw+sETlyM91k51Arl2ajbNT9L4JwoXE2dvRe1yd8Q64E4OL7vHYw31mlnVsf+BeeLyAZUEQtqahQ==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.2.1.tgz", + "integrity": "sha512-G+UJeQx9AKBHRQBpmvr8T/3K5bJa485eu+4tQBxFq0KoT22+jJyzo1B50JDT9QdC1DEmWQfdKsa8ybiNWYsi0Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.2.1", + "@typescript-eslint/visitor-keys": "6.2.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.2.1.tgz", + "integrity": "sha512-eBIXQeupYmxVB6S7x+B9SdBeB6qIdXKjgQBge2J+Ouv8h9Cxm5dHf/gfAZA6dkMaag+03HdbVInuXMmqFB/lKQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.2.1", + "@typescript-eslint/types": "6.2.1", + "@typescript-eslint/typescript-estree": "6.2.1", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.2.1.tgz", + "integrity": "sha512-iTN6w3k2JEZ7cyVdZJTVJx2Lv7t6zFA8DCrJEHD2mwfc16AEvvBWVhbFh34XyG2NORCd0viIgQY1+u7kPI0WpA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.2.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz", + "integrity": "sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-jest": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.2.tgz", + "integrity": "sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.6.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-loader/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/babel-loader/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/babel-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.2", + "core-js-compat": "^3.31.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "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" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.5.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, + "dependencies": { + "run-applescript": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001518", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001518.tgz", + "integrity": "sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.0.tgz", + "integrity": "sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.9" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "dev": true, + "dependencies": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-6.0.0.tgz", + "integrity": "sha512-VbfLlOWO7sBHBTn6pwDQzc07Z0SDydgDBfNfCE0nvrehdBNv9RKsuupIRa/qal0+fBZhAALyQDPMKz5lnvcchw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-6.0.0.tgz", + "integrity": "sha512-X+r+JBuoO37FBOWVNhVJhxtSBUFHgHbrcc0CjFT28JEdOw1qaDwABv/uunyodUuSy2hMPe9j/HjssxSlvUmKjg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-specificity": "^3.0.0", + "postcss-selector-parser": "^6.0.13", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", + "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/css-prefers-color-scheme": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-9.0.0.tgz", + "integrity": "sha512-03QGAk/FXIRseDdLb7XAiu6gidQ0Nd8945xuM7VFVPpc6goJsG9uIO8xQjTxwbPdPIIV4o4AJoOJyt8gwDl67g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.7.0.tgz", + "integrity": "sha512-1hN+I3r4VqSNQ+OmMXxYexnumbOONkSil0TWMebVXHtzYW4tRRPovUNHPHj2d4nrgOuYJ8Vs3XwvywsuwwXNNA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ] + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/default-browser/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/default-browser/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.0.tgz", + "integrity": "sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dev": true, + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-webpack": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.0.1.tgz", + "integrity": "sha512-CdrgfhZOnx4uB18SgaoP9XHRN2v48BbjuXQsZY5ixs5A8579NxQkmMxRtI7aTwSiSQcM2ao12Fdu+L3ZS3bG4w==", + "dev": true, + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.479", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.479.tgz", + "integrity": "sha512-ABv1nHMIR8I5n3O3Een0gr6i0mfM+YcTZqjHy3pAYaOjgFG+BMquuKrSyfYf5CbEkLr9uM05RA3pOk4udNB/aQ==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "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.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "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.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", + "dev": true + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", + "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "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.2", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.9.0.tgz", + "integrity": "sha512-+sbni7NfVXnOpnRadUA8S28AUlsZt9GjgFvABIRL9Hkn8KqNzOp+7Lw4QWtrwn20KzU3wqu1QoOj2m+7rKRqkA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz", + "integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.12.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "resolve": "^1.22.3", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-jest": { + "version": "27.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz", + "integrity": "sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0", + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-jest/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-plugin-jest/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-jest/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", + "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-4.0.1.tgz", + "integrity": "sha512-fUFcXpui/FftGx3NzvWgLZXlLbu+m74sUxGEgxgoxYcUtkIQbS6SdNNZkS99m5ycb23TfoNYrDpp1k/CK5j6Hw==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.37.0", + "jest-worker": "^29.5.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz", + "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.6.2", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.2.tgz", + "integrity": "sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.6.2", + "@types/node": "*", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-util": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz", + "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", + "integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.1.tgz", + "integrity": "sha512-lj9cnmB/kVS0QHsJnYKD1uo3o39nrbKxszjnqS9Fr6NB7bZzW45U6WSGBPKXDL/CvDKqDNPA4r3DoDQ8GTxo2A==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.2.tgz", + "integrity": "sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.6.2", + "@jest/types": "^29.6.1", + "import-local": "^3.0.2", + "jest-cli": "^29.6.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.2.tgz", + "integrity": "sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.6.2", + "@jest/expect": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.6.2", + "jest-matcher-utils": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-runtime": "^29.6.2", + "jest-snapshot": "^29.6.2", + "jest-util": "^29.6.2", + "p-limit": "^3.1.0", + "pretty-format": "^29.6.2", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-cli": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.2.tgz", + "integrity": "sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q==", + "dev": true, + "dependencies": { + "@jest/core": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/types": "^29.6.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.6.2", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.2.tgz", + "integrity": "sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.6.2", + "@jest/types": "^29.6.1", + "babel-jest": "^29.6.2", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.6.2", + "jest-environment-node": "^29.6.2", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.6.2", + "jest-runner": "^29.6.2", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.6.2", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.2.tgz", + "integrity": "sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.2.tgz", + "integrity": "sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.1", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.6.2", + "pretty-format": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.6.2.tgz", + "integrity": "sha512-7oa/+266AAEgkzae8i1awNEfTfjwawWKLpiw2XesZmaoVVj9u9t8JOYx18cG29rbPNtkUlZ8V4b5Jb36y/VxoQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.6.2", + "@jest/fake-timers": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.6.2", + "jest-util": "^29.6.2", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-node": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.2.tgz", + "integrity": "sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.6.2", + "@jest/fake-timers": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/node": "*", + "jest-mock": "^29.6.2", + "jest-util": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.2.tgz", + "integrity": "sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.1", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.6.2", + "jest-worker": "^29.6.2", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-haste-map/node_modules/jest-worker": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz", + "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.6.2", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz", + "integrity": "sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz", + "integrity": "sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.6.2", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.2.tgz", + "integrity": "sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.6.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.2.tgz", + "integrity": "sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.1", + "@types/node": "*", + "jest-util": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.2.tgz", + "integrity": "sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.2", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.6.2", + "jest-validate": "^29.6.2", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz", + "integrity": "sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.2.tgz", + "integrity": "sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w==", + "dev": true, + "dependencies": { + "@jest/console": "^29.6.2", + "@jest/environment": "^29.6.2", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.6.2", + "jest-haste-map": "^29.6.2", + "jest-leak-detector": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-resolve": "^29.6.2", + "jest-runtime": "^29.6.2", + "jest-util": "^29.6.2", + "jest-watcher": "^29.6.2", + "jest-worker": "^29.6.2", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz", + "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.6.2", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runner/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-runtime": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.2.tgz", + "integrity": "sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.6.2", + "@jest/fake-timers": "^29.6.2", + "@jest/globals": "^29.6.2", + "@jest/source-map": "^29.6.0", + "@jest/test-result": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-mock": "^29.6.2", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.6.2", + "jest-snapshot": "^29.6.2", + "jest-util": "^29.6.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.2.tgz", + "integrity": "sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.6.2", + "@jest/transform": "^29.6.2", + "@jest/types": "^29.6.1", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.6.2", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.6.2", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.6.2", + "jest-message-util": "^29.6.2", + "jest-util": "^29.6.2", + "natural-compare": "^1.4.0", + "pretty-format": "^29.6.2", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/jest-util": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.2.tgz", + "integrity": "sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.2.tgz", + "integrity": "sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.6.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.2.tgz", + "integrity": "sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.6.2", + "@jest/types": "^29.6.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.6.2", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jiti": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", + "integrity": "sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/lint-staged": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.3.tgz", + "integrity": "sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==", + "dev": true, + "dependencies": { + "chalk": "5.2.0", + "cli-truncate": "^3.1.0", + "commander": "^10.0.0", + "debug": "^4.3.4", + "execa": "^7.0.0", + "lilconfig": "2.1.0", + "listr2": "^5.0.7", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.3", + "pidtree": "^0.6.0", + "string-argv": "^0.3.1", + "yaml": "^2.2.2" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/lint-staged/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.8.tgz", + "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.19", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.8.0", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/listr2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.0.tgz", + "integrity": "sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", + "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-6.0.2.tgz", + "integrity": "sha512-IRuCwwAAQbgaLhxQdQcIIK0dCVXg3XDUnzgKD8iwdiYdwU4rMWRWyl/W9/0nA4ihVpq5pyALiHB2veBJ0292pw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-6.0.0.tgz", + "integrity": "sha512-kaWTgnhRKFtfMF8H0+NQBFxgr5CGg05WGe07Mc1ld6XHwwRWlqSbHOW0zwf+BtkBQpsdVUu7+gl9dtdvhWMedw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^3.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-9.0.2.tgz", + "integrity": "sha512-SfPjgr//VQ/DOCf80STIAsdAs7sbIbxATvVmd+Ec7JvR8onz9pjawhq3BJM3Pie40EE3TyB0P6hft16D33Nlyg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-9.0.0.tgz", + "integrity": "sha512-RmUFL+foS05AKglkEoqfx+KFdKRVmqUAxlHNz4jLqIi7046drIPyerdl4B6j/RA2BSP8FI8gJcHmLRrwJOMnHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-media": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-10.0.0.tgz", + "integrity": "sha512-NxDn7C6GJ7X8TsWOa8MbCdq9rLERRLcPfQSp856k1jzMreL8X9M6iWk35JjPRIb9IfRnVohmxAylDRx7n4Rv4g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^1.0.3", + "@csstools/css-parser-algorithms": "^2.3.0", + "@csstools/css-tokenizer": "^2.1.1", + "@csstools/media-query-list-parser": "^2.1.2" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-13.3.0.tgz", + "integrity": "sha512-q4VgtIKSy5+KcUvQ0WxTjDy9DZjQ5VCXAZ9+tT9+aPMbA0z6s2t1nMw0QHszru1ib5ElkXl9JUpYYU37VVUs7g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^1.0.4", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-7.1.4.tgz", + "integrity": "sha512-TU2xyUUBTlpiLnwyE2ZYMUIYB41MKMkBZ8X8ntkqRDQ8sdBLhFFsPgNcOliBd5+/zcK51C9hRnSE7hKUJMxQSw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/cascade-layer-name-parser": "^1.0.3", + "@csstools/css-parser-algorithms": "^2.3.0", + "@csstools/css-tokenizer": "^2.1.1", + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-8.0.0.tgz", + "integrity": "sha512-Oy5BBi0dWPwij/IA+yDYj+/OBMQ9EPqAzTHeSNUYrUWdll/PRJmcbiUj0MNcsBi681I1gcSTLvMERPaXzdbvJg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-5.0.0.tgz", + "integrity": "sha512-wR8npIkrIVUTicUpCWSSo1f/g7gAEIH70FMqCugY4m4j6TX4E0T2Q5rhfO0gqv00biBZdLyb+HkW8x6as+iJNQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^3.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-9.0.0.tgz", + "integrity": "sha512-zA4TbVaIaT8npZBEROhZmlc+GBKE8AELPHXE7i4TmIUEQhw/P/mSJfY9t6tBzpQ1rABeGtEOHYrW4SboQeONMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-8.0.0.tgz", + "integrity": "sha512-E7+J9nuQzZaA37D/MUZMX1K817RZGDab8qw6pFwzAkDd/QtlWJ9/WTKmzewNiuxzeq6WWY7ATiRePVoDKp+DnA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-5.0.0.tgz", + "integrity": "sha512-YjsEEL6890P7MCv6fch6Am1yq0EhQCJMXyT4LBohiu87+4/WqR7y5W3RIv53WdA901hhytgRvjlrAhibhW4qsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-6.0.0.tgz", + "integrity": "sha512-bg58QnJexFpPBU4IGPAugAPKV0FuFtX5rHYNSKVaV91TpHN7iwyEzz1bkIPCiSU5+BUN00e+3fV5KFrwIgRocw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-lab-function": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-6.0.1.tgz", + "integrity": "sha512-/Xl6JitDh7jWkcOLxrHcAlEaqkxyaG3g4iDMy5RyhNaiQPJ9Egf2+Mxp1W2qnH5jB2bj59f3RbdKmC6qx1IcXA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/css-color-parser": "^1.2.2", + "@csstools/css-parser-algorithms": "^2.3.1", + "@csstools/css-tokenizer": "^2.2.0", + "@csstools/postcss-progressive-custom-properties": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", + "dev": true, + "dependencies": { + "cosmiconfig": "^8.2.0", + "jiti": "^1.18.2", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/postcss-logical": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-7.0.0.tgz", + "integrity": "sha512-zYf3vHkoW82f5UZTEXChTJvH49Yl9X37axTZsJGxrCG2kOUwtaAoz9E7tqYg0lsIoJLybaL8fk/2mOi81zVIUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.0.0.tgz", + "integrity": "sha512-knqwW65kxssmyIFadRSimaiRyLVRd0MdwfabesKw6XvGLwSOCJ+4zfvNQQCOOYij5obwpZzDpODuGRv2PCyiUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-specificity": "^3.0.0", + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-2.0.0.tgz", + "integrity": "sha512-lyDrCOtntq5Y1JZpBFzIWm2wG9kbEdujpNt4NLannF+J9c8CgFIzPa80YQfdza+Y+yFfzbYj/rfoOsYsooUWTQ==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-5.0.0.tgz", + "integrity": "sha512-2rlxDyeSics/hC2FuMdPnWiP9WUPZ5x7FTuArXLFVpaSQ2woPSfZS4RD59HuEokbZhs/wPUQJ1E3MT6zVv94MQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-9.0.0.tgz", + "integrity": "sha512-qLEPD9VPH5opDVemwmRaujODF9nExn24VOC3ghgVLEvfYN7VZLwJHes0q/C9YR5hI2UC3VgBE8Wkdp1TxCXhtg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-9.1.0.tgz", + "integrity": "sha512-G+x9BD7jb9uHBB7o720emXV00CP+VdWeirJsHC5ERSpbTd2e6Xg7vHzT+a6UkxFyddALuV+Q8wJMgeTKaau+Pg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/postcss-cascade-layers": "^4.0.0", + "@csstools/postcss-color-function": "^3.0.1", + "@csstools/postcss-color-mix-function": "^2.0.1", + "@csstools/postcss-exponential-functions": "^1.0.0", + "@csstools/postcss-font-format-keywords": "^3.0.0", + "@csstools/postcss-gradients-interpolation-method": "^4.0.1", + "@csstools/postcss-hwb-function": "^3.0.1", + "@csstools/postcss-ic-unit": "^3.0.0", + "@csstools/postcss-is-pseudo-class": "^4.0.0", + "@csstools/postcss-logical-float-and-clear": "^2.0.0", + "@csstools/postcss-logical-resize": "^2.0.0", + "@csstools/postcss-logical-viewport-units": "^2.0.1", + "@csstools/postcss-media-minmax": "^1.0.6", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^2.0.1", + "@csstools/postcss-nested-calc": "^3.0.0", + "@csstools/postcss-normalize-display-values": "^3.0.0", + "@csstools/postcss-oklab-function": "^3.0.1", + "@csstools/postcss-progressive-custom-properties": "^3.0.0", + "@csstools/postcss-relative-color-syntax": "^2.0.1", + "@csstools/postcss-scope-pseudo-class": "^3.0.0", + "@csstools/postcss-stepped-value-functions": "^3.0.1", + "@csstools/postcss-text-decoration-shorthand": "^3.0.0", + "@csstools/postcss-trigonometric-functions": "^3.0.1", + "@csstools/postcss-unset-value": "^3.0.0", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.9", + "css-blank-pseudo": "^6.0.0", + "css-has-pseudo": "^6.0.0", + "css-prefers-color-scheme": "^9.0.0", + "cssdb": "^7.7.0", + "postcss-attribute-case-insensitive": "^6.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^6.0.0", + "postcss-color-hex-alpha": "^9.0.2", + "postcss-color-rebeccapurple": "^9.0.0", + "postcss-custom-media": "^10.0.0", + "postcss-custom-properties": "^13.3.0", + "postcss-custom-selectors": "^7.1.4", + "postcss-dir-pseudo-class": "^8.0.0", + "postcss-double-position-gradients": "^5.0.0", + "postcss-focus-visible": "^9.0.0", + "postcss-focus-within": "^8.0.0", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^5.0.0", + "postcss-image-set-function": "^6.0.0", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^6.0.1", + "postcss-logical": "^7.0.0", + "postcss-nesting": "^12.0.0", + "postcss-opacity-percentage": "^2.0.0", + "postcss-overflow-shorthand": "^5.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^9.0.0", + "postcss-pseudo-class-any-link": "^9.0.0", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^7.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-9.0.0.tgz", + "integrity": "sha512-QNCYIL98VKFKY6HGDEJpF6+K/sg9bxcUYnOmNHJxZS5wsFDFaVoPeG68WAuhsqwbIBSo/b9fjEnTwY2mTSD+uA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.0.13" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-7.0.1.tgz", + "integrity": "sha512-1zT5C27b/zeJhchN7fP0kBr16Cc61mu7Si9uWWLoA3Px/D9tIJPKchJCkUH3tPO5D0pCFmGeApAv8XpXBQJ8SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz", + "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", + "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.12.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sass": { + "version": "1.64.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.2.tgz", + "integrity": "sha512-TnDlfc+CRnUAgLO9D8cQLFu/GIjJIzJCGkE7o4ekIGQOH7T3GetiRR/PsTWJUHhkzcSPrARkPI+gNWn5alCzDg==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", + "dev": true, + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swiper": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-10.2.0.tgz", + "integrity": "sha512-nktQsOtBInJjr3f5DicxC8eHYGcLXDVIGPSon0QoXRaO6NjKnATCbQ8SZsD3dN1Ph1RH4EhVPwSYCcuDRFWHGQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "engines": { + "node": ">= 4.7.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toastify-js": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", + "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/ts-loader": { + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", + "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "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" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json index 7cfe95f..c1fc635 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,58 @@ "description": "this-is-this-team", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "start": "webpack serve", + "build:dev": "webpack --node-env=development", + "build:prod": "webpack --node-env=production", + "lint:check": "eslint .", + "lint:fix": "eslint . --fix", + "prettier:check": "prettier . --check", + "prettier:fix": "prettier . --write", + "test": "jest", + "prepare": "husky install" }, "author": "", - "license": "ISC" + "license": "ISC", + "devDependencies": { + "@babel/core": "^7.22.9", + "@babel/preset-env": "^7.22.9", + "@types/jest": "^29.5.3", + "@types/node-fetch": "^2.6.4", + "@types/toastify-js": "^1.12.0", + "@typescript-eslint/eslint-plugin": "^6.2.1", + "babel-loader": "^9.1.3", + "css-loader": "^6.8.1", + "dotenv-webpack": "^8.0.1", + "eslint": "^8.46.0", + "eslint-config-prettier": "^8.9.0", + "eslint-plugin-import": "^2.28.0", + "eslint-plugin-jest": "^27.2.3", + "eslint-plugin-prettier": "^5.0.0", + "eslint-webpack-plugin": "^4.0.1", + "html-webpack-plugin": "^5.5.3", + "husky": "^8.0.3", + "jest": "^29.6.2", + "jest-environment-jsdom": "^29.6.2", + "lint-staged": "^13.2.3", + "mini-css-extract-plugin": "^2.7.6", + "postcss": "^8.4.27", + "postcss-loader": "^7.3.3", + "postcss-preset-env": "^9.1.0", + "prettier": "^3.0.0", + "sass": "^1.64.2", + "sass-loader": "^13.3.2", + "style-loader": "^3.3.3", + "ts-jest": "^29.1.1", + "ts-loader": "^9.4.4", + "typescript": "^5.1.6", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + }, + "dependencies": { + "@commercetools/platform-sdk": "^4.11.0", + "@commercetools/sdk-client-v2": "^2.2.0", + "swiper": "^10.2.0", + "toastify-js": "^1.12.0" + } } diff --git a/src/assets/favicon.png b/src/assets/favicon.png new file mode 100644 index 0000000..45074d5 Binary files /dev/null and b/src/assets/favicon.png differ diff --git a/src/assets/icons/account-icon.svg b/src/assets/icons/account-icon.svg new file mode 100644 index 0000000..aec8ebb --- /dev/null +++ b/src/assets/icons/account-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/icons/bag-icon.svg b/src/assets/icons/bag-icon.svg new file mode 100644 index 0000000..67a5261 --- /dev/null +++ b/src/assets/icons/bag-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/cart-icon.svg b/src/assets/icons/cart-icon.svg new file mode 100644 index 0000000..e1223e7 --- /dev/null +++ b/src/assets/icons/cart-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/cart-trash-icon.svg b/src/assets/icons/cart-trash-icon.svg new file mode 100644 index 0000000..8e9c782 --- /dev/null +++ b/src/assets/icons/cart-trash-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/change-password-icon.svg b/src/assets/icons/change-password-icon.svg new file mode 100644 index 0000000..8ba5d88 --- /dev/null +++ b/src/assets/icons/change-password-icon.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/check.svg b/src/assets/icons/check.svg new file mode 100644 index 0000000..6f86b8d --- /dev/null +++ b/src/assets/icons/check.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/chevron-up.svg b/src/assets/icons/chevron-up.svg new file mode 100644 index 0000000..1acd021 --- /dev/null +++ b/src/assets/icons/chevron-up.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/create-account-icon.svg b/src/assets/icons/create-account-icon.svg new file mode 100644 index 0000000..20c5927 --- /dev/null +++ b/src/assets/icons/create-account-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/empty-addresses-book.svg b/src/assets/icons/empty-addresses-book.svg new file mode 100644 index 0000000..2b25c72 --- /dev/null +++ b/src/assets/icons/empty-addresses-book.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/github-profile-icon.svg b/src/assets/icons/github-profile-icon.svg new file mode 100644 index 0000000..35b02e5 --- /dev/null +++ b/src/assets/icons/github-profile-icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/assets/icons/link-arrow.svg b/src/assets/icons/link-arrow.svg new file mode 100644 index 0000000..e056de3 --- /dev/null +++ b/src/assets/icons/link-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/logout-icon.svg b/src/assets/icons/logout-icon.svg new file mode 100644 index 0000000..8112b50 --- /dev/null +++ b/src/assets/icons/logout-icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/assets/icons/popup-close-icon.svg b/src/assets/icons/popup-close-icon.svg new file mode 100644 index 0000000..f4242aa --- /dev/null +++ b/src/assets/icons/popup-close-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/quote-icon.svg b/src/assets/icons/quote-icon.svg new file mode 100644 index 0000000..71c7a9b --- /dev/null +++ b/src/assets/icons/quote-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/rsschool-icon-active.svg b/src/assets/icons/rsschool-icon-active.svg new file mode 100644 index 0000000..ff5edc6 --- /dev/null +++ b/src/assets/icons/rsschool-icon-active.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/rsschool-icon.svg b/src/assets/icons/rsschool-icon.svg new file mode 100644 index 0000000..ef8175f --- /dev/null +++ b/src/assets/icons/rsschool-icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/spinner-icon.svg b/src/assets/icons/spinner-icon.svg new file mode 100644 index 0000000..94ef831 --- /dev/null +++ b/src/assets/icons/spinner-icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/icons/star-icon.svg b/src/assets/icons/star-icon.svg new file mode 100644 index 0000000..6a62140 --- /dev/null +++ b/src/assets/icons/star-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/star.svg b/src/assets/icons/star.svg new file mode 100644 index 0000000..1ea437e --- /dev/null +++ b/src/assets/icons/star.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/success-icon.svg b/src/assets/icons/success-icon.svg new file mode 100644 index 0000000..ea65186 --- /dev/null +++ b/src/assets/icons/success-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assets/icons/visibility-off.svg b/src/assets/icons/visibility-off.svg new file mode 100644 index 0000000..62be473 --- /dev/null +++ b/src/assets/icons/visibility-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/visibility.svg b/src/assets/icons/visibility.svg new file mode 100644 index 0000000..28d3a2e --- /dev/null +++ b/src/assets/icons/visibility.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/banner_discover-world.jpg b/src/assets/img/banner_discover-world.jpg new file mode 100644 index 0000000..054361a Binary files /dev/null and b/src/assets/img/banner_discover-world.jpg differ diff --git a/src/assets/img/main_hero-image.jpg b/src/assets/img/main_hero-image.jpg new file mode 100644 index 0000000..a61b86c Binary files /dev/null and b/src/assets/img/main_hero-image.jpg differ diff --git a/src/assets/img/placeholder-image.svg b/src/assets/img/placeholder-image.svg new file mode 100644 index 0000000..d2e692d --- /dev/null +++ b/src/assets/img/placeholder-image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/img/promo-codes/CRUISE100.jpg b/src/assets/img/promo-codes/CRUISE100.jpg new file mode 100644 index 0000000..d5ae2e6 Binary files /dev/null and b/src/assets/img/promo-codes/CRUISE100.jpg differ diff --git a/src/assets/img/promo-codes/FAMILYFUN.jpg b/src/assets/img/promo-codes/FAMILYFUN.jpg new file mode 100644 index 0000000..abd464e Binary files /dev/null and b/src/assets/img/promo-codes/FAMILYFUN.jpg differ diff --git a/src/assets/img/promo-codes/GROUP24.jpg b/src/assets/img/promo-codes/GROUP24.jpg new file mode 100644 index 0000000..d94c4ae Binary files /dev/null and b/src/assets/img/promo-codes/GROUP24.jpg differ diff --git a/src/assets/img/promo-codes/LASTCHANCE.jpg b/src/assets/img/promo-codes/LASTCHANCE.jpg new file mode 100644 index 0000000..c8f028f Binary files /dev/null and b/src/assets/img/promo-codes/LASTCHANCE.jpg differ diff --git a/src/assets/img/shop_hero-image.jpg b/src/assets/img/shop_hero-image.jpg new file mode 100644 index 0000000..8f7f0d5 Binary files /dev/null and b/src/assets/img/shop_hero-image.jpg differ diff --git a/src/assets/img/shop_hero-image_africa.jpg b/src/assets/img/shop_hero-image_africa.jpg new file mode 100644 index 0000000..c805c68 Binary files /dev/null and b/src/assets/img/shop_hero-image_africa.jpg differ diff --git a/src/assets/img/shop_hero-image_america.jpg b/src/assets/img/shop_hero-image_america.jpg new file mode 100644 index 0000000..035dbb1 Binary files /dev/null and b/src/assets/img/shop_hero-image_america.jpg differ diff --git a/src/assets/img/shop_hero-image_asia.jpg b/src/assets/img/shop_hero-image_asia.jpg new file mode 100644 index 0000000..bdf16ac Binary files /dev/null and b/src/assets/img/shop_hero-image_asia.jpg differ diff --git a/src/assets/img/shop_hero-image_europe.jpg b/src/assets/img/shop_hero-image_europe.jpg new file mode 100644 index 0000000..2af8a06 Binary files /dev/null and b/src/assets/img/shop_hero-image_europe.jpg differ diff --git a/src/assets/img/shop_hero-image_hiking.jpg b/src/assets/img/shop_hero-image_hiking.jpg new file mode 100644 index 0000000..5b406cb Binary files /dev/null and b/src/assets/img/shop_hero-image_hiking.jpg differ diff --git a/src/assets/img/shop_hero-image_sailing.jpg b/src/assets/img/shop_hero-image_sailing.jpg new file mode 100644 index 0000000..e8f08dd Binary files /dev/null and b/src/assets/img/shop_hero-image_sailing.jpg differ diff --git a/src/assets/img/team-members/andrew.jfif b/src/assets/img/team-members/andrew.jfif new file mode 100644 index 0000000..6ea3134 Binary files /dev/null and b/src/assets/img/team-members/andrew.jfif differ diff --git a/src/assets/img/team-members/maksim.png b/src/assets/img/team-members/maksim.png new file mode 100644 index 0000000..5cee598 Binary files /dev/null and b/src/assets/img/team-members/maksim.png differ diff --git a/src/assets/img/team-members/yauheni.jfif b/src/assets/img/team-members/yauheni.jfif new file mode 100644 index 0000000..81e3310 Binary files /dev/null and b/src/assets/img/team-members/yauheni.jfif differ diff --git a/src/components/about-us/about-us-collaboration.ts b/src/components/about-us/about-us-collaboration.ts new file mode 100644 index 0000000..878085b --- /dev/null +++ b/src/components/about-us/about-us-collaboration.ts @@ -0,0 +1,51 @@ +import BaseComponent from '../base-component'; +import aboutUsMethods from '../../constants/aboutUsMethods'; +import './about-us.scss'; + +export default class AboutUsCollaboration extends BaseComponent<'section'> { + constructor() { + super('section', ['about-us-collaboration']); + this.renderAboutUsCollaboration(); + } + + private renderAboutUsCollaboration = (): void => { + const title = new BaseComponent('h2', ['about-us-collaboration__title'], 'Collaboration').getElement(); + const blockquote = new BaseComponent('blockquote', ['about-us-collaboration__blockquote']).getElement(); + blockquote.insertAdjacentHTML( + 'afterbegin', + ` +

Great things in business are never done alone, they’re done by a team.

+ + ` + ); + + const methods = new BaseComponent('div', ['about-us-methods']).getElement(); + const methodsTitle = new BaseComponent( + 'h4', + ['about-us-methods__title'], + 'Our effective collaboration methods:' + ).getElement(); + const methodsWrapp = new BaseComponent('ul', ['about-us-methods__list']).getElement(); + + aboutUsMethods.forEach((obj, index) => { + const methodsItem = new BaseComponent('li', ['about-us-methods-item']).getElement(); + const methodsItemIndex = new BaseComponent( + 'span', + ['about-us-methods-item__index'], + String(index + 1) + ).getElement(); + const methodsItemTextWrapp = new BaseComponent('div', ['about-us-methods-item-wrapp']).getElement(); + const methodsItemTitle = new BaseComponent('p', ['about-us-methods-item__title'], obj.title).getElement(); + const methodsItemDescr = new BaseComponent('p', ['about-us-methods-item__descr'], obj.description).getElement(); + + methodsItemTextWrapp.append(methodsItemTitle, methodsItemDescr); + methodsItem.append(methodsItemIndex, methodsItemTextWrapp); + + methodsWrapp.append(methodsItem); + }); + + methods.append(methodsTitle, methodsWrapp); + + this.node.append(title, blockquote, methods); + }; +} diff --git a/src/components/about-us/about-us-list.ts b/src/components/about-us/about-us-list.ts new file mode 100644 index 0000000..40eb171 --- /dev/null +++ b/src/components/about-us/about-us-list.ts @@ -0,0 +1,15 @@ +import aboutUsMembers from '../../constants/aboutUsMembers'; +import BaseComponent from '../base-component'; +import AboutUsMember from './about-us-member'; +import './about-us.scss'; + +export default class AboutUsList extends BaseComponent<'section'> { + constructor() { + super('section', ['about-us-list']); + this.renderAboutUsList(); + } + + private renderAboutUsList = (): void => { + aboutUsMembers.forEach((obj) => this.node.append(new AboutUsMember(obj).getElement())); + }; +} diff --git a/src/components/about-us/about-us-member.ts b/src/components/about-us/about-us-member.ts new file mode 100644 index 0000000..06a37ba --- /dev/null +++ b/src/components/about-us/about-us-member.ts @@ -0,0 +1,43 @@ +import BaseComponent from '../base-component'; +import { IAboutUsMember } from '../../types/interfaces'; +import './about-us.scss'; + +export default class AboutUsMember extends BaseComponent<'div'> { + constructor(member: IAboutUsMember) { + super('div', ['about-us-member']); + this.renderAboutUsMember(member); + } + + private renderAboutUsMember = (member: IAboutUsMember): void => { + const memberHeader = new BaseComponent('div', ['about-us-member__header']).getElement(); + const memberHeaderImg = new BaseComponent('div', ['about-us-member__img', member.imgClass]).getElement(); + const memberHeaderWrapp = new BaseComponent('div', ['about-us-member__header-wrapp']).getElement(); + const memberHeaderName = new BaseComponent('h3', ['about-us-member__title'], member.name).getElement(); + const memberHeaderRole = new BaseComponent('p', ['about-us-member__role'], member.role).getElement(); + memberHeaderWrapp.append(memberHeaderName, memberHeaderRole); + memberHeader.append(memberHeaderImg, memberHeaderWrapp); + + const memberAbout = new BaseComponent('div', ['about-us-member__about']).getElement(); + const memberAboutLabel = new BaseComponent('span', ['about-us-member__label'], 'About').getElement(); + const memberAboutText = new BaseComponent('p', ['about-us-member__text'], member.about).getElement(); + memberAbout.append(memberAboutLabel, memberAboutText); + + const memberContributions = new BaseComponent('div', ['about-us-member__contributions']).getElement(); + const memberContributionsLabel = new BaseComponent( + 'span', + ['about-us-member__label'], + 'Contributions' + ).getElement(); + const memberContributionsList = new BaseComponent('ul', ['about-us-member__contributions-list']).getElement(); + member.contributions.forEach((contribution) => { + memberContributionsList.append(new BaseComponent('li', [], contribution).getElement()); + }); + memberContributions.append(memberContributionsLabel, memberContributionsList); + + const memberGithubLink = new BaseComponent('a', ['about-us-member__link'], 'GitHub Profile').getElement(); + memberGithubLink.href = member.link; + memberGithubLink.target = '_blank'; + + this.node.append(memberHeader, memberAbout, memberContributions, memberGithubLink); + }; +} diff --git a/src/components/about-us/about-us-rsschool-link.ts b/src/components/about-us/about-us-rsschool-link.ts new file mode 100644 index 0000000..7446570 --- /dev/null +++ b/src/components/about-us/about-us-rsschool-link.ts @@ -0,0 +1,23 @@ +import BaseComponent from '../base-component'; +import './about-us.scss'; + +export default class AboutUsRSSchool extends BaseComponent<'div'> { + constructor() { + super('div', ['about-us-rsschool']); + this.renderAboutUsRsschool(); + } + + private renderAboutUsRsschool(): void { + const rsschoolLink = new BaseComponent('a', ['about-us-rsschool__link']).getElement(); + rsschoolLink.href = 'https://rs.school/js/'; + rsschoolLink.target = '_blank'; + + const rsschoolText = new BaseComponent( + 'h4', + ['about-us-rsschool__text'], + 'The project is being developed as part of the final task of the course JavaScript/Front-end (2023Q1) from the RS School.' + ).getElement(); + + this.node.append(rsschoolLink, rsschoolText); + } +} diff --git a/src/components/about-us/about-us.scss b/src/components/about-us/about-us.scss new file mode 100644 index 0000000..ee93f1a --- /dev/null +++ b/src/components/about-us/about-us.scss @@ -0,0 +1,318 @@ +.about-us { + &-list { + margin: 48px 0 104px 0; + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 24px; + gap: 24px; + + @include pre-tablet { + grid-template-columns: repeat(1, 1fr); + } + + @include mobile { + margin: 30px 0 60px 0; + } + } + + &-member { + padding: 32px; + display: flex; + flex-direction: column; + align-items: flex-start; + //justify-content: space-between; + gap: 32px; + border-radius: 8px; + background: $color-bg-light; + + @include pre-tablet { + gap: 24px; + } + + @include small-mobile { + padding: 16px; + gap: 16px; + } + + &__header { + width: 100%; + display: flex; + align-items: center; + gap: 20px; + padding-bottom: 32px; + border-bottom: 2px solid rgba($color-primary, 0.08); + + @include pre-tablet { + padding-bottom: 24px; + } + + @include small-mobile { + padding-bottom: 16px; + } + } + + &__img { + min-width: 96px; + height: 96px; + border-radius: 100%; + background-color: #fff; + background-image: url('../../assets/img/placeholder-image.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + overflow: hidden; + + @include small-mobile { + min-width: 60px; + height: 60px; + } + + &.andrew { + background-image: url('../../assets/img/team-members/andrew.jfif'); + } + &.yauheni { + background-image: url('../../assets/img/team-members/yauheni.jfif'); + } + &.maksim { + background-image: url('../../assets/img/team-members/maksim.png'); + } + } + + &__header-wrapp { + display: flex; + flex-direction: column; + } + + &__title { + @include font-h4; + } + + &__role { + font: $font-label; + + @include small-mobile { + font-size: 12px; + } + } + + &__label { + display: inline-block; + margin-bottom: 12px; + font: $font-about-label; + letter-spacing: 1.1px; + text-transform: uppercase; + + @include small-mobile { + margin-bottom: 8px; + } + } + + &__text { + @include small-mobile { + font-size: 14px; + } + } + + &__link { + margin-top: auto; + display: flex; + align-items: center; + gap: 4px; + position: relative; + font: $font-button; + color: $color-button; + transition: all 0.3s ease-in-out; + + &::after { + content: ''; + width: 20px; + height: 20px; + background-image: url('../../assets/icons/github-profile-icon.svg'); + } + + &::before { + content: ''; + position: absolute; + width: 0; + height: 1px; + background: $color-button; + left: 0; + bottom: -4px; + transition: width 0.2s ease-in-out; + } + + &:not(:disabled):hover, + &:not(:disabled):active { + &::before { + width: 100%; + } + } + } + + &__contributions-list { + margin-left: 16px; + + & li { + list-style: disc; + margin-bottom: 8px; + + @include small-mobile { + font-size: 14px; + margin-bottom: 4px; + } + } + } + } + + &-collaboration { + padding: 104px 0; + border-top: 1px solid $color-border; + border-bottom: 1px solid $color-border; + + @include mobile { + padding-top: 60px; + margin-bottom: 60px; + } + + &__title { + @include font-h1; + } + + &__blockquote { + margin-top: 48px; + width: fit-content; + padding: 64px; + background: $color-bg-light; + border-radius: 8px; + position: relative; + + @include tablet { + padding: 40px; + } + + & p { + @include font-h2; + } + + & footer { + margin-top: 40px; + font: $font-button; + + @include tablet { + margin-top: 20px; + } + } + + &::before { + content: ''; + display: block; + width: 36px; + height: 32px; + background-image: url('../../assets/icons/quote-icon.svg'); + background-position: center; + background-size: cover; + margin-bottom: 20px; + + @include tablet { + width: 27px; + height: 24px; + } + } + } + } + + &-methods { + margin-top: 48px; + + &__title { + @include font-h2; + } + + &__list { + margin-top: 48px; + } + + &-item { + display: flex; + margin-bottom: 40px; + + &__index { + margin-right: 20px; + display: flex; + align-items: center; + justify-content: center; + min-width: 40px; + height: 40px; + border-radius: 100%; + background: $color-button; + color: $color-white; + } + + &__title { + @include font-h4; + margin-bottom: 10px; + } + + &__descr { + max-width: 1000px; + @include small-mobile { + font-size: 14px; + } + } + } + } + + &-rsschool { + padding: 104px 0; + display: flex; + align-items: center; + + @include pre-tablet { + flex-direction: column; + align-items: flex-start; + } + + @include mobile { + padding: 40px 32px; + margin-bottom: 60px; + } + + &__link { + display: block; + min-width: 220px; + height: 80px; + background-image: url('../../assets/icons/rsschool-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + transition: all 0.3s ease; + + &:hover { + background-image: url('../../assets/icons/rsschool-icon-active.svg'); + } + + @include pre-tablet { + margin-bottom: 40px; + } + + @include small-mobile { + min-width: 135px; + height: 50px; + } + } + + &__text { + max-width: 1300px; + margin: 0 0 0 40px; + padding: 0 0 0 40px; + @include font-h2; + border-left: 1.5px solid rgba($color-primary, 0.12); + + @include pre-tablet { + margin: 0; + padding: 0; + border: none; + } + } + } +} diff --git a/src/components/account/account-addresses/account-addresses.scss b/src/components/account/account-addresses/account-addresses.scss new file mode 100644 index 0000000..0ee25a9 --- /dev/null +++ b/src/components/account/account-addresses/account-addresses.scss @@ -0,0 +1,68 @@ +.account-addresses { + &__title { + @include font-h3; + } + + &__wrapp { + margin-top: 24px; + padding: 32px; + display: flex; + flex-direction: column; + background: $color-bg-card; + border-radius: 8px; + + @include tablet { + margin-top: 8px; + } + + @include small-mobile { + padding: 24px; + } + + &.centered { + align-items: center; + } + } + + &__view-btn { + margin-top: 32px; + max-width: fit-content; + } + + &__add-btn { + margin-top: 24px; + max-width: fit-content; + } + + &__item { + margin-top: 10px; + + &:first-child { + margin-top: 0; + } + } + + &-empty { + &__img { + width: 40px; + height: 40px; + background-image: url('../../../assets/icons/empty-addresses-book.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + + &__title { + margin-top: 16px; + text-align: center; + @include font-h4; + } + + &__descr { + margin-top: 8px; + max-width: 338px; + text-align: center; + font-size: 15px; + } + } +} diff --git a/src/components/account/account-addresses/account-addresses.ts b/src/components/account/account-addresses/account-addresses.ts new file mode 100644 index 0000000..5a2c0a1 --- /dev/null +++ b/src/components/account/account-addresses/account-addresses.ts @@ -0,0 +1,75 @@ +import BaseComponent from '../../base-component'; +import userStore from '../../../store/user-store'; +import Button from '../../button/button'; +import { changeUrlEvent } from '../../../utils/change-url-event'; +import './account-addresses.scss'; +import { AppRoutesPath } from '../../../router/types'; +import Sup from '../../sup/sup'; + +export default class AccountAddresses extends BaseComponent<'div'> { + private detailsTitle: HTMLElement; + + constructor() { + super('div', ['account-addresses']); + + this.detailsTitle = new BaseComponent('h3', ['account-addresses__title'], 'Address Book').getElement(); + + this.node.append(this.detailsTitle, this.addressBookInfo()); + } + + private addressBookInfo(): HTMLElement { + const { customer } = userStore.getState(); + + const defaultBillingAddressId = customer?.defaultBillingAddressId; + const defaultShippingAddressId = customer?.defaultShippingAddressId; + + const addressesWrapp = new BaseComponent('div', ['account-addresses__wrapp']).getElement(); + + if (customer && customer?.addresses.length > 0) { + customer?.addresses.forEach((address) => { + const addressElementText = `${address.streetName}, ${address.city}, ${address.postalCode} ${address.country}`; + const addressElement = new BaseComponent('p', ['account-addresses__item'], addressElementText).getElement(); + + if (address.id === defaultBillingAddressId) { + addressElement.append(new Sup('Default Billing').getElement()); + } + if (address.id === defaultShippingAddressId) { + addressElement.append(new Sup('Default Shipping').getElement()); + } + + addressesWrapp.append(addressElement); + }); + + const viewAddressesBtn = new Button( + 'button', + `View Addresses (${customer.addresses.length})`, + ['account-addresses__view-btn'], + false, + () => changeUrlEvent(AppRoutesPath.ACCOUNT_ADDRESSES) + ).getElement(); + + addressesWrapp.append(viewAddressesBtn); + } else { + const addressEmptyImg = new BaseComponent('span', ['account-addresses-empty__img']).getElement(); + const addressEmptyTitle = new BaseComponent( + 'h4', + ['account-addresses-empty__title'], + 'Your Address Book is Empty' + ).getElement(); + const addressEmptyDescr = new BaseComponent( + 'p', + ['account-addresses-empty__descr'], + 'Investor focus research & development value proposition graphical user interface investor. ' + ).getElement(); + + const addAddressesBtn = new Button('button', `Add Address`, ['account-addresses__add-btn'], false, () => + changeUrlEvent(AppRoutesPath.ACCOUNT_ADDRESSES) + ).getElement(); + + addressesWrapp.classList.add('centered'); + addressesWrapp.append(addressEmptyImg, addressEmptyTitle, addressEmptyDescr, addAddressesBtn); + } + + return addressesWrapp; + } +} diff --git a/src/components/account/account-details/account-details.scss b/src/components/account/account-details/account-details.scss new file mode 100644 index 0000000..5562f0c --- /dev/null +++ b/src/components/account/account-details/account-details.scss @@ -0,0 +1,27 @@ +.account-details { + &__title { + @include font-h3; + } + + &__wrapp { + margin-top: 24px; + padding: 32px; + display: flex; + flex-direction: column; + background: $color-bg-card; + border-radius: 8px; + + @include tablet { + margin-top: 8px; + } + + @include small-mobile { + padding: 24px; + } + } + + &__edit-btn { + margin-top: 32px; + max-width: fit-content; + } +} diff --git a/src/components/account/account-details/account-details.ts b/src/components/account/account-details/account-details.ts new file mode 100644 index 0000000..4024148 --- /dev/null +++ b/src/components/account/account-details/account-details.ts @@ -0,0 +1,54 @@ +import BaseComponent from '../../base-component'; +import Button from '../../button/button'; +import List from '../../list/list'; +import DetailsForm from '../../form/details-form'; +import userStore from '../../../store/user-store'; +import { ListDataType } from '../../../types/types'; +import { AccountInfoMode } from '../../../types/enums'; +import './account-details.scss'; + +export default class AccountDetails extends BaseComponent<'div'> { + private mode: AccountInfoMode; + private detailsTitle: HTMLElement; + private detailsWrapp: HTMLElement; + + constructor(mode: AccountInfoMode, onChange: () => void = () => {}) { + super('div', ['account-details']); + + this.mode = mode; + this.detailsTitle = new BaseComponent('h3', ['account-details__title'], 'Account Details').getElement(); + this.detailsWrapp = new BaseComponent('div', ['account-details__wrapp']).getElement(); + + this.createDetailsList(onChange); + + this.node.append(this.detailsTitle, this.detailsWrapp); + } + + private createDetailsList(onChange: () => void = () => {}): void { + const { customer } = userStore.getState(); + + if (this.mode === AccountInfoMode.SHOW) { + const buttonEdit = new Button( + 'button', + 'Edit account details', + ['account-details__edit-btn'], + false, + onChange + ).getElement(); + + const listObj: ListDataType = { + 'First Name': customer?.firstName || '', + 'Last Name': customer?.lastName || '', + 'Birth Date': customer?.dateOfBirth || '', + 'Email ': customer?.email || '', + 'Password ': `● ● ● ● ● ● ●`, + }; + + const listOfLiElements = customer ? new List(listObj).getElement() : ''; + + this.detailsWrapp.append(listOfLiElements, buttonEdit); + } else { + this.detailsWrapp.append(new DetailsForm(onChange).getElement()); + } + } +} diff --git a/src/components/address/address.scss b/src/components/address/address.scss new file mode 100644 index 0000000..8376dcb --- /dev/null +++ b/src/components/address/address.scss @@ -0,0 +1,28 @@ +.address { + max-width: 828px; + margin-top: 24px; + padding: 32px; + display: flex; + flex-direction: column; + border-radius: 8px; + background: $color-bg-card; + + @include small-mobile { + padding: 24px; + } + + &__sups { + margin: 0 0 16px -3px; + } + + &__actions { + margin-top: 32px; + display: flex; + align-items: center; + gap: 24px; + + @include mobile { + flex-direction: column; + } + } +} diff --git a/src/components/address/address.ts b/src/components/address/address.ts new file mode 100644 index 0000000..6b0035a --- /dev/null +++ b/src/components/address/address.ts @@ -0,0 +1,94 @@ +import BaseComponent from '../base-component'; +import List from '../list/list'; +import Button from '../button/button'; +import Sup from '../sup/sup'; +import AddressForm from '../form/address-form'; +import { AddressesMode } from '../../types/enums'; +import { IAddressData } from '../../types/interfaces'; +import './address.scss'; + +export default class Address extends BaseComponent<'div'> { + private mode: AddressesMode; + private addressData: IAddressData | null; + private firstBtnAction: (type: AddressesMode) => void; + private secondBtnAction: (id: string) => void; + + constructor( + mode: AddressesMode, + addressData: IAddressData | null, + firstCallback: (type: AddressesMode) => void, + secondCallback: (id: string) => void + ) { + super('div', ['address']); + + this.mode = mode; + this.addressData = addressData; + this.firstBtnAction = firstCallback; + this.secondBtnAction = secondCallback; + + if (mode === AddressesMode.NEW) { + this.renderNewAddress(); + } else { + this.renderAddress(); + } + } + + private renderNewAddress = (): void => { + const form = new AddressForm(this.firstBtnAction, this.secondBtnAction).getElement(); + this.node.append(form); + }; + + private renderAddress = (): void => { + const data = this.addressData; + + this.node.innerHTML = ''; + + if (this.mode === AddressesMode.SHOW) { + const defaultsWrapp = new BaseComponent('div', ['address__sups']).getElement(); + + if (data?.defaultBillingAddressId || data?.defaultShippingAddressId) { + const defaultBilling = + data?.defaultBillingAddressId === data?.address.id ? new Sup('Default Billing').getElement() : ''; + const defaultShipping = + data?.defaultShippingAddressId === data?.address.id ? new Sup('Default Shipping').getElement() : ''; + + defaultsWrapp.append(defaultBilling, defaultShipping); + } + + const type: string[] = []; + + if (data?.billingAddressIds?.includes(data?.address.id || '')) type.push('Billing'); + if (data?.shippingAddressIds?.includes(data?.address.id || '')) type.push('Shipping'); + + const listObj = { + 'Type ': `${type.join(', ')}`, + 'Street ': data?.address?.streetName || '', + 'City ': data?.address?.city || '', + 'Postcode ': data?.address?.postalCode || '', + 'Country ': data?.address?.country || '', + }; + + const list = new List(listObj).getElement(); + + const buttonWrapp = new BaseComponent('div', ['address__actions']).getElement(); + const buttonSubmit = new Button('submit', 'Edit Address', [], false, this.changeMode).getElement(); + const buttonCancel = new Button('button', 'Remove Address', ['button--cancel'], false, () => + this.secondBtnAction(data?.address?.id || '') + ).getElement(); + + buttonWrapp.append(buttonSubmit, buttonCancel); + + if (defaultsWrapp.childElementCount > 0) this.node.append(defaultsWrapp); + + this.node.append(list, buttonWrapp); + } else { + this.node.append(new AddressForm(this.firstBtnAction, this.changeMode, this.addressData).getElement()); + } + }; + + private changeMode = (): void => { + this.mode = this.mode === AddressesMode.SHOW ? AddressesMode.EDIT : AddressesMode.SHOW; + this.firstBtnAction(this.mode); + this.renderAddress(); + }; +} diff --git a/src/components/banner/banner.scss b/src/components/banner/banner.scss new file mode 100644 index 0000000..d2e7031 --- /dev/null +++ b/src/components/banner/banner.scss @@ -0,0 +1,66 @@ +.banner { + width: 100%; + height: 680px; + color: $color-white; + background-image: url('../../assets/img/banner_discover-world.jpg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + + @include tablet { + height: 540px; + } + + &--main-page { + height: calc(100dvh - 80px); + background-image: url('../../assets/img/main_hero-image.jpg'); + } + + &__container { + @include container; + height: 100%; + } + + &__content { + max-width: 840px; + height: 100%; + display: flex; + flex-direction: column; + padding-top: 250px; + + @include tablet { + padding-top: 200px; + } + + @include mobile { + padding-top: 120px; + } + + .banner--main-page & { + justify-content: flex-end; + padding: 120px 0; + + @include tablet { + padding: 80px 0; + } + + @include mobile { + padding: 40px 0; + } + } + } + + &__title { + @include font-h1; + margin-bottom: 24px; + } + + &__text { + font: $font-subtitle; + margin-bottom: 32px; + + @include tablet { + font-size: 16px; + } + } +} diff --git a/src/components/banner/banner.test.ts b/src/components/banner/banner.test.ts new file mode 100644 index 0000000..3ca4baa --- /dev/null +++ b/src/components/banner/banner.test.ts @@ -0,0 +1,44 @@ +import Banner from './banner'; + +describe('Banner', () => { + it('should render banner with correct title and text', () => { + const title = 'Test Title'; + const text = 'Test Text'; + + const banner = new Banner(title, text).getElement(); + const bannerTitle: HTMLElement | null = banner.querySelector('.banner__title'); + const bannerText: HTMLElement | null = banner.querySelector('.banner__text'); + + expect(bannerTitle?.textContent).toBe(title); + expect(bannerText?.textContent).toBe(text); + }); + + it('should have the correct class names', () => { + const banner = new Banner('Title', 'Text', ['test-class']).getElement(); + + expect(banner.classList.contains('test-class')).toBe(true); + }); + + it('should create a banner with no additional class if none provided', () => { + const banner = new Banner('Title', 'Text').getElement(); + + expect(banner.classList.length).toBe(1); + }); + + it('should call the button click handler when clicked', () => { + const banner = new Banner('Title', 'Text').getElement(); + const bannerButton: HTMLButtonElement | null = banner.querySelector('.button--white'); + const buttonClickSpy = jest.spyOn(bannerButton!, 'click'); + + bannerButton?.click(); + + expect(buttonClickSpy).toHaveBeenCalled(); + }); + + it('should not throw error when button is clicked with no click handler', () => { + const banner = new Banner('Title', 'Text').getElement(); + const bannerButton: HTMLButtonElement | null = banner.querySelector('.button--white'); + + expect(() => bannerButton?.click()).not.toThrow(); + }); +}); diff --git a/src/components/banner/banner.ts b/src/components/banner/banner.ts new file mode 100644 index 0000000..5c3377d --- /dev/null +++ b/src/components/banner/banner.ts @@ -0,0 +1,29 @@ +import BaseComponent from '../../components/base-component'; +import { AppRoutesPath } from '../../router/types'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import Button from '../button/button'; +import './banner.scss'; + +export default class Banner extends BaseComponent<'section'> { + constructor(title: string, text: string, classes: string[] = []) { + super('section', ['banner', ...classes]); + + this.createMarkup(title, text); + } + + private createMarkup(title: string, text: string): void { + const container: HTMLDivElement = new BaseComponent('div', ['banner__container']).getElement(); + const bannerContent: HTMLDivElement = new BaseComponent('div', ['banner__content']).getElement(); + const bannerTitle: HTMLHeadingElement = new BaseComponent('h1', ['banner__title'], title).getElement(); + const bannerText: HTMLParagraphElement = new BaseComponent('p', ['banner__text'], text).getElement(); + const bannerButton: HTMLButtonElement = new Button('button', 'Shop All', ['button--white'], false, () => + changeUrlEvent(AppRoutesPath.SHOP) + ).getElement(); + + bannerContent.append(bannerTitle, bannerText, bannerButton); + + container.append(bannerContent); + + this.node.append(container); + } +} diff --git a/src/components/base-component.ts b/src/components/base-component.ts new file mode 100644 index 0000000..0f4eb50 --- /dev/null +++ b/src/components/base-component.ts @@ -0,0 +1,13 @@ +export default class BaseComponent { + protected node: HTMLElementTagNameMap[K]; + + constructor(tagName: K, classNames: Array = [], textContent: string = '') { + this.node = document.createElement(tagName); + this.node.classList.add(...classNames); + this.node.textContent = textContent; + } + + public getElement(): HTMLElementTagNameMap[K] { + return this.node; + } +} diff --git a/src/components/basket-empty/basket-empty.scss b/src/components/basket-empty/basket-empty.scss new file mode 100644 index 0000000..bb34119 --- /dev/null +++ b/src/components/basket-empty/basket-empty.scss @@ -0,0 +1,33 @@ +.basket-empty { + margin-bottom: 80px; + + &__container { + @include container; + } + + &__content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + padding: 80px 20px; + text-align: center; + background-color: $color-bg-light; + border-radius: 8px; + } + + &__icon { + width: 40px; + height: 40px; + background: url('../../assets/icons/bag-icon.svg') center/cover; + } + + &__title { + @include font-h4; + } + + &__subtitle { + margin-bottom: 20px; + } +} diff --git a/src/components/basket-empty/basket-empty.ts b/src/components/basket-empty/basket-empty.ts new file mode 100644 index 0000000..368c4ec --- /dev/null +++ b/src/components/basket-empty/basket-empty.ts @@ -0,0 +1,34 @@ +import { AppRoutesPath } from '../../router/types'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import './basket-empty.scss'; + +export default class BasketEmpty extends BaseComponent<'section'> { + constructor() { + super('section', ['basket-empty']); + + this.renderBasketContent(); + } + + private renderBasketContent(): void { + const basketEmptyContainer = new BaseComponent('div', ['basket-empty__container']).getElement(); + const basketEmptyContent = new BaseComponent('div', ['basket-empty__content']).getElement(); + const basketIcon = new BaseComponent('div', ['basket-empty__icon']).getElement(); + const contentTitle = new BaseComponent('h4', ['basket-empty__title'], 'Your Shopping Cart is Empty').getElement(); + + const basketSubtitle = new BaseComponent( + 'p', + ['basket-empty__subtitle'], + 'Looks like you haven’t added anything yet, let’s get you started!' + ).getElement(); + + const basketBtn = new Button('button', 'Start Shopping', ['basket-empty__button'], false, () => + changeUrlEvent(AppRoutesPath.SHOP) + ).getElement(); + + basketEmptyContent.append(basketIcon, contentTitle, basketSubtitle, basketBtn); + basketEmptyContainer.append(basketEmptyContent); + this.node.append(basketEmptyContainer); + } +} diff --git a/src/components/basket-items/basket-items.scss b/src/components/basket-items/basket-items.scss new file mode 100644 index 0000000..8430dde --- /dev/null +++ b/src/components/basket-items/basket-items.scss @@ -0,0 +1,263 @@ +.basket-items { + margin-bottom: 60px; + + &__container { + @include container; + } + + &__table { + width: 100%; + border-collapse: collapse; + margin-bottom: 24px; + + &-head { + text-align: left; + font-size: 11px; + font-weight: 700; + line-height: 120%; + letter-spacing: 1.1px; + text-transform: uppercase; + + @include tablet { + display: none; + } + } + + &-body { + font: $font-label; + text-transform: capitalize; + } + + &-row { + @include tablet { + display: flex; + align-items: center; + justify-content: flex-end; + flex-wrap: wrap; + border-bottom: 1px solid $color-border; + } + } + + &-th { + padding: 27.5px 0; + border-bottom: 1px solid $color-border; + } + + &-td { + padding: 24px 16px 24px 0; + border-bottom: 1px solid $color-border; + + &--price, + &--total-price { + min-width: 100px; + + @include mobile { + width: 100%; + } + } + + &--price { + @include mobile { + &::before { + content: 'Price '; + } + } + } + + &--total-price { + @include mobile { + &::before { + content: 'Total '; + } + } + } + + &--quantity { + @include mobile { + width: 100%; + } + } + + &--remove { + padding-right: 0; + width: 80px; + + @include tablet { + order: -1; + margin-left: auto; + } + + @include mobile { + width: 24px; + } + } + + @include tablet { + border: none; + } + + @include mobile { + padding: 12px 0; + } + } + + &-row:last-child .basket-items__table-td { + border: none; + } + } + + &__product { + display: flex; + align-items: center; + gap: 20px; + + @include tablet { + width: 85%; + order: -2; + } + + @include mobile { + width: 70%; + } + } + + &__image { + &-wrapper { + width: 132px; + height: 83px; + background: $color-bg-secondary; + border-radius: 8px; + overflow: hidden; + + @include mobile { + height: auto; + } + } + + img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; + } + + &--placeholder { + background-image: url('../../assets/img/placeholder-image.svg'); + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + } + } + + &__prices { + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; + + @include mobile { + display: inline-flex; + } + } + + &__price { + color: $color-primary; + + &--old { + text-decoration: line-through; + color: $color-secondary-40; + } + + &--new { + color: $color-error; + } + } + + &__quantity { + width: 107px; + height: 43px; + border-radius: 6px; + background: $color-bg-light; + display: flex; + align-items: center; + justify-content: space-between; + font: $font-button; + + @include mobile { + width: 100%; + } + + &--disabled { + pointer-events: none; + opacity: 0.5; + } + } + + &__remove { + background: transparent; + color: $color-primary; + position: relative; + display: flex; + align-items: center; + gap: 2px; + opacity: 0.6; + padding: 0; + width: 80px; + + &_all { + width: unset; + } + + @include mobile { + width: 24px; + + &_all { + width: unset; + } + } + + &-icon { + width: 15px; + height: 15px; + background-image: url('../../assets/icons/popup-close-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + + @include mobile { + width: 24px; + height: 24px; + } + } + + span { + @include mobile { + display: none; + } + } + + &::after { + content: ''; + position: absolute; + width: 100%; + height: 1px; + background: $color-secondary-60; + left: 0; + bottom: -4px; + transition: width 0.2s ease-in-out; + + @include mobile { + display: none; + } + } + + &:hover, + &:active { + background: transparent !important; + + &::after { + width: 0; + } + } + } +} diff --git a/src/components/basket-items/basket-items.ts b/src/components/basket-items/basket-items.ts new file mode 100644 index 0000000..c14af17 --- /dev/null +++ b/src/components/basket-items/basket-items.ts @@ -0,0 +1,320 @@ +import { LineItem } from '@commercetools/platform-sdk'; +import BaseComponent from '../../components/base-component'; +import Button from '../button/button'; +import formatPrice from '../../utils/formatPrice'; +import Notification from '../notification/notification'; +import cartStore from '../../store/cart-store'; +import removeProductFromCart from '../../services/basket/removeProductFromCart'; +import './basket-items.scss'; +import changeCartItemQuantity from '../../services/basket/changeCartItemQuantity'; +import removeCart from '../../services/basket/removeCart'; + +enum BasketItemQuantityAction { + DEC = 'decrement', + INC = 'increment', +} + +export default class BasketItems extends BaseComponent<'section'> { + private tableElements: HTMLTableRowElement[]; + private lineTotalElements: Record; + private quantityElements: Record; + private clearAllBtn: HTMLButtonElement = new Button( + 'button', + 'Clear All', + ['basket-items__remove', 'basket-items__remove_all'], + false, + () => this.onRemoveCart() + ).getElement(); + + constructor(items: LineItem[]) { + super('section', ['basket-items']); + + this.tableElements = []; + this.quantityElements = {}; + this.lineTotalElements = {}; + + this.renderBasketItems(items); + this.addSubscribtion(); + } + + private renderBasketItems(items: LineItem[]): void { + const basketItemsContainer = new BaseComponent('div', ['basket-items__container']).getElement(); + const table: HTMLTableElement = this.renderTable(items); + + basketItemsContainer.append(table, this.clearAllBtn); + + this.node.append(basketItemsContainer); + } + + private async onRemoveCart(): Promise { + try { + const response = await removeCart(); + + cartStore.dispatch({ type: 'UPDATE_CART', cart: response }); + + this.clearAllBtn.disabled = false; + } catch (err) { + if (err instanceof Error) new Notification('error', err.message); + + this.clearAllBtn.disabled = false; + } + } + + private renderTable(items: LineItem[]): HTMLTableElement { + const table: HTMLTableElement = new BaseComponent('table', ['basket-items__table']).getElement(); + const tableHead: HTMLTableSectionElement = this.renderTableHead(); + const tableBody: HTMLTableSectionElement = this.renderTableBody(items); + + table.append(tableHead, tableBody); + + return table; + } + + private renderTableHead(): HTMLTableSectionElement { + const headers: string[] = ['Product', 'Price', 'Quantity', 'Total', '']; + const tableHead: HTMLTableSectionElement = new BaseComponent('thead', ['basket-items__table-head']).getElement(); + const tableHeadRow: HTMLTableRowElement = new BaseComponent('tr', ['basket-items__table-row']).getElement(); + + headers.forEach((headerText) => { + const th: HTMLTableCellElement = new BaseComponent('th', ['basket-items__table-th']).getElement(); + th.textContent = headerText; + tableHeadRow.append(th); + }); + + tableHead.append(tableHeadRow); + + return tableHead; + } + + private renderTableBody(items: LineItem[]): HTMLTableSectionElement { + const tableBody: HTMLTableSectionElement = new BaseComponent('tbody', ['basket-items__table-body']).getElement(); + + items.forEach((item) => { + const row: HTMLTableRowElement = new BaseComponent('tr', ['basket-items__table-row']).getElement(); + + const infoCell = this.renderInfo(item); + const priceCell = this.renderPrice(item); + const quantityCell = this.renderQuantityField(item); + const totalPriceCell = this.renderTotalPrice(item); + const removeCell = this.renderRemoveBtn(item); + + row.append(infoCell, priceCell, quantityCell, totalPriceCell, removeCell); + tableBody.append(row); + + row.id = item.id; + this.tableElements.push(row); + }); + + return tableBody; + } + + private renderInfo(item: LineItem): HTMLTableCellElement { + const infoElement: HTMLTableCellElement = new BaseComponent('td', [ + 'basket-items__table-td', + 'basket-items__product', + ]).getElement(); + const titleElement: HTMLSpanElement = new BaseComponent('span', ['basket-items__title'], item.name.en).getElement(); + const imageWrapper: HTMLDivElement = new BaseComponent('div', ['basket-items__image-wrapper']).getElement(); + const imageElement: HTMLImageElement = new BaseComponent('img', ['basket-items__image']).getElement(); + + if (item.variant.images?.[0]?.url) { + imageElement.src = item.variant.images?.[0]?.url; + imageElement.alt = 'tour-image'; + imageWrapper.append(imageElement); + } else { + imageWrapper.classList.add('basket-items__image--placeholder'); + } + + infoElement.append(imageWrapper, titleElement); + + return infoElement; + } + + private renderPrice(item: LineItem): HTMLTableCellElement { + const priceField: HTMLTableCellElement = new BaseComponent('td', [ + 'basket-items__table-td', + 'basket-items__table-td--price', + ]).getElement(); + const pricesElement: HTMLDivElement = new BaseComponent('div', ['basket-items__prices']).getElement(); + const priceStandard: HTMLSpanElement = new BaseComponent('span', ['basket-items__price']).getElement(); + const priceDisc: HTMLSpanElement = new BaseComponent('span', [ + 'basket-items__price', + 'basket-items__price--new', + ]).getElement(); + + if (item.price.value) { + priceStandard.textContent = formatPrice( + item.price.value.currencyCode, + item.price.value.centAmount, + item.price.value.fractionDigits + ); + pricesElement.append(priceStandard); + } + + if (item.price.discounted) { + priceDisc.textContent = formatPrice( + item.price.discounted.value.currencyCode, + item.price.discounted.value.centAmount, + item.price.discounted.value.fractionDigits + ); + priceStandard.classList.add('basket-items__price--old'); + pricesElement.append(priceDisc); + } + + priceField.append(pricesElement); + + return priceField; + } + + private renderQuantityField(item: LineItem): HTMLTableCellElement { + const maxQuantity: number = Number(item.variant.attributes?.[3].value); + + const quantityElement: HTMLTableCellElement = new BaseComponent('td', [ + 'basket-items__table-td', + 'basket-items__table-td--quantity', + ]).getElement(); + + const quantityField: HTMLDivElement = new BaseComponent('div', ['basket-items__quantity']).getElement(); + const quantityFieldDec: HTMLButtonElement = new Button('button', '-', ['button--quantity'], false, () => + this.handleChangeItemQuantity(item, BasketItemQuantityAction.DEC) + ).getElement(); + const quantityFieldNumber: HTMLSpanElement = new BaseComponent('span', [], `${item.quantity}`).getElement(); + const quantityFieldInc: HTMLButtonElement = new Button( + 'button', + '+', + ['button--quantity'], + maxQuantity === item.quantity, + () => this.handleChangeItemQuantity(item, BasketItemQuantityAction.INC) + ).getElement(); + + this.quantityElements[item.id] = [quantityField, quantityFieldNumber, quantityFieldInc]; + + quantityField.append(quantityFieldDec, quantityFieldNumber, quantityFieldInc); + + quantityElement.append(quantityField); + return quantityElement; + } + + private renderTotalPrice(item: LineItem): HTMLTableCellElement { + const priceElement: HTMLTableCellElement = new BaseComponent('td', [ + 'basket-items__table-td', + 'basket-items__table-td--total-price', + ]).getElement(); + const price: HTMLSpanElement = new BaseComponent('span', ['basket-items__price']).getElement(); + + if (item.totalPrice.centAmount) { + price.textContent = formatPrice( + item.totalPrice.currencyCode, + item.totalPrice.centAmount, + item.totalPrice.fractionDigits + ); + this.lineTotalElements[item.id] = price; + priceElement.append(price); + } + + return priceElement; + } + + private renderRemoveBtn(item: LineItem): HTMLTableCellElement { + const removeField: HTMLTableCellElement = new BaseComponent('td', [ + 'basket-items__table-td', + 'basket-items__table-td--remove', + ]).getElement(); + const removeBtn: HTMLButtonElement = new Button('button', '', ['basket-items__remove']).getElement(); + const iconRemoveBtn: HTMLDivElement = new BaseComponent('div', ['basket-items__remove-icon']).getElement(); + const textRemoveBtn: HTMLSpanElement = new BaseComponent('span', [], 'Remove').getElement(); + + removeBtn.addEventListener('click', (event) => this.onRemoveFromCart(event, item.productId)); + + removeBtn.append(iconRemoveBtn, textRemoveBtn); + removeField.append(removeBtn); + + return removeField; + } + + private handleChangeItemQuantity(item: LineItem, action: BasketItemQuantityAction): void { + if (action === BasketItemQuantityAction.DEC) { + const newQuantity = Number(this.quantityElements[item.id][1].textContent) - 1; + this.onChangeQuantity(item.id, newQuantity); + } else { + const newQuantity = Number(this.quantityElements[item.id][1].textContent) + 1; + this.onChangeQuantity(item.id, newQuantity); + } + } + + private onChangeQuantity = async (lineItemId: string, quantity: number): Promise => { + try { + this.quantityElements[lineItemId][0].classList.add('basket-items__quantity--disabled'); + const cart = await changeCartItemQuantity(lineItemId, quantity); + cartStore.dispatch({ type: 'UPDATE_CART', cart }); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + if (error.message === 'invalid_token') { + localStorage.removeItem('tokenAnon'); + localStorage.removeItem('token'); + } + } else { + console.error(error); + } + } finally { + this.quantityElements[lineItemId][0].classList.remove('basket-items__quantity--disabled'); + } + }; + + private async onRemoveFromCart(event: MouseEvent, productId: string): Promise { + try { + if (event.currentTarget instanceof HTMLButtonElement) event.currentTarget.disabled = true; + + const updatedCart = await removeProductFromCart(productId); + cartStore.dispatch({ type: 'UPDATE_CART', cart: updatedCart }); + new Notification('success', 'Tour has been successfully removed from cart!').showNotification(); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + + if (event.currentTarget instanceof HTMLButtonElement) event.currentTarget.disabled = false; + } + } + + private addSubscribtion(): void { + cartStore.subscribe((state) => { + const cartItemIds = state.cart?.lineItems.map((item) => item.id).flat(); + + this.tableElements.forEach((itemHtml) => { + if (!cartItemIds?.includes(itemHtml.id)) { + itemHtml.remove(); + } + + if (cartItemIds?.includes(itemHtml.id)) { + const lineItem: LineItem | undefined = state.cart?.lineItems.find((item) => item.id === itemHtml.id); + + if (lineItem) { + this.lineTotalElements[itemHtml.id].textContent = formatPrice( + lineItem.totalPrice.currencyCode, + lineItem.totalPrice.centAmount, + lineItem.totalPrice.fractionDigits + ); + + const currentDisplayQuantity: string | null = this.quantityElements[itemHtml.id][1].textContent; + const currentActualQuantity: number | undefined = lineItem.quantity; + const maxQuantity: number = Number(lineItem.variant.attributes?.[3].value); + + if (Number(currentDisplayQuantity) !== currentActualQuantity) { + this.quantityElements[itemHtml.id][1].textContent = String(currentActualQuantity); + } + + if (maxQuantity === currentActualQuantity) { + this.quantityElements[itemHtml.id][2].disabled = true; + } else { + this.quantityElements[itemHtml.id][2].disabled = false; + } + } + } + }); + }); + } +} diff --git a/src/components/basket-total/basket-total.scss b/src/components/basket-total/basket-total.scss new file mode 100644 index 0000000..d0ff27a --- /dev/null +++ b/src/components/basket-total/basket-total.scss @@ -0,0 +1,66 @@ +.basket-total { + margin-bottom: 80px; + + &__container { + @include container; + display: flex; + flex-direction: column; + gap: 16px; + align-items: flex-end; + } + + &__content { + display: flex; + flex-direction: column; + width: 480px; + padding: 32px; + background-color: $color-bg-light; + border-radius: 8px; + + @include mobile { + width: 100%; + } + } + + &__button { + width: 480px; + + @include mobile { + width: 100%; + } + } + + &__promo { + display: flex; + align-items: flex-end; + gap: 8px; + margin-bottom: 24px; + + &-input { + flex-grow: 1; + } + + &-button { + height: 48px; + padding: 12px 32px; + } + } + + &__total { + padding: 20px 0; + border-top: 1px solid $color-border; + font: $font-label; + display: flex; + align-items: center; + justify-content: space-between; + + &-price { + font: $font-button; + + &.discount { + font-size: 16px; + color: $color-success; + } + } + } +} diff --git a/src/components/basket-total/basket-total.ts b/src/components/basket-total/basket-total.ts new file mode 100644 index 0000000..2a61765 --- /dev/null +++ b/src/components/basket-total/basket-total.ts @@ -0,0 +1,153 @@ +import { Cart } from '@commercetools/platform-sdk'; +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import InputField from '../input/input'; +import cartStore from '../../store/cart-store'; +import addDiscountToCart from '../../services/basket/addDiscountToCart'; +import Notification from '../notification/notification'; +import createBasketTotal from '../../utils/createBasketTotal'; +import createBasketDiscountTotal from '../../utils/createBasketDiscountTotal'; +import getDiscountCode from '../../services/getDiscountCode'; +import removeDiscountCart from '../../services/basket/removeDiscountCart'; +import './basket-total.scss'; + +export default class BasketTotal extends BaseComponent<'section'> { + private totalBox: HTMLDivElement | null = null; + private inputPromo: InputField | null = null; + private buttonClearDiscount: HTMLButtonElement | null = null; + private currentPromoCode: string = ''; + + constructor(cart: Cart) { + super('section', ['basket-total']); + + this.renderSection(cart); + this.addSubscribtion(); + } + + private renderSection(cart: Cart): void { + const container: HTMLDivElement = new BaseComponent('div', ['basket-total__container']).getElement(); + const content: HTMLDivElement = new BaseComponent('div', ['basket-total__content']).getElement(); + const button: HTMLButtonElement = new Button( + 'button', + 'Proceed to Checkout', + ['basket-total__button'], + true + ).getElement(); + + const promoBox = this.renderPromoForm(); + this.totalBox = new BaseComponent('div', ['basket-total__prices']).getElement(); + + if (cart.discountCodes.length > 0) { + this.renderTotalWithDiscount(cart); + } else { + this.renderTotal(cart); + } + + content.append(promoBox, this.totalBox); + container.append(content, button); + + this.node.append(container); + } + + private renderPromoForm(): HTMLFormElement { + const promoForm: HTMLFormElement = new BaseComponent('form', ['basket-total__promo']).getElement(); + this.inputPromo = new InputField('text', 'promo', 'TRAVEL2023', 'Enter Promo Code', ['basket-total__promo-input']); + const buttonApply: HTMLButtonElement = new Button('button', 'Apply', ['basket-total__promo-button']).getElement(); + this.buttonClearDiscount = new Button( + 'button', + '', + ['button--trash-cart', 'basket-total__delete-promo'], + false, + this.onRemoveDiscount + ).getElement(); + + const onClick = () => { + const promoFormData: FormData = new FormData(promoForm); + const promoCode: string | undefined = promoFormData.get('promo')?.toString(); + + if (promoCode) this.addPromoCodeToBasket(promoCode); + }; + + buttonApply.addEventListener('click', onClick); + + promoForm.append(this.inputPromo.getElement(), buttonApply, this.buttonClearDiscount); + + return promoForm; + } + + private renderTotal(cart: Cart): void { + (this.totalBox as HTMLDivElement).innerHTML = ''; + this.totalBox?.append(...createBasketTotal(cart)); + this.buttonClearDiscount?.classList.add('hidden'); + } + + private async renderTotalWithDiscount(cart: Cart): Promise { + (this.totalBox as HTMLDivElement).innerHTML = ''; + this.totalBox?.append(...createBasketDiscountTotal(cart)); + const discount = await getDiscountCode(); + this.inputPromo?.setValue(discount?.code || ''); + this.currentPromoCode = discount?.code || ''; + this.buttonClearDiscount?.classList.remove('hidden'); + } + + private async addPromoCodeToBasket(promoCode: string): Promise { + if (this.currentPromoCode !== promoCode) { + try { + const cart = await addDiscountToCart(promoCode); + this.currentPromoCode = promoCode; + + cartStore.dispatch({ type: 'UPDATE_CART', cart }); + + this.renderTotalWithDiscount(cart as Cart); + new Notification('success', 'Promo Code is successfully applied!').showNotification(); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + if (error.message === 'invalid_token') { + localStorage.removeItem('tokenAnon'); + localStorage.removeItem('token'); + } + } else { + console.error(error); + } + } + } else { + new Notification('warning', 'This promo code has already been entered!').showNotification(); + } + } + + private onRemoveDiscount = async (): Promise => { + try { + const cart = await removeDiscountCart(); + this.renderTotal(cart as Cart); + this.inputPromo?.setValue(''); + this.currentPromoCode = ''; + + cartStore.dispatch({ type: 'UPDATE_CART', cart }); + + new Notification('success', 'Promo Code is successfully deleted!').showNotification(); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + if (error.message === 'invalid_token') { + localStorage.removeItem('tokenAnon'); + localStorage.removeItem('token'); + } + } else { + console.error(error); + } + } + }; + + private addSubscribtion(): void { + cartStore.subscribe((state) => { + (this.totalBox as HTMLDivElement).innerHTML = ''; + + if (this.currentPromoCode) { + this.renderTotalWithDiscount(state.cart as Cart); + } else { + this.renderTotal(state.cart as Cart); + } + }); + } +} diff --git a/src/components/breadcrumbs/breadcrumbs.scss b/src/components/breadcrumbs/breadcrumbs.scss new file mode 100644 index 0000000..2c73a2c --- /dev/null +++ b/src/components/breadcrumbs/breadcrumbs.scss @@ -0,0 +1,21 @@ +.breadcrumbs { + &__container { + @include container; + display: flex; + justify-content: space-between; + } + + &__links { + padding: 32px 0; + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; + } + + &__current { + font: $font-xs; + color: $color-primary; + white-space: nowrap; + } +} diff --git a/src/components/breadcrumbs/breadcrumbs.test.ts b/src/components/breadcrumbs/breadcrumbs.test.ts new file mode 100644 index 0000000..c3757cb --- /dev/null +++ b/src/components/breadcrumbs/breadcrumbs.test.ts @@ -0,0 +1,31 @@ +import Breadcrumbs from './breadcrumbs'; +import { IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; + +describe('Breadcrumbs component', () => { + const breadcrumbLinks: IBreadcrumbLink[] = [ + { pageName: 'Home', pageHref: AppRoutesPath.MAIN }, + { pageName: 'Login', pageHref: AppRoutesPath.LOGIN }, + ]; + + const breadcrumbs: HTMLDivElement = new Breadcrumbs(breadcrumbLinks, 'Test').getElement(); + + it('should render correct html', () => { + const expectedHTML = + ''; + + expect(breadcrumbs.outerHTML).toContain(expectedHTML); + }); + + it('should render correct links amount', () => { + const linksElement: HTMLDivElement | null = breadcrumbs.querySelector('.breadcrumbs__links'); + + expect(linksElement?.childNodes.length).toEqual(breadcrumbLinks.length + 1); + }); + + it('should render correct currentPage', () => { + const currentPage: HTMLParagraphElement | null = breadcrumbs.querySelector('.breadcrumbs__current'); + + expect(currentPage?.textContent).toBe('Test'); + }); +}); diff --git a/src/components/breadcrumbs/breadcrumbs.ts b/src/components/breadcrumbs/breadcrumbs.ts new file mode 100644 index 0000000..e12fec3 --- /dev/null +++ b/src/components/breadcrumbs/breadcrumbs.ts @@ -0,0 +1,44 @@ +import BaseComponent from '../base-component'; +import Link from '../link/link'; +import Button from '../button/button'; +import userLogout from '../../services/userLogout'; +import Notification from '../../components/notification/notification'; +import { IBreadcrumbLink } from '../../types/interfaces'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import { AppRoutesPath } from '../../router/types'; +import './breadcrumbs.scss'; + +export default class Breadcrumbs extends BaseComponent<'div'> { + constructor(links: IBreadcrumbLink[], currentPage: string, showLogoutBtn: boolean = false) { + super('div', ['breadcrumbs']); + + this.renderBreadcrumbs(links, currentPage, showLogoutBtn); + } + + renderBreadcrumbs(links: IBreadcrumbLink[], currentPage: string, showLogoutBtn: boolean = false): void { + const container: HTMLDivElement = new BaseComponent('div', ['breadcrumbs__container']).getElement(); + const linksElement: HTMLDivElement = new BaseComponent('div', ['breadcrumbs__links']).getElement(); + const activeLinksElements: HTMLAnchorElement[] = links.map((link) => + new Link(link.pageName, ['link--breadcrumbs'], link.pageHref).getElement() + ); + const currentPageElement: HTMLParagraphElement = new BaseComponent( + 'p', + ['breadcrumbs__current'], + currentPage + ).getElement(); + + linksElement.append(...activeLinksElements, currentPageElement); + + const logoutBtn = new Button('button', 'Log Out', ['button--logout'], false, () => { + userLogout(); + changeUrlEvent(AppRoutesPath.MAIN); + new Notification('success', 'You have successfully logged out!').showNotification(); + }); + + container.append(linksElement); + + if (showLogoutBtn) container.append(logoutBtn.getElement()); + + this.node.append(container); + } +} diff --git a/src/components/button/button.scss b/src/components/button/button.scss new file mode 100644 index 0000000..4d33dde --- /dev/null +++ b/src/components/button/button.scss @@ -0,0 +1,302 @@ +.button { + background: $color-button; + border-radius: 6px; + padding: 16px 32px; + display: flex; + justify-content: center; + align-items: center; + color: $color-white; + font: $font-button; + cursor: pointer; + transition: background 0.3s ease-in-out; + + &:disabled { + opacity: 0.5; + cursor: default; + } + + &:not(:disabled):hover, + &:not(:disabled):active { + background: $color-button-hover; + } + + &--white { + width: 124px; + background: $color-white; + color: $color-primary; + + &:not(:disabled):hover, + &:not(:disabled):active { + background: $color-gray; + } + } + + &--loading { + position: relative; + color: transparent; + + &::after { + content: ''; + position: absolute; + width: 20px; + height: 20px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-image: url('../../assets/icons/spinner-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + } + + &--success { + position: relative; + color: transparent; + + &::after { + content: ''; + position: absolute; + width: 20px; + height: 20px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-image: url('../../assets/icons/success-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + } + + &--cart { + padding: 0; + width: 48px; + height: 48px; + position: relative; + + &::after { + content: ''; + position: absolute; + width: 20px; + height: 20px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-image: url('../../assets/icons/cart-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + } + + &--logout { + position: relative; + background: none; + border-radius: 0; + padding: 0; + color: $color-secondary-40; + transition: transform 0.3s ease-in-out; + + &:not(:disabled):hover, + &:not(:disabled):active { + background: none; + transform: scale(1.06); + } + + &::before { + content: ''; + position: absolute; + width: 20px; + height: 20px; + top: 50%; + left: -22px; + transform: translate(0, -50%); + background-image: url('../../assets/icons/logout-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + + &::after { + content: ''; + position: absolute; + width: 81px; + height: 1px; + top: 67%; + left: -21px; + transform: translate(0, -50%); + background-color: $color-secondary-40; + } + } + + &--cancel { + position: relative; + background: none; + border-radius: 0; + padding: 0; + color: $color-secondary-40; + transition: color 0.3s ease-in-out; + + &:not(:disabled):hover, + &:not(:disabled):active { + background: none; + color: $color-secondary-60; + + &::after { + background: $color-secondary-60; + width: 0; + } + } + + &::after { + content: ''; + position: absolute; + width: 100%; + height: 1px; + left: 0; + bottom: 0px; + background-color: $color-secondary-40; + transition: all 0.3s ease-in-out; + } + } + + &--change-password { + position: relative; + background: none; + width: fit-content; + border-radius: 0; + padding: 0; + margin-left: 30px; + color: $color-button-hover; + transition: transform 0.3s ease-in-out; + + &:not(:disabled):hover, + &:not(:disabled):active { + background: none; + transform: scale(1.03); + } + + &::before { + content: ''; + position: absolute; + width: 26px; + height: 25px; + top: 50%; + left: -30px; + transform: translate(0, -50%); + background-image: url('../../assets/icons/change-password-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + } + + &--reset { + background: transparent; + padding: 0; + color: $color-button; + position: relative; + + &::before { + content: ''; + position: absolute; + width: 100%; + height: 1px; + background: $color-button; + left: 0; + bottom: -4px; + transition: width 0.2s ease-in-out; + } + + &:not(:disabled):hover, + &:not(:disabled):active { + background: transparent; + + &::before { + width: 0; + } + } + } + + &--add-address { + position: relative; + background: none; + border-radius: 0; + padding: 0; + color: $color-button; + transition: all 0.3s ease-in-out; + + &:not(:disabled):hover, + &:not(:disabled):active { + background: none; + color: $color-button-hover; + + &::after { + background: $color-button-hover; + width: 0; + } + } + + &::after { + content: ''; + position: absolute; + width: 100%; + height: 1px; + left: 0; + bottom: 0px; + background: $color-button; + transition: all 0.3s ease-in-out; + } + } + + &--trash-cart { + position: relative; + display: block; + background-color: $color-error; + overflow: hidden; + height: 48px; + + &.hidden { + display: none; + } + + &:not(:disabled):hover, + &:not(:disabled):active { + background-color: rgba($color-error, 0.8); + } + + &::after { + content: ''; + position: absolute; + width: 25px; + height: 25px; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + background-image: url('../../assets/icons/cart-trash-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + } + + &--quantity { + background: none; + border-radius: 6px; + padding: 8px; + display: flex; + justify-content: center; + align-items: center; + color: $color-black; + font: $font-button; + font-size: 20px; + cursor: pointer; + transition: all 0.3s ease-in-out; + + &:not(:disabled):hover, + &:not(:disabled):active { + color: $color-white; + } + } +} diff --git a/src/components/button/button.test.ts b/src/components/button/button.test.ts new file mode 100644 index 0000000..89307b0 --- /dev/null +++ b/src/components/button/button.test.ts @@ -0,0 +1,31 @@ +import Button from './button'; + +describe('Button', () => { + const button: Button = new Button('button', 'Test Button', ['btn-test-class'], true, () => { + console.log('Button is clicked!'); + }); + + it('should render correct html-element', () => { + expect(button.getElement().outerHTML).toBe( + '' + ); + }); + it('should render correct textContent', () => { + expect(button.getElement().textContent).toBe('Test Button'); + }); + it('should render correct classList', () => { + expect(button.getElement().classList.contains('btn-test-class')).toBe(true); + }); + it('should button is disabled', () => { + const mockCallBack: jest.Mock = jest.fn(); + button.getElement().click(); + expect(mockCallBack.mock.calls.length).not.toEqual(1); + }); + test('Console log should have been called', () => { + const logSpy: jest.SpyInstance = jest.spyOn(global.console, 'log'); + button.getElement().disabled = false; + button.getElement().click(); + expect(logSpy).toHaveBeenCalled(); + expect(logSpy).toHaveBeenCalledWith('Button is clicked!'); + }); +}); diff --git a/src/components/button/button.ts b/src/components/button/button.ts new file mode 100644 index 0000000..941ebab --- /dev/null +++ b/src/components/button/button.ts @@ -0,0 +1,17 @@ +import BaseComponent from '../base-component'; +import './button.scss'; + +export default class Button extends BaseComponent<'button'> { + constructor( + type: 'submit' | 'reset' | 'button' = 'button', + text: string, + classes: string[] = [], + disabled: boolean = false, + onClick: () => void = () => {} + ) { + super('button', ['button', ...classes], text); + this.node.type = type; + disabled && this.node.setAttribute('disabled', 'true'); + this.node.addEventListener('click', onClick); + } +} diff --git a/src/components/category-list/category-list.scss b/src/components/category-list/category-list.scss new file mode 100644 index 0000000..a8beacd --- /dev/null +++ b/src/components/category-list/category-list.scss @@ -0,0 +1,54 @@ +.category-list { + margin-top: 48px; + + &__container { + @include container; + display: flex; + flex-direction: column; + gap: 16px; + } + + &__title { + @include font-h4; + } + + &__list { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 16px; + } + + &__link { + color: $color-secondary-60; + transition: color 0.3s ease-in-out; + position: relative; + + &::before { + content: ''; + position: absolute; + width: 0; + height: 1px; + background: $color-primary; + left: 0; + bottom: -4px; + transition: width 0.2s ease-in-out; + } + + &:hover { + color: $color-primary; + + &::before { + width: 100%; + } + } + + &--active { + color: $color-primary; + + &::before { + width: 100%; + } + } + } +} diff --git a/src/components/category-list/category-list.ts b/src/components/category-list/category-list.ts new file mode 100644 index 0000000..6da464a --- /dev/null +++ b/src/components/category-list/category-list.ts @@ -0,0 +1,27 @@ +import { ICategory } from '../../types/types'; +import BaseComponent from '../base-component'; +import Link from '../link/link'; +import './category-list.scss'; + +export default class CategoryList extends BaseComponent<'div'> { + constructor(title: string, categories: ICategory[], currentSlug: string) { + super('div', ['category-list']); + + this.drawList(title, categories, currentSlug); + } + + private drawList(title: string, items: ICategory[], currentSlug: string): void { + const container: HTMLDivElement = new BaseComponent('div', ['category-list__container']).getElement(); + const titleElelemt: HTMLHeadingElement = new BaseComponent('h4', ['category-list__title'], title).getElement(); + const categoryList: HTMLDivElement = new BaseComponent('div', ['category-list__list']).getElement(); + const categoryElements = items.map((item) => { + const classes: string[] = + currentSlug === item.slug ? ['category-list__link', 'category-list__link--active'] : ['category-list__link']; + return new Link(item.label, ['link', ...classes], item.url).getElement(); + }); + categoryList.append(...categoryElements); + container.append(titleElelemt, categoryList); + + this.node.append(container); + } +} diff --git a/src/components/footer/footer.scss b/src/components/footer/footer.scss new file mode 100644 index 0000000..d75dee9 --- /dev/null +++ b/src/components/footer/footer.scss @@ -0,0 +1,102 @@ +.footer { + background-color: $color-primary; + + &__container { + @include container; + padding: 80px 120px; + display: flex; + justify-content: space-between; + + @include tablet { + padding: 40px 60px; + } + + @include mobile { + flex-direction: column; + justify-content: flex-start; + gap: 40px; + padding: 20px; + } + } + + &__information { + display: flex; + flex-direction: column; + align-self: flex-start; + gap: 16px; + max-width: 400px; + + @include mobile { + order: 2; + max-width: unset; + } + + @include tablet { + max-width: 300px; + } + } + + &__subtitle { + color: $color-white; + } + + &__post-subtitle { + color: $color-white; + font-size: 14px; + opacity: 0.5; + + @include mobile { + font-size: 12px; + } + } + + &__nav { + display: flex; + gap: 64px; + + @include tablet { + gap: 30px; + } + + @include mobile { + order: 1; + justify-content: flex-start; + flex-wrap: wrap; + gap: 40px; + } + } + + &__menu { + display: flex; + flex-direction: column; + gap: 16px; + + @include mobile { + gap: 5px; + } + + .menu { + &__title > a { + color: $color-white; + + @include tablet { + display: block; + } + } + + &__item:not(.menu__title) > a { + color: $color-gray; + opacity: 0.5; + transition: all 0.2s ease; + + @include tablet { + display: block; + } + + &:hover { + opacity: 1; + } + } + } + } +} diff --git a/src/components/footer/footer.test.ts b/src/components/footer/footer.test.ts new file mode 100644 index 0000000..51bf940 --- /dev/null +++ b/src/components/footer/footer.test.ts @@ -0,0 +1,33 @@ +import Footer from './footer'; + +describe('Footer', () => { + const footer = new Footer().getElement(); + + it('renders without crashing', () => { + expect(footer).toBeDefined(); + }); + + it('contains footer information', () => { + const footerInformation: HTMLElement | null = footer.querySelector('.footer__information'); + + expect(footerInformation).toBeTruthy(); + }); + + it('contains a link to the login page', () => { + const loginLink: HTMLElement | null = footer.querySelector('.menu__link[href="/login"]'); + + expect(loginLink).toBeTruthy(); + }); + + it('contains a link to the signUp page', () => { + const registrationLink: HTMLElement | null = footer.querySelector('.menu__link[href="/registration"]'); + + expect(registrationLink).toBeTruthy(); + }); + + it('renders correct number of menu items', () => { + const menuItems = footer.querySelectorAll('.menu__item'); + + expect(menuItems.length).toBe(15); + }); +}); diff --git a/src/components/footer/footer.ts b/src/components/footer/footer.ts new file mode 100644 index 0000000..98f103e --- /dev/null +++ b/src/components/footer/footer.ts @@ -0,0 +1,95 @@ +import BaseComponent from '../base-component'; +import Logo from '../logo/logo'; +import menuItems from '../header/header-nav/menu-items'; +import Link from '../link/link'; +import { AppRoutesPath } from '../../router/types'; +import { IMenuItems } from '../../types/types'; +import './footer.scss'; + +export default class Footer extends BaseComponent<'footer'> { + private container: HTMLDivElement; + + constructor() { + super('footer', ['footer']); + + this.container = this.createMarkup(); + + this.node.append(this.container); + } + + private createMarkup(): HTMLDivElement { + const container: HTMLDivElement = new BaseComponent<'div'>('div', ['footer__container']).getElement(); + const footerInfo: HTMLDivElement = this.drawFooterInfo(); + const footerNavigation: HTMLElement = this.drawNavigation(); + + container.append(footerInfo, footerNavigation); + + return container; + } + + private drawFooterInfo(): HTMLDivElement { + const footerInfo: HTMLDivElement = new BaseComponent<'div'>('div', ['footer__information']).getElement(); + const footerLogo: HTMLHeadingElement = new Logo().getElement(); + const footerSubtitle: HTMLParagraphElement = new BaseComponent<'p'>( + 'p', + ['footer__subtitle'], + 'From hidden gems to iconic landmarks, our journeys are designed to ignite your sense of wonder.' + ).getElement(); + + const footerPostSubtitle: HTMLParagraphElement = new BaseComponent<'p'>( + 'p', + ['footer__post-subtitle'], + 'The project is made for noncommercial purposes.' + ).getElement(); + + footerInfo.append(footerLogo, footerSubtitle, footerPostSubtitle); + + return footerInfo; + } + + private drawNavigation(): HTMLElement { + const navigation: HTMLElement = new BaseComponent<'nav'>('nav', ['footer__nav']).getElement(); + + menuItems.forEach((item: IMenuItems) => { + if (item.innerItems) { + const menu: HTMLUListElement = new BaseComponent<'ul'>('ul', ['footer__menu']).getElement(); + + const menuTitle: HTMLLIElement = this.createListItem(item.title, ['menu__item', 'menu__title'], item.href); + + menu.append(menuTitle); + + item.innerItems.forEach((innerItem) => { + const menuItem: HTMLLIElement = this.createListItem(innerItem.title, ['menu__item'], innerItem.href); + + menu.append(menuItem); + }); + + navigation.append(menu); + } + }); + + const pagesMenu: HTMLUListElement = new BaseComponent<'ul'>('ul', ['footer__menu']).getElement(); + + const pagesItem: HTMLLIElement = this.createListItem('Pages', ['menu__item', 'menu__title'], AppRoutesPath.ANCHOR); + const signupItem: HTMLLIElement = this.createListItem('Create Account', ['menu__item'], AppRoutesPath.SIGN_UP); + const loginItem: HTMLLIElement = this.createListItem('Log In', ['menu__item'], AppRoutesPath.LOGIN); + const aboutUsItem: HTMLLIElement = this.createListItem('About Us', ['menu__item'], AppRoutesPath.ABOUT_US); + const accountItem: HTMLLIElement = this.createListItem('Account', ['menu__item'], AppRoutesPath.ACCOUNT); + const shoppingCartItem: HTMLLIElement = this.createListItem('Shopping Cart', ['menu__item'], AppRoutesPath.BASKET); + + pagesMenu.append(pagesItem, signupItem, loginItem, aboutUsItem, accountItem, shoppingCartItem); + + navigation.append(pagesMenu); + + return navigation; + } + + private createListItem(name: string, classNames: string[], href: AppRoutesPath | string): HTMLLIElement { + const listItem: HTMLLIElement = new BaseComponent<'li'>('li', [...classNames]).getElement(); + const itemLink: HTMLAnchorElement = new Link(name, ['menu__link'], href).getElement(); + + listItem.append(itemLink); + + return listItem; + } +} diff --git a/src/components/form/address-form.ts b/src/components/form/address-form.ts new file mode 100644 index 0000000..667aa75 --- /dev/null +++ b/src/components/form/address-form.ts @@ -0,0 +1,211 @@ +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import InputField from '../input/input'; +import SelectTypeField from '../select/select-type'; +import Notification from '../notification/notification'; +import addAddress from '../../services/addresses/addAddress'; +import setDefaultTypeAddress from '../../services/addresses/setDefaultTypeAddress'; +import addTypeAddressID from '../../services/addresses/addTypeAddressID'; +import changeAddress from '../../services/addresses/changeAddress'; +import removeTypeAddressID from '../../services/addresses/removeTypeAddressID'; +import { AddressInputs } from '../../constants/addressInputs'; +import { IAddressData, IAddressFormData, InputFilds } from '../../types/interfaces'; +import { AddressesMode } from '../../types/enums'; +import './form.scss'; + +export default class AddressForm extends BaseComponent<'form'> { + private inputs: InputFilds; + private selectType: SelectTypeField; + private isDefaultBilling: boolean = false; + private isDefaultShipping: boolean = false; + private buttonSubmit: HTMLButtonElement; + private buttonCancel: HTMLButtonElement; + private firstBtnAction: (type: AddressesMode) => void; + private secondBtnAction: (id: string) => void; + private addressData: IAddressData | null; + + constructor( + firstCallback: (type: AddressesMode) => void, + secondCallback: (id: string) => void, + addressData: IAddressData | null = null + ) { + super('form', ['form__form']); + this.inputs = {}; + this.selectType = new SelectTypeField(); + this.addressData = addressData; + if (addressData) { + this.isDefaultBilling = addressData?.defaultBillingAddressId === addressData?.address.id; + this.isDefaultShipping = addressData?.defaultShippingAddressId === addressData?.address.id; + } + this.firstBtnAction = firstCallback; + this.secondBtnAction = secondCallback; + this.node.addEventListener('submit', (event) => this.onSubmit(event)); + this.buttonSubmit = new Button('submit', this.addressData ? 'Save Address' : 'Add Address', []).getElement(); + this.buttonCancel = new Button('button', 'Cancel', ['button--cancel'], false, () => + this.secondBtnAction('new') + ).getElement(); + this.createMarkup(); + } + + private createMarkup(): void { + const actionField: HTMLDivElement = new BaseComponent('div', ['form__action']).getElement(); + actionField.append(this.buttonSubmit, this.buttonCancel); + + const formContent: HTMLDivElement = new BaseComponent('div', ['form__content']).getElement(); + + const addressMainInputs = AddressInputs['main'].map(({ type, name, placeholder, label }) => { + const inputField = new InputField(type, name, placeholder, label); + + if (name === 'streetName') { + inputField.setValue(this.addressData?.address.streetName || ''); + } else if (name === 'city') { + inputField.setValue(this.addressData?.address.city || ''); + } else if (name === 'postalCode') { + inputField.setValue(this.addressData?.address.postalCode || ''); + } + + this.inputs[name] = inputField; + + return inputField.getElement(); + }); + + const addressCheckboxesInputs = AddressInputs['checkboxes'].map(({ type, name, placeholder, label }) => { + const inputField = new InputField(type, name, placeholder, label); + + if (name === 'checkboxDefaultShipping') { + inputField.getElement().addEventListener('change', () => { + this.isDefaultShipping = !this.isDefaultShipping; + }); + + if (this.addressData) { + inputField.setChecked(this.addressData?.defaultShippingAddressId === this.addressData?.address.id); + } + } + + if (name === 'checkboxDefaultBilling') { + inputField.getElement().addEventListener('change', () => { + this.isDefaultBilling = !this.isDefaultBilling; + }); + + if (this.addressData) { + inputField.setChecked(this.addressData?.defaultBillingAddressId === this.addressData?.address.id); + } + } + + this.inputs[name] = inputField; + + return inputField.getElement(); + }); + + const chackboxesWrapp = new BaseComponent('div', []).getElement(); + chackboxesWrapp.append(...addressCheckboxesInputs); + + if (this.addressData) + this.selectType.setValue( + this.addressData?.billingAddressIds?.includes(this.addressData?.address.id || ''), + this.addressData?.shippingAddressIds?.includes(this.addressData?.address.id || '') + ); + + formContent.append(this.selectType.getElement(), ...addressMainInputs, chackboxesWrapp); + + this.node.append(formContent, actionField); + } + + private getSignupData(): IAddressFormData | undefined { + const type: string | undefined = this.selectType.getValue(); + const streetName: string | undefined = this.inputs['streetName'].getValue('streetBilling'); + const city: string | undefined = this.inputs['city'].getValue('cityBilling'); + const postalCode: string | undefined = this.inputs['postalCode'].getValue('postcodeBilling'); + const country = 'US'; + + if (!(type && streetName && city && postalCode && country)) { + return; + } + + return { + type, + streetName, + city, + postalCode, + country, + }; + } + + private async onSubmit(event: SubmitEvent): Promise { + event.preventDefault(); + + this.buttonSubmit.disabled = true; + this.buttonSubmit.classList.add('button--loading'); + + const values = this.getSignupData(); + + if (!values) { + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + return; + } + let addressId: string; + + try { + if (this.addressData) { + await changeAddress(this.addressData.address.id || '', values); + addressId = this.addressData.address.id || ''; + } else { + const { addresses } = await addAddress(values); + addressId = addresses[addresses.length - 1].id || ''; + } + + if (values.type === 'Billing') { + await addTypeAddressID('Billing', addressId); + if (this.addressData?.shippingAddressIds?.includes(addressId)) await removeTypeAddressID('Shipping', addressId); + } else if (values.type === 'Shipping') { + await addTypeAddressID('Shipping', addressId); + if (this.addressData?.billingAddressIds?.includes(addressId)) await removeTypeAddressID('Billing', addressId); + } else { + await addTypeAddressID('Billing', addressId); + await addTypeAddressID('Shipping', addressId); + } + + if (this.isDefaultBilling && this.isDefaultShipping) { + await setDefaultTypeAddress('Billing', addressId); + await setDefaultTypeAddress('Shhipping', addressId); + } else if (this.isDefaultBilling) { + await setDefaultTypeAddress('Billing', addressId); + if (this.addressData?.defaultBillingAddressId === this.addressData?.address.id) { + await setDefaultTypeAddress('Shipping', ''); + } + } else if (this.isDefaultShipping) { + await setDefaultTypeAddress('Shipping', addressId); + if (this.addressData?.defaultShippingAddressId === this.addressData?.address.id) { + await setDefaultTypeAddress('Billing', ''); + } + } else { + await setDefaultTypeAddress('Billing', ''); + await setDefaultTypeAddress('Shipping', ''); + } + + if (this.addressData?.address.id) { + new Notification('success', 'The selected address has been successfully updated!').showNotification(); + } else { + new Notification('success', 'Your Address is successfully added!').showNotification(); + } + + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.add('button--success'); + + setTimeout(() => { + this.firstBtnAction(this.addressData?.address.id ? AddressesMode.SHOW : AddressesMode.NEW); + }, 500); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.remove('button--success'); + } + } +} diff --git a/src/components/form/details-form.ts b/src/components/form/details-form.ts new file mode 100644 index 0000000..ffdef20 --- /dev/null +++ b/src/components/form/details-form.ts @@ -0,0 +1,143 @@ +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import InputField from '../input/input'; +import Notification from '../notification/notification'; +import PopupPassword from '../popup/popup-password'; +import updateUser from '../../services/updateUser'; +import userStore from '../../store/user-store'; +import { MyCustomerUpdateAction } from '@commercetools/platform-sdk'; +import { detailsEditInputs } from '../../constants/detailsEditInputs'; +import { IDetailsData, InputFilds } from '../../types/interfaces'; +import { removePopupFromBody } from '../../utils/remove-popup'; +import './form.scss'; + +export default class DetailsForm extends BaseComponent<'form'> { + private inputs: InputFilds; + private buttonWrapp: HTMLDivElement; + private buttonChangePassword: HTMLButtonElement; + private buttonSubmit: HTMLButtonElement; + private buttonCancel: HTMLButtonElement; + private onChangeModeCallback: () => void; + + constructor(onChange: () => void = () => {}) { + super('form', ['form__form']); + this.inputs = {}; + this.buttonWrapp = new BaseComponent('div', ['form__action']).getElement(); + this.buttonSubmit = new Button('submit', 'Save account details', []).getElement(); + this.buttonCancel = new Button('button', 'Cancel', ['button--cancel'], false, onChange).getElement(); + this.buttonChangePassword = new Button('button', 'Change password?', ['button--change-password'], false, () => { + document.body.append(new PopupPassword(() => removePopupFromBody('.popup-password')).getElement()); + }).getElement(); + + this.buttonWrapp.append(this.buttonSubmit, this.buttonCancel); + + this.createDetailsForm(); + + this.onChangeModeCallback = onChange; + + this.node.append(this.buttonChangePassword, this.buttonWrapp); + this.node.addEventListener('submit', (event) => this.onSubmit(event)); + } + + private createDetailsForm(): void { + const { customer } = userStore.getState(); + + const formContent: HTMLDivElement = new BaseComponent('div', [ + 'form__content', + 'form--details__content', + ]).getElement(); + + const infoInputs = detailsEditInputs.main.map(({ type, name, placeholder, label }) => { + const inputField: InputField = new InputField(type, name, placeholder, label); + if (name === 'firstName') { + inputField.setValue(customer?.firstName || ''); + } else if (name === 'lastName') { + inputField.setValue(customer?.lastName || ''); + } else if (name === 'dateOfBirth') { + inputField.setValue(customer?.dateOfBirth || ''); + } else if (name === 'email') { + inputField.setValue(customer?.email || ''); + } + this.inputs[name] = inputField; + return inputField.getElement(); + }); + + formContent.append(...infoInputs); + this.node.append(formContent); + } + + private getDetailsData(): IDetailsData | undefined { + const firstName: string | undefined = this.inputs['firstName'].getValue('firstName'); + const lastName: string | undefined = this.inputs['lastName'].getValue('lastName'); + const email: string | undefined = this.inputs['email'].getValue('email'); + const dateOfBirth: string | undefined = this.inputs['dateOfBirth'].getValue('birthDate'); + + if (!(firstName && lastName && email && dateOfBirth)) { + return; + } + + return { + firstName, + lastName, + email, + dateOfBirth, + }; + } + + private async onSubmit(event: SubmitEvent): Promise { + event.preventDefault(); + + this.buttonSubmit.disabled = true; + this.buttonSubmit.classList.add('button--loading'); + + const values: IDetailsData | undefined = this.getDetailsData(); + + if (!values) { + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + + return; + } + + try { + const body: MyCustomerUpdateAction[] = [ + { + action: 'setFirstName', + firstName: values.firstName, + }, + { + action: 'setLastName', + lastName: values.lastName, + }, + { + action: 'changeEmail', + email: values.email, + }, + { + action: 'setDateOfBirth', + dateOfBirth: values.dateOfBirth, + }, + ]; + await updateUser(body); + + new Notification('success', 'Account details is successfully updated!').showNotification(); + + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.add('button--success'); + + setTimeout(() => { + this.onChangeModeCallback(); + }, 500); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.remove('button--success'); + } + } +} diff --git a/src/components/form/form.scss b/src/components/form/form.scss new file mode 100644 index 0000000..b671eb2 --- /dev/null +++ b/src/components/form/form.scss @@ -0,0 +1,84 @@ +.form { + background: $color-bg-card; + border-radius: 8px; + padding: 64px; + display: flex; + flex-direction: column; + + @include mobile { + padding: 32px; + } + + @include small-mobile { + padding: 24px; + } + + &__title { + @include font-h2; + margin-bottom: 12px; + } + + &__subtitle { + color: $color-secondary-60; + margin-bottom: 32px; + } + + &__form { + display: flex; + flex-direction: column; + gap: 32px; + + &-block { + display: flex; + flex-direction: column; + gap: 16px; + } + } + + &__content { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 32px; + + @include tablet { + grid-template-columns: 1fr; + gap: 16px; + } + } + + &__action { + display: flex; + align-items: center; + gap: 24px; + + @include mobile { + flex-direction: column; + } + } + + &--login { + width: min(544px, 100%); + } + + &--details { + &__content { + @media (max-width: 1430px) { + grid-template-columns: 1fr; + } + } + } + + &--password { + margin-top: 20px; + display: grid; + grid-template-columns: 1fr; + gap: 20px; + padding: 20px; + border-radius: 8px; + background-color: $color-bg-card; + + @include mobile { + padding: 14px 8px; + } + } +} diff --git a/src/components/form/login-form.ts b/src/components/form/login-form.ts new file mode 100644 index 0000000..b18bd57 --- /dev/null +++ b/src/components/form/login-form.ts @@ -0,0 +1,108 @@ +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import InputField from '../input/input'; +import Link from '../link/link'; +import { ISigninData } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import './form.scss'; +import signinUser from '../../services/signinUser'; +import Notification from '../notification/notification'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import userStore from '../../store/user-store'; + +export default class LoginForm extends BaseComponent<'div'> { + private formElement: HTMLFormElement; + private emailField: InputField; + private passwordField: InputField; + private buttonSubmit: HTMLButtonElement; + + constructor() { + super('div', ['form', 'form--login']); + + this.formElement = new BaseComponent('form', ['form__form']).getElement(); + this.formElement.addEventListener('submit', (event) => this.onSubmit(event)); + + this.emailField = new InputField('email', 'email', 'Email', 'Email'); + this.passwordField = new InputField('password', 'password', 'Password', 'Password'); + this.buttonSubmit = new Button('submit', 'Log in').getElement(); + + this.createMarkup(); + } + + private createMarkup(): void { + const title = 'Welcome Back!'; + const subTitle = 'Log In to access your account.'; + const formTitle: HTMLHeadElement = new BaseComponent('h2', ['form__title'], title).getElement(); + const formSubtitle: HTMLParagraphElement = new BaseComponent('p', ['form__subtitle'], subTitle).getElement(); + + const actionField: HTMLDivElement = new BaseComponent('div', ['form__action']).getElement(); + const linkOnLogin: HTMLAnchorElement = new Link( + 'Create Account', + ['link--arrow'], + AppRoutesPath.SIGN_UP + ).getElement(); + + actionField.append(this.buttonSubmit, linkOnLogin); + + const inputsBlock: HTMLDivElement = new BaseComponent('div', ['form__form-block']).getElement(); + + inputsBlock.append(this.emailField.getElement(), this.passwordField.getElement()); + + this.formElement.append(inputsBlock, actionField); + + this.node.append(formTitle, formSubtitle, this.formElement); + } + + private getLoginData(): ISigninData | undefined { + const email: string | undefined = this.emailField.getValue('email'); + const password: string | undefined = this.passwordField.getValue('password'); + + if (!(email && password)) { + return; + } + + return { + email, + password, + }; + } + + private async onSubmit(event: SubmitEvent): Promise { + event.preventDefault(); + + this.buttonSubmit.disabled = true; + this.buttonSubmit.classList.add('button--loading'); + + const values: ISigninData | undefined = this.getLoginData(); + + if (!values) { + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + + return; + } + + try { + await signinUser(values); + + const { customer } = userStore.getState(); + const userFullName = `${customer?.firstName} ${customer?.lastName}`; + new Notification('success', `Hello, ${userFullName}!`).showNotification(); + + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.add('button--success'); + + changeUrlEvent(AppRoutesPath.MAIN); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.remove('button--success'); + } + } +} diff --git a/src/components/form/signup-form.ts b/src/components/form/signup-form.ts new file mode 100644 index 0000000..46eb981 --- /dev/null +++ b/src/components/form/signup-form.ts @@ -0,0 +1,197 @@ +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import InputField from '../input/input'; +import Link from '../link/link'; +import signupUser from '../../services/signupUser'; +import Notification from '../notification/notification'; +import { signupInputs } from '../../constants/signupInputs'; +import { IAddress, InputFilds, ISignupData } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import './form.scss'; + +export default class SignupForm extends BaseComponent<'div'> { + private formElement: HTMLFormElement; + private inputs: InputFilds; + private checkboxAddress: boolean; + private isDefaultShipping: boolean; + private isDefaultBilling: boolean; + private buttonSubmit: HTMLButtonElement; + + constructor() { + super('div', ['form']); + this.formElement = new BaseComponent('form', ['form__form']).getElement(); + this.inputs = {}; + this.checkboxAddress = false; + this.isDefaultShipping = false; + this.isDefaultBilling = false; + this.formElement.addEventListener('submit', (event) => this.onSubmit(event)); + this.buttonSubmit = new Button('submit', 'Create Account').getElement(); + this.createMarkup(); + } + + private createMarkup(): void { + const title = 'Create Account'; + const subTitle = 'Create a new account & experience our services.'; + const formTitle: HTMLHeadElement = new BaseComponent('h2', ['form__title'], title).getElement(); + const formSubtitle: HTMLParagraphElement = new BaseComponent('p', ['form__subtitle'], subTitle).getElement(); + + const actionField: HTMLDivElement = new BaseComponent('div', ['form__action']).getElement(); + const linkOnLogin: HTMLAnchorElement = new Link('Log In', ['link--arrow'], AppRoutesPath.LOGIN).getElement(); + actionField.append(this.buttonSubmit, linkOnLogin); + + const formContent: HTMLDivElement = new BaseComponent('div', ['form__content']).getElement(); + const infoInputsBlock: HTMLDivElement = new BaseComponent('div', ['form__form-block']).getElement(); + const addressesBlock: HTMLDivElement = new BaseComponent('div', ['form__form-block']).getElement(); + + const infoInputs = signupInputs['infoInputs'].map(({ type, name, placeholder, label }) => { + const inputField: InputField = new InputField(type, name, placeholder, label); + this.inputs[name] = inputField; + return inputField.getElement(); + }); + + const addressInputs = signupInputs['addressInputs'].map(({ type, name, placeholder, label }) => { + const inputField = new InputField(type, name, placeholder, label); + + if (name === 'checkboxAddress') { + inputField.getElement().addEventListener('change', () => this.toggleBillingAddress()); + } + + if (name === 'checkboxDefaultShipping') { + inputField.getElement().addEventListener('change', () => { + this.isDefaultShipping = !this.isDefaultShipping; + }); + } + + if (name === 'checkboxDefaultBilling') { + inputField.getElement().addEventListener('change', () => { + this.isDefaultBilling = !this.isDefaultBilling; + }); + } + + this.inputs[name] = inputField; + + return inputField.getElement(); + }); + + infoInputsBlock.append(...infoInputs); + addressesBlock.append(...addressInputs); + formContent.append(infoInputsBlock, addressesBlock); + + this.formElement.append(formContent, actionField); + this.node.append(formTitle, formSubtitle, this.formElement); + } + + private toggleBillingAddress(): void { + this.inputs['streetBilling'].getElement().classList.toggle('form-field--hidden'); + this.inputs['cityBilling'].getElement().classList.toggle('form-field--hidden'); + this.inputs['postcodeBilling'].getElement().classList.toggle('form-field--hidden'); + + this.checkboxAddress = !this.checkboxAddress; + } + + private getShippingAddress(): IAddress | undefined { + const streetShipping: string | undefined = this.inputs['streetShipping'].getValue('streetShipping'); + const cityShipping: string | undefined = this.inputs['cityShipping'].getValue('cityShipping'); + const postcodeShipping: string | undefined = this.inputs['postcodeShipping'].getValue('postcodeShipping'); + + if (!(streetShipping && cityShipping && postcodeShipping)) { + return; + } + + return { + key: 'shipping', + country: 'US', + streetName: streetShipping, + city: cityShipping, + postalCode: postcodeShipping, + }; + } + + private getBillingAddress(): IAddress | undefined { + const streetBilling: string | undefined = this.inputs['streetBilling'].getValue('streetBilling'); + const cityBilling: string | undefined = this.inputs['cityBilling'].getValue('cityBilling'); + const postcodeBilling: string | undefined = this.inputs['postcodeBilling'].getValue('postcodeBilling'); + + if (!(streetBilling && cityBilling && postcodeBilling && !this.checkboxAddress)) { + return; + } + + return { + key: 'billing', + country: 'US', + streetName: streetBilling, + city: cityBilling, + postalCode: postcodeBilling, + }; + } + + private getSignupData(): ISignupData | undefined { + const firstName: string | undefined = this.inputs['firstName'].getValue('firstName'); + const lastName: string | undefined = this.inputs['lastName'].getValue('lastName'); + const email: string | undefined = this.inputs['email'].getValue('email'); + const password: string | undefined = this.inputs['password'].getValue('password'); + const dateOfBirth: string | undefined = this.inputs['birthDate'].getValue('birthDate'); + const shippingAddress: IAddress | undefined = this.getShippingAddress(); + const billingAddress: IAddress | undefined = this.getBillingAddress(); + + if (!(firstName && lastName && email && password && dateOfBirth && shippingAddress)) { + return; + } + + const addresses: IAddress[] = [shippingAddress]; + + if (!this.checkboxAddress) { + if (!billingAddress) return; + addresses.push(billingAddress); + } + + return { + firstName, + lastName, + email, + password, + dateOfBirth, + addresses, + shippingAddresses: [0], + billingAddresses: [billingAddress ? 1 : 0], + ...(this.isDefaultShipping ? { defaultShippingAddress: 0 } : {}), + ...(this.isDefaultBilling ? { defaultBillingAddress: billingAddress ? 1 : 0 } : {}), + }; + } + + private async onSubmit(event: SubmitEvent): Promise { + event.preventDefault(); + this.buttonSubmit.disabled = true; + this.buttonSubmit.classList.add('button--loading'); + + const values: ISignupData | undefined = this.getSignupData(); + + if (!values) { + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + return; + } + + try { + await signupUser(values); + + new Notification('success', 'Registration completed successfully').showNotification(); + + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.add('button--success'); + + changeUrlEvent(AppRoutesPath.MAIN); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.remove('button--success'); + } + } +} diff --git a/src/components/header/burger-menu/burger-menu.scss b/src/components/header/burger-menu/burger-menu.scss new file mode 100644 index 0000000..c74564c --- /dev/null +++ b/src/components/header/burger-menu/burger-menu.scss @@ -0,0 +1,53 @@ +.burger-menu { + display: none; + flex-direction: column; + justify-content: space-between; + width: 20px; + height: 15px; + transition: all 0.2 ease; + z-index: 100; + + & div { + width: 100%; + height: 2px; + background-color: $color-primary; + transition: all 0.3s ease; + } + + &_opened { + & > div { + background-color: $color-logo; + } + + & > div:nth-child(2) { + opacity: 0; + } + + & > div:nth-child(1) { + transform: translateY(6.5px) rotate(-45deg); + } + + & > div:nth-child(3) { + transform: translateY(-6.5px) rotate(45deg); + } + } + + @include tablet { + display: flex; + } +} + +body { + & .blur { + position: absolute; + content: ''; + top: 0; + left: 0; + height: 100%; + width: 100%; + display: block; + background-color: rgba(0, 0, 0, 0.4); + z-index: 10; + overflow: hidden; + } +} diff --git a/src/components/header/burger-menu/burger-menu.ts b/src/components/header/burger-menu/burger-menu.ts new file mode 100644 index 0000000..6fff06a --- /dev/null +++ b/src/components/header/burger-menu/burger-menu.ts @@ -0,0 +1,48 @@ +import './burger-menu.scss'; +import BaseComponent from '../../base-component'; + +export default class BurgerMenu extends BaseComponent<'div'> { + private isOpenMenu: boolean; + private blur: HTMLDivElement; + private headerMenu: HTMLElement; + + constructor(headerMenu: HTMLElement) { + super('div', ['burger-menu']); + + this.blur = new BaseComponent<'div'>('div', ['blur']).getElement(); + this.drawBurgerMenu(); + this.headerMenu = headerMenu; + this.isOpenMenu = false; + + this.node.onclick = () => { + this.toggleBurgerMenu(); + }; + + this.blur.onclick = () => { + this.toggleBurgerMenu(); + }; + } + + private drawBurgerMenu(): void { + for (let i = 0; i < 3; i++) { + const line = new BaseComponent<'div'>('div', ['burger-menu__line']).getElement(); + this.node.append(line); + } + } + + private toggleBurgerMenu(): void { + this.isOpenMenu = !this.isOpenMenu; + + if (this.isOpenMenu) { + document.body.append(this.blur); + document.body.classList.add('hidden'); + this.headerMenu.classList.add('header__menu_opened'); + this.node.classList.add('burger-menu_opened'); + } else { + this.blur.remove(); + document.body.removeAttribute('class'); + this.headerMenu.classList.remove('header__menu_opened'); + this.node.classList.remove('burger-menu_opened'); + } + } +} diff --git a/src/components/header/header-nav/header-nav.scss b/src/components/header/header-nav/header-nav.scss new file mode 100644 index 0000000..4e59ad5 --- /dev/null +++ b/src/components/header/header-nav/header-nav.scss @@ -0,0 +1,124 @@ +.header { + @include tablet { + position: relative; + } + + &__menu { + background-color: white; + + @include tablet { + & { + position: fixed; + top: 0; + right: -400px; + width: 320px; + height: 100vh; + z-index: 20; + transition: right 0.3s ease; + } + + &_opened { + position: absolute; + right: 0; + } + } + } + + &__list { + position: relative; + display: flex; + gap: 54px; + + @include tablet { + top: 80px; + width: 100%; + flex-direction: column; + gap: 0; + background-color: white; + width: 320px; + z-index: 20; + } + } + + &__item { + position: relative; + display: inline-block; + transition: all 0.2s ease; + + & > a, + &:after { + @include tablet { + display: block; + padding: 5px 50px; + font-size: 20px; + } + } + + &:hover { + &:after, + & > a { + opacity: 0.6; + } + } + + &_with-submenu { + &:after { + @include chevron; + top: calc(50% - 10px); + right: -20px; + cursor: pointer; + transform: rotate(180deg); + + @include tablet { + display: none; + } + } + + &:hover { + &:after { + transform: rotate(0); + } + } + } + + & .dropdown-menu { + padding: 12px 0; + width: 140px; + + @include tablet { + position: static; + width: 100%; + padding: 0; + box-shadow: none; + opacity: 0.5; + + &_closed { + display: block; + } + } + + & .header__link { + display: inline-block; + width: 100%; + padding: 12px 20px; + + &:hover { + background-color: $color-gray; + } + + @include tablet { + padding: 0; + width: 100%; + padding: 5px 70px; + } + } + } + } + + &__bridge { + @include tablet { + display: block; + right: 0; + } + } +} diff --git a/src/components/header/header-nav/header-nav.ts b/src/components/header/header-nav/header-nav.ts new file mode 100644 index 0000000..ab16ed0 --- /dev/null +++ b/src/components/header/header-nav/header-nav.ts @@ -0,0 +1,91 @@ +import './header-nav.scss'; +import BaseComponent from '../../base-component'; +import menuItems from './menu-items'; +import { IMenuItems } from '../../../types/types'; +import Link from '../../link/link'; + +export default class HeaderNav extends BaseComponent<'nav'> { + private list: HTMLUListElement; + + constructor() { + super('nav', ['header__menu']); + + this.list = this.createHeaderList(menuItems); + + this.node.append(this.list); + } + + private createHeaderList(menuItems: IMenuItems[] = []): HTMLUListElement { + const headerList: HTMLUListElement = new BaseComponent<'ul'>('ul', ['header__list']).getElement(); + + menuItems.forEach((item) => { + const headerItem: HTMLLIElement = this.createListItem(item, [ + 'header__item', + item['innerItems'] ? 'header__item_with-submenu' : 'header__item_empty', + ]); + + const { innerItems }: IMenuItems = item; + + if (innerItems) { + const bridge: HTMLDivElement = new BaseComponent<'div'>('div', ['header__bridge']).getElement(); + const dropdownMenu: HTMLUListElement = new BaseComponent<'ul'>('ul', [ + 'dropdown-menu', + 'dropdown-menu_closed', + ]).getElement(); + + innerItems.forEach((innerItem) => { + const innerListItem: HTMLLIElement = this.createListItem(innerItem, ['item__inner-item']); + + dropdownMenu.append(innerListItem); + + headerItem.append(bridge); + + headerItem.append(dropdownMenu); + + headerItem.onmouseenter = (event) => { + if (event.target instanceof HTMLElement) this.showInnerList(event.target); + }; + + headerItem.onmouseleave = (event) => { + if (event.target instanceof HTMLElement) this.hideInnerList(event.target); + }; + }); + } + + headerList.append(headerItem); + }); + + return headerList; + } + + private createListItem(menuItem: IMenuItems, classNames: string[]): HTMLLIElement { + const listItem: HTMLLIElement = new BaseComponent<'li'>('li', [...classNames]).getElement(); + const itemLink: HTMLAnchorElement = new Link(menuItem.title, ['header__link'], menuItem.href).getElement(); + + listItem.append(itemLink); + + return listItem; + } + + private showInnerList(element: HTMLElement): void { + const classClosed = 'dropdown-menu_closed'; + const classOpened = 'dropdown-menu_opened'; + const dropdownMenu = element.querySelector(`.${classClosed}`); + + if (dropdownMenu) { + dropdownMenu.classList.remove(classClosed); + dropdownMenu.classList.add(classOpened); + } + } + + private hideInnerList(element: HTMLElement): void { + const classClosed = 'dropdown-menu_closed'; + const classOpened = 'dropdown-menu_opened'; + const dropdownMenu = element.querySelector(`.${classOpened}`); + + if (dropdownMenu) { + dropdownMenu.classList.remove(classOpened); + dropdownMenu.classList.add(classClosed); + } + } +} diff --git a/src/components/header/header-nav/menu-items.ts b/src/components/header/header-nav/menu-items.ts new file mode 100644 index 0000000..241f7dd --- /dev/null +++ b/src/components/header/header-nav/menu-items.ts @@ -0,0 +1,51 @@ +import { AppRoutesPath } from '../../../router/types'; +import { IMenuItems } from '../../../types/types'; + +const menuItems: IMenuItems[] = [ + { + title: 'Shop', + href: AppRoutesPath.SHOP, + innerItems: [ + { + title: 'Shop All', + href: AppRoutesPath.SHOP, + }, + { + title: 'Best Sellers', + href: AppRoutesPath.SHOP, + }, + { + title: 'New Tours', + href: AppRoutesPath.SHOP, + }, + ], + }, + { + title: 'Categories', + href: AppRoutesPath.SHOP, + innerItems: [ + { + title: 'Europe', + href: '/shop/europe', + }, + { + title: 'Asia', + href: '/shop/asia', + }, + { + title: 'America', + href: '/shop/america', + }, + { + title: 'Africa', + href: '/shop/africa', + }, + ], + }, + { + title: 'About Us', + href: AppRoutesPath.ABOUT_US, + }, +]; + +export default menuItems; diff --git a/src/components/header/header-user/header-user.scss b/src/components/header/header-user/header-user.scss new file mode 100644 index 0000000..c5fe444 --- /dev/null +++ b/src/components/header/header-user/header-user.scss @@ -0,0 +1,122 @@ +.header { + &__user { + display: flex; + align-items: center; + gap: 15px; + margin-left: auto; + } + + &__user-account { + position: relative; + display: flex; + gap: 8px; + align-items: center; + height: 100%; + transition: all 0.2s ease; + cursor: pointer; + + &:hover > .user-account__title { + opacity: 0.6; + } + + .user-account { + &__title { + opacity: 1; + user-select: none; + cursor: unset; + max-width: 150px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + transition: opacity 0.2s ease; + + @include tablet { + display: none; + } + + @include mobile { + display: none; + } + } + + &__icon { + @include account-icon; + + &_authorized { + width: 1.5rem; + height: 1.5rem; + background: salmon; + border-radius: 100%; + } + } + } + + .dropdown-menu { + flex-direction: column; + justify-content: center; + align-items: center; + gap: 16px; + padding: 12px 20px 24px; + + @include tablet { + top: 35px; + right: 0; + } + + &_opened { + display: flex; + } + + &__button { + padding: 16px 40px; + white-space: nowrap; + } + + &__link { + white-space: nowrap; + } + } + } + + &__user-cart { + position: relative; + display: flex; + align-items: center; + justify-content: center; + padding-left: 16px; + border-left: 2px solid $color-border; + gap: 4px; + height: 100%; + padding-left: 16px; + + .user-cart { + &__icon { + @include cart-icon; + } + + &__counter { + display: flex; + align-items: center; + justify-content: center; + height: 25px; + width: 25px; + background-color: $color-gray; + color: $color-primary; + border-radius: 100%; + pointer-events: none; + + @include mobile { + position: absolute; + transform: scale(0.7); + top: -10px; + right: -10px; + } + } + } + + @include mobile { + padding: 0; + border: 0; + } + } +} diff --git a/src/components/header/header-user/header-user.ts b/src/components/header/header-user/header-user.ts new file mode 100644 index 0000000..65c7921 --- /dev/null +++ b/src/components/header/header-user/header-user.ts @@ -0,0 +1,132 @@ +import BaseComponent from '../../base-component'; +import Button from '../../button/button'; +import Link from '../../link/link'; +import { AppRoutesPath } from '../../../router/types'; +import { changeUrlEvent } from '../../../utils/change-url-event'; +import userStore from '../../../store/user-store'; +import userLogout from '../../../services/userLogout'; +import './header-user.scss'; +import cartStore from '../../../store/cart-store'; + +export default class HeaderUser extends BaseComponent<'div'> { + private account: HTMLDivElement; + private dropdownMenu: HTMLDivElement; + private cart: HTMLAnchorElement; + private accountIcon: HTMLSpanElement; + private accountTitle: HTMLParagraphElement; + private loginBtn: HTMLButtonElement; + private createAccountBtn: HTMLAnchorElement; + private logoutBtn: HTMLButtonElement; + private profileBtn: HTMLAnchorElement; + private bridge: HTMLDivElement; + private cartCounter: HTMLDivElement; + + constructor() { + super('div', ['header__user']); + + this.account = new BaseComponent<'div'>('div', ['header__user-account']).getElement(); + this.accountIcon = new BaseComponent<'span'>('span', ['user-account__icon']).getElement(); + this.accountTitle = new BaseComponent<'p'>('p', ['user-account__title'], 'Account').getElement(); + this.dropdownMenu = new BaseComponent<'div'>('div', ['dropdown-menu', 'dropdown-menu_closed']).getElement(); + this.profileBtn = new Link( + 'My profile', + ['link--unset', 'dropdown-menu__link'], + AppRoutesPath.ACCOUNT + ).getElement(); + this.loginBtn = new Button('button', 'Log In', ['dropdown-menu__button'], false, () => + changeUrlEvent(AppRoutesPath.LOGIN) + ).getElement(); + this.createAccountBtn = new Link( + 'Create Account', + ['link--arrow', 'dropdown-menu__link'], + AppRoutesPath.SIGN_UP + ).getElement(); + + this.logoutBtn = new Button('button', 'Log Out', ['dropdown-menu__button'], false, () => { + userLogout(); + changeUrlEvent(AppRoutesPath.MAIN); + }).getElement(); + + this.bridge = new BaseComponent('div', ['header__bridge']).getElement(); + + this.drawAccount(userStore.getState().isAuth); + + this.cartCounter = new BaseComponent<'div'>('div', ['user-cart__counter'], '0').getElement(); + this.cart = this.drawCart(); + + this.node.append(this.account, this.cart); + + this.setListeners(); + this.addSubscribtion(); + } + + private drawAccount(isAuth: boolean): void { + if (isAuth) { + const userName = `${userStore.getState().customer?.firstName}`; + + this.accountIcon.classList.add('user-account__icon_authorized'); + this.accountIcon.textContent = `${userName[0]}`; + this.accountTitle.textContent = userName; + + this.dropdownMenu.innerHTML = ''; + this.dropdownMenu.append(this.profileBtn, this.logoutBtn); + } else { + this.accountIcon.classList.remove('user-account__icon_authorized'); + this.accountIcon.textContent = ''; + this.accountTitle.textContent = 'Account'; + + this.dropdownMenu.innerHTML = ''; + this.dropdownMenu.append(this.loginBtn, this.createAccountBtn); + } + + this.account.innerHTML = ''; + this.account.append(this.accountIcon, this.accountTitle, this.bridge, this.dropdownMenu); + } + + private setListeners(): void { + this.account.addEventListener('click', () => this.onOpenDropdownMenu()); + this.account.addEventListener('mouseenter', () => this.onOpenDropdownMenu()); + this.account.addEventListener('mouseleave', () => this.onCloseDropdownMenu()); + } + + private closeDropdownOnMobile(event: TouchEvent): void { + if (this.dropdownMenu.classList.contains('dropdown-menu_opened')) { + if (event.target instanceof HTMLElement) { + if (this.account && event.target !== this.account && !event.target.closest('.header__user-account')) { + this.onCloseDropdownMenu(); + } + } + } + } + + private onOpenDropdownMenu(): void { + this.dropdownMenu.classList.remove('dropdown-menu_closed'); + this.dropdownMenu.classList.add('dropdown-menu_opened'); + + document.body?.addEventListener('touchstart', (event) => this.closeDropdownOnMobile(event)); + } + + private onCloseDropdownMenu(): void { + this.dropdownMenu.classList.remove('dropdown-menu_opened'); + this.dropdownMenu.classList.add('dropdown-menu_closed'); + + document.body?.removeEventListener('touchstart', (event) => this.closeDropdownOnMobile(event)); + } + + private drawCart(): HTMLAnchorElement { + const cart: HTMLAnchorElement = new Link('', ['header__user-cart'], AppRoutesPath.BASKET).getElement(); + const cartIcon: HTMLDivElement = new BaseComponent<'div'>('div', ['user-cart__icon']).getElement(); + + cart.append(cartIcon, this.cartCounter); + + return cart; + } + + private addSubscribtion(): void { + userStore.subscribe((state) => this.drawAccount(state.isAuth)); + + cartStore.subscribe((state) => { + this.cartCounter.textContent = state.cart?.totalLineItemQuantity ? String(state.cart.totalLineItemQuantity) : '0'; + }); + } +} diff --git a/src/components/header/header.scss b/src/components/header/header.scss new file mode 100644 index 0000000..f127b8f --- /dev/null +++ b/src/components/header/header.scss @@ -0,0 +1,55 @@ +.header { + height: 80px; + border-bottom: 1px solid rgba(0, 19, 41, 0.12); + + &__container { + @include container; + display: flex; + align-items: center; + justify-content: flex-start; + gap: 64px; + height: 100%; + + @include tablet { + justify-content: space-between; + gap: 20px; + } + } + + &__link { + color: $color-primary; + transition: all 0.2s ease; + } + + &__bridge { + position: absolute; + top: 20px; + width: calc(100% + 20px); + height: 15px; + z-index: 0; + + @include tablet { + display: none; + } + } + + .dropdown-menu { + position: absolute; + flex-direction: column; + justify-content: center; + align-items: center; + top: 35px; + border-radius: 8px; + background: $color-white; + box-shadow: 0px 0px 40px 0px rgba(0, 0, 0, 0.08); + z-index: 2; + + &_closed { + display: none; + } + + &_opened { + display: block; + } + } +} diff --git a/src/components/header/header.ts b/src/components/header/header.ts new file mode 100644 index 0000000..a8ebe51 --- /dev/null +++ b/src/components/header/header.ts @@ -0,0 +1,30 @@ +import './header.scss'; +import BaseComponent from '../base-component'; +import HeaderNav from './header-nav/header-nav'; +import HeaderUser from './header-user/header-user'; +import Logo from '../logo/logo'; +import BurgerMenu from './burger-menu/burger-menu'; + +export default class Header extends BaseComponent<'header'> { + private container: HTMLDivElement; + + constructor() { + super('header', ['header']); + + this.container = this.createMarkup(); + + this.node.append(this.container); + } + + private createMarkup(): HTMLDivElement { + const container: HTMLDivElement = new BaseComponent<'div'>('div', ['header__container']).getElement(); + const headerLogo: HTMLHeadingElement = new Logo().getElement(); + const navigation: HTMLElement = new HeaderNav().getElement(); + const userWrapper: HTMLDivElement = new HeaderUser().getElement(); + const burgerMenu: HTMLDivElement = new BurgerMenu(navigation).getElement(); + + container.append(headerLogo, navigation, userWrapper, burgerMenu); + + return container; + } +} diff --git a/src/components/input/input.scss b/src/components/input/input.scss new file mode 100644 index 0000000..284712b --- /dev/null +++ b/src/components/input/input.scss @@ -0,0 +1,109 @@ +.form-field { + display: flex; + flex-direction: column; + + &__label { + font: $font-label; + color: $color-primary; + margin-bottom: 8px; + } + + &__input { + padding: 10px 24px; + height: 48px; + width: 100%; + font: $font-main; + color: $color-primary; + background: $color-white; + border: 1px solid $color-white; + border-radius: 6px; + transition: + color 0.3s ease-in-out, + border 0.3s ease-in-out; + + &:focus, + &:hover { + border: 1px solid $color-border; + } + + &.valid-error { + border: 1px solid $color-error; + color: $color-error; + } + + &::placeholder { + opacity: 0.4; + } + + &:disabled { + opacity: 0.6; + border: 1px solid $color-white; + } + + @include small-mobile { + padding: 10px 14px; + } + } + + &-password { + position: relative; + + .form-field__input { + padding-right: 46px; + } + } + + &__check { + position: absolute; + right: 24px; + top: 44.5px; + width: 20px; + height: 20px; + background-image: url('../../assets/icons/visibility.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + cursor: pointer; + + @include small-mobile { + right: 14px; + } + + &.password-visible { + background-image: url('../../assets/icons/visibility-off.svg'); + } + } + + &__error { + margin-top: 4px; + font-size: 14px; + color: $color-error; + } + + &-checkbox { + flex-direction: row-reverse; + align-items: center; + justify-content: flex-end; + + input { + cursor: pointer; + width: auto; + } + + .form-field__label { + margin: 0 0 0 8px; + } + } + + &-country { + &::after { + content: '* currently, the shop only operates in the USA'; + color: $color-secondary-60; + margin-top: 8px; + } + } + + &--hidden { + display: none; + } +} diff --git a/src/components/input/input.test.ts b/src/components/input/input.test.ts new file mode 100644 index 0000000..779394f --- /dev/null +++ b/src/components/input/input.test.ts @@ -0,0 +1,29 @@ +import Input from './input'; + +describe('Input', () => { + const inputComponent: Input = new Input('password', 'Test Input', 'Test Placeholder', 'Test Label', [ + 'input-test-class', + ]); + + it('should render correct html', () => { + const expectedHTML: string = + '
'; + + expect(inputComponent.getElement().outerHTML).toContain(expectedHTML); + }); + + it('should render correct textContent', () => { + const label: HTMLElement | null = inputComponent.getElement().querySelector('.form-field__label'); + expect(label?.textContent).toBe('Test Label'); + }); + + it('should render correct textContent', () => { + const input: HTMLInputElement | null = inputComponent.getElement().querySelector('input'); + expect(input?.getAttribute('type')).toBe('password'); + }); + + it('should render correct textContent', () => { + const input: HTMLInputElement | null = inputComponent.getElement().querySelector('input'); + expect(input?.getAttribute('placeholder')).toBe('Test Placeholder'); + }); +}); diff --git a/src/components/input/input.ts b/src/components/input/input.ts new file mode 100644 index 0000000..67518a8 --- /dev/null +++ b/src/components/input/input.ts @@ -0,0 +1,116 @@ +import BaseComponent from '../base-component'; +import formValidationRules from '../../constants/formValidationRules'; +import './input.scss'; + +export default class InputField extends BaseComponent<'div'> { + private labelElement: HTMLLabelElement; + private inputElement: HTMLInputElement; + private errorElement: HTMLSpanElement; + + constructor( + type: string = 'text', + name: string = '', + placeholder: string = '', + label: string = '', + classes: string[] = [] + ) { + super('div', ['form-field', ...classes]); + + this.labelElement = new BaseComponent('label', ['form-field__label'], label).getElement(); + this.inputElement = new BaseComponent('input', ['form-field__input']).getElement(); + this.errorElement = new BaseComponent('span', ['form-field__error']).getElement(); + + this.setAttributes(type, name, placeholder); + + if (type === 'date') this.addMinMaxForInputDate(); + if (type === 'password') this.createPasswordCheckbox(); + if (type === 'checkbox') this.node.classList.add('form-field-checkbox'); + if (name === 'country') this.createCountryField(); + + this.node.append(this.labelElement, this.inputElement); + } + + public getValue(inputName: keyof typeof formValidationRules, comparisonValues?: string): string | undefined { + const regex: RegExp = formValidationRules[inputName]?.rule; + + if (regex && !regex.test(this.inputElement.value.trim())) { + this.showError(inputName); + this.inputElement.addEventListener('input', () => this.clearError()); + + return; + } + + if (inputName === 'newPassword' && this.inputElement.value === comparisonValues) { + this.showError(inputName, true); + this.inputElement.addEventListener('input', () => this.clearError()); + + return; + } + + this.inputElement.removeEventListener('input', () => this.clearError()); + + return this.inputElement.value.trim(); + } + + public setChecked(isChecked: boolean = false): void { + this.inputElement.checked = isChecked; + } + + public setValue(value: string): void { + this.inputElement.value = value; + } + + public setAttribute(name: string, value: string): void { + this.inputElement.setAttribute(name, value); + } + + private setAttributes(type: string = 'text', name: string = '', placeholder: string = ''): void { + this.inputElement.type = type; + this.inputElement.name = name; + this.inputElement.id = name; + this.inputElement.placeholder = placeholder; + this.labelElement.setAttribute('for', name); + } + + private createCountryField(): void { + this.node.classList.add('form-field-country'); + this.inputElement.value = 'US'; + this.inputElement.disabled = true; + } + + private addMinMaxForInputDate(): void { + this.inputElement.min = '1900-01-01'; + const thirteenYearsAgo: Date = new Date(new Date().setFullYear(new Date().getFullYear() - 13)); + const formattedDate: string = `${thirteenYearsAgo.getFullYear()}-${(thirteenYearsAgo.getMonth() + 1) + .toString() + .padStart(2, '0')}-${thirteenYearsAgo.getDate().toString().padStart(2, '0')}`; + this.inputElement.max = formattedDate; + } + + private showError(inputName: keyof typeof formValidationRules, isConfirm: boolean = false): void { + this.inputElement.classList.add('valid-error'); + this.errorElement.textContent = isConfirm + ? formValidationRules[inputName].secondErrorText || '' + : formValidationRules[inputName].errorText; + this.node.append(this.errorElement); + } + + private clearError(): void { + this.inputElement.classList.remove('valid-error'); + this.errorElement.textContent = ''; + this.errorElement.remove(); + } + + private createPasswordCheckbox(): void { + this.node.classList.add('form-field-password'); + + const checkboxBlock: HTMLDivElement = new BaseComponent('div', ['form-field__check']).getElement(); + + checkboxBlock.addEventListener('click', () => { + this.inputElement.type = this.inputElement.type === 'password' ? 'text' : 'password'; + checkboxBlock.classList.toggle('password-visible'); + }); + + this.node.append(checkboxBlock); + } +} diff --git a/src/components/link/link.scss b/src/components/link/link.scss new file mode 100644 index 0000000..1547a49 --- /dev/null +++ b/src/components/link/link.scss @@ -0,0 +1,109 @@ +.link { + &--breadcrumbs { + font: $font-xs; + color: $color-secondary-40; + transition: color 0.3s ease-in-out; + white-space: nowrap; + + &::after { + content: '/'; + margin-left: 6px; + } + + &:hover { + color: $color-secondary-60; + } + } + + &--arrow, + &--unset { + font: $font-button; + display: flex; + align-items: center; + position: relative; + transition: + border 0.3s ease-in-out, + color 0.3s ease-in-out, + opacity 0.3s ease-in-out; + + &::after { + content: ''; + display: inline-block; + margin-left: 6px; + background-position: center; + background-repeat: no-repeat; + background-size: cover; + transition: transform 0.3s ease-in-out; + } + } + + &--arrow { + color: $color-button; + &::after { + width: 8px; + height: 8px; + background-image: url('../../assets/icons/link-arrow.svg'); + } + + &::before { + content: ''; + position: absolute; + width: 100%; + height: 1px; + background: $color-button; + left: 0; + bottom: -4px; + transition: width 0.2s ease-in-out; + } + + &:hover, + &:active { + color: $color-button-hover; + + &::after { + transform: rotate(45deg); + } + + &::before { + width: 0; + } + } + } + + &--unset { + color: unset; + opacity: 0.5; + + &:hover { + opacity: 1; + } + } + + &--return { + position: relative; + font: $font-button; + color: $color-secondary-40; + transition: all 0.3s ease-in-out; + + &:not(:disabled):hover, + &:not(:disabled):active { + color: $color-secondary-60; + + &::after { + background: $color-secondary-60; + width: 0; + } + } + + &::after { + content: ''; + position: absolute; + width: 100%; + height: 1px; + left: 0; + bottom: -1px; + background: $color-secondary-40; + transition: all 0.3s ease-in-out; + } + } +} diff --git a/src/components/link/link.test.ts b/src/components/link/link.test.ts new file mode 100644 index 0000000..5ed1fd9 --- /dev/null +++ b/src/components/link/link.test.ts @@ -0,0 +1,28 @@ +import Link from './link'; +import { AppRoutesPath } from '../../router/types'; + +describe('Link', () => { + const link: Link = new Link('Hello', ['link-test-class'], AppRoutesPath.LOGIN); + + it('should render correct html-element', () => { + expect(link.getElement().outerHTML).toBe('Hello'); + }); + it('should render correct textContent', () => { + expect(link.getElement().textContent).toBe('Hello'); + }); + it('should render correct classList', () => { + expect(link.getElement().classList.contains('link-test-class')).toBe(true); + }); + it('should render correct href', () => { + expect(link.getElement().href).toBe('http://localhost/login'); + }); + it('should change url', () => { + link.getElement().click(); + expect(window.location.pathname).toBe('/login'); + }); + it('should trigger a new custom event', () => { + const dispatchEventSpy: jest.SpyInstance = jest.spyOn(window, 'dispatchEvent'); + link.getElement().click(); + expect(dispatchEventSpy.mock.calls[0][0].bubbles).toEqual(true); + }); +}); diff --git a/src/components/link/link.ts b/src/components/link/link.ts new file mode 100644 index 0000000..fc6ed48 --- /dev/null +++ b/src/components/link/link.ts @@ -0,0 +1,16 @@ +import BaseComponent from '../base-component'; +import { AppRoutesPath } from '../../router/types'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import './link.scss'; + +export default class Link extends BaseComponent<'a'> { + constructor(text: string, classes: string[] = [], href: AppRoutesPath | string) { + super('a', ['link', ...classes], text); + this.node.href = href; + + this.node.addEventListener('click', (e) => { + e.preventDefault(); + changeUrlEvent(href); + }); + } +} diff --git a/src/components/list/list.scss b/src/components/list/list.scss new file mode 100644 index 0000000..fd6d3a0 --- /dev/null +++ b/src/components/list/list.scss @@ -0,0 +1,27 @@ +.list { + &-item { + display: flex; + padding: 16px 0; + border-bottom: 1px solid rgba($color-primary, 0.08); + + &:first-child { + padding-top: 0; + } + + &__key { + min-width: 140px; + font: $font-button; + + @include mobile { + min-width: 100px; + } + } + + &__value { + font-size: 15px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + } +} diff --git a/src/components/list/list.test.ts b/src/components/list/list.test.ts new file mode 100644 index 0000000..3b00bcc --- /dev/null +++ b/src/components/list/list.test.ts @@ -0,0 +1,28 @@ +import { ListDataType } from '../../types/types'; +import List from './list'; + +describe('List', () => { + const mockObj: ListDataType = { + name: 'John', + lastName: 'Deer', + country: 'US', + }; + + const list = new List(mockObj).getElement(); + + it('should be defined', () => { + expect(list).toBeDefined(); + }); + + it('should root-element have the correct tagName', () => { + expect(list.tagName).toBe('UL'); + }); + + it('should child-element have the correct tagName', () => { + expect(list.children[0].tagName).toBe('LI'); + }); + + it('should have the correct presence of children nodes', () => { + expect(list.childNodes.length).toBe(3); + }); +}); diff --git a/src/components/list/list.ts b/src/components/list/list.ts new file mode 100644 index 0000000..39bb457 --- /dev/null +++ b/src/components/list/list.ts @@ -0,0 +1,26 @@ +import BaseComponent from '../base-component'; +import { ListDataType } from '../../types/types'; +import './list.scss'; + +export default class List extends BaseComponent<'ul'> { + constructor(data: ListDataType) { + super('ul', ['list']); + this.node.append(...this.createList(data)); + } + + private createList(data: ListDataType): HTMLElement[] { + const listOfElements: HTMLElement[] = []; + + for (const key in data) { + const newElement = new BaseComponent('li', ['list-item']).getElement(); + const newElementKey = new BaseComponent('p', ['list-item__key'], key).getElement(); + const newElementValue = new BaseComponent('p', ['list-item__value'], data[key]).getElement(); + + newElement.append(newElementKey, newElementValue); + + listOfElements.push(newElement); + } + + return listOfElements; + } +} diff --git a/src/components/logo/logo.scss b/src/components/logo/logo.scss new file mode 100644 index 0000000..10bf88c --- /dev/null +++ b/src/components/logo/logo.scss @@ -0,0 +1,17 @@ +.logo { + display: inline-block; + font: $font-logo; + + &__link { + color: $color-logo; + white-space: nowrap; + } + + @include tablet { + font-size: 24px; + } + + @include mobile { + font-size: 22px; + } +} diff --git a/src/components/logo/logo.test.ts b/src/components/logo/logo.test.ts new file mode 100644 index 0000000..c988bf9 --- /dev/null +++ b/src/components/logo/logo.test.ts @@ -0,0 +1,21 @@ +import Logo from './logo'; + +describe('Logo', () => { + const logo: HTMLElement = new Logo().getElement(); + + it('should be defined', () => { + expect(logo).toBeDefined(); + }); + + it('should have the correct tagName', () => { + expect(logo.tagName).toBe('H1'); + }); + + it('should child-element have the correct tagName', () => { + expect(logo.children[0].tagName).toBe('A'); + }); + + it('should have the "logo" class', () => { + expect(logo.classList.contains('logo')).toBe(true); + }); +}); diff --git a/src/components/logo/logo.ts b/src/components/logo/logo.ts new file mode 100644 index 0000000..1ca91ea --- /dev/null +++ b/src/components/logo/logo.ts @@ -0,0 +1,14 @@ +import BaseComponent from '../base-component'; +import Link from '../link/link'; +import { AppRoutesPath } from '../../router/types'; +import './logo.scss'; + +export default class Logo extends BaseComponent<'h1'> { + constructor() { + super('h1', ['logo']); + + const logoLink = new Link('this is this.', ['logo__link'], AppRoutesPath.MAIN).getElement(); + + this.node.append(logoLink); + } +} diff --git a/src/components/notification/notification.scss b/src/components/notification/notification.scss new file mode 100644 index 0000000..b3505f4 --- /dev/null +++ b/src/components/notification/notification.scss @@ -0,0 +1,33 @@ +.custom-toast { + display: flex; + align-items: flex-start; + gap: 8px; + color: $color-white; + padding: 20px 24px; + border-radius: 8px; + transition: all 0.2s ease; + + &:hover { + opacity: 0.9; + } + + .toast-close { + transition: all 0.2s ease; + + &:hover { + opacity: 0.7; + } + } + + &_success { + background: $color-success; + } + + &_error { + background: $color-error; + } + + &_warning { + background: $color-logo; + } +} diff --git a/src/components/notification/notification.test.ts b/src/components/notification/notification.test.ts new file mode 100644 index 0000000..6cd3c92 --- /dev/null +++ b/src/components/notification/notification.test.ts @@ -0,0 +1,19 @@ +import Notification from './notification'; + +const TEST_DURATION: number = 1000; + +describe('Notification', () => { + const notification: Notification = new Notification('success', 'Test Notification Text', TEST_DURATION); + + it('should have correct type propeprty', () => { + expect(notification).toHaveProperty('type', 'success'); + }); + + it('should have correct message propeprty', () => { + expect(notification).toHaveProperty('message', 'Test Notification Text'); + }); + + it('should have correct duration propeprty', () => { + expect(notification).toHaveProperty('duration', TEST_DURATION); + }); +}); diff --git a/src/components/notification/notification.ts b/src/components/notification/notification.ts new file mode 100644 index 0000000..1e5723e --- /dev/null +++ b/src/components/notification/notification.ts @@ -0,0 +1,27 @@ +import Toastify from 'toastify-js'; +import 'toastify-js/src/toastify.css'; +import './notification.scss'; + +const BASE_DURATION: number = 5000; + +export default class Notification { + private message: string; + private type: 'error' | 'success' | 'warning'; + private duration: number; + + constructor(type: 'error' | 'success' | 'warning', message: string, duration: number = BASE_DURATION) { + this.message = message; + this.type = type; + this.duration = duration; + } + + public showNotification(): void { + Toastify({ + className: `custom-toast custom-toast_${this.type}`, + text: this.message, + duration: this.duration, + gravity: 'bottom', + close: true, + }).showToast(); + } +} diff --git a/src/components/popup/popup-password.ts b/src/components/popup/popup-password.ts new file mode 100644 index 0000000..d2bf3e3 --- /dev/null +++ b/src/components/popup/popup-password.ts @@ -0,0 +1,122 @@ +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import InputField from '../input/input'; +import Notification from '../notification/notification'; +import changePassword from '../../services/changePassword'; +import signinUser from '../../services/signinUser'; +import userStore from '../../store/user-store'; +import { detailsEditInputs } from '../../constants/detailsEditInputs'; +import { IDetailsPasswordData, InputFilds } from '../../types/interfaces'; +import './popup.scss'; + +export default class PopupPassword extends BaseComponent<'div'> { + private inputs: InputFilds = {}; + private formElement: HTMLFormElement; + private buttonWrapp: HTMLDivElement; + private buttonSubmit: HTMLButtonElement; + private buttonCancel: HTMLButtonElement; + private onCloseCallback: () => void; + + constructor(onClose: () => void = () => {}) { + super('div', ['popup', 'open', 'popup-password']); + this.formElement = new BaseComponent('form', ['form__form']).getElement(); + this.formElement.addEventListener('submit', (event) => this.onSubmit(event)); + this.buttonWrapp = new BaseComponent('div', ['form__action']).getElement(); + this.buttonSubmit = new Button('submit', 'Save password', []).getElement(); + this.buttonCancel = new Button('button', 'Cancel', ['button--cancel'], false, this.closePopup).getElement(); + this.buttonWrapp.append(this.buttonSubmit, this.buttonCancel); + this.formElement.append(this.buttonWrapp); + + const popupWrapp = new BaseComponent('div', ['popup__content']).getElement(); + const popupCloseIcon = new BaseComponent('div', ['popup__close']).getElement(); + popupCloseIcon.addEventListener('click', this.closePopup); + const popupCloseTitle = new BaseComponent('h2', ['popup__title'], 'Create new password').getElement(); + popupWrapp.append(popupCloseIcon, popupCloseTitle, this.formElement); + + this.createPasswordForm(); + + this.onCloseCallback = onClose; + + this.node.append(popupWrapp); + this.node.addEventListener('click', this.closeOnBackDropClick); + } + + private closePopup = (): void => { + this.node.classList.remove('open'); + this.onCloseCallback(); + }; + + private closeOnBackDropClick = (e: MouseEvent): void => { + const dialogElement = e.currentTarget; + const isClickedOnBackDrop = e.target === dialogElement; + if (isClickedOnBackDrop) { + this.closePopup(); + } + }; + + private createPasswordForm(): void { + const formContent: HTMLDivElement = new BaseComponent('div', ['form--password']).getElement(); + const infoInputs = detailsEditInputs.passwords.map(({ type, name, placeholder, label }) => { + const inputField: InputField = new InputField(type, name, placeholder, label); + this.inputs[name] = inputField; + return inputField.getElement(); + }); + formContent.append(...infoInputs); + this.formElement.prepend(formContent); + } + + private getDetailsData(): IDetailsPasswordData | undefined { + const currentPassword: string | undefined = this.inputs['currentPassword'].getValue('password'); + const newPassword: string | undefined = this.inputs['newPassword'].getValue('newPassword', currentPassword); + + if (!(currentPassword && newPassword)) { + return; + } + + return { + currentPassword, + newPassword, + }; + } + + private async onSubmit(event: SubmitEvent): Promise { + event.preventDefault(); + + this.buttonSubmit.disabled = true; + this.buttonSubmit.classList.add('button--loading'); + + const values: IDetailsPasswordData | undefined = this.getDetailsData(); + + if (!values) { + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + return; + } + + try { + const { customer } = userStore.getState(); + + await changePassword(values.currentPassword, values.newPassword); + + await signinUser({ email: customer?.email || '', password: values.newPassword }); + + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.add('button--success'); + new Notification('success', 'New password successfully updated!').showNotification(); + + setTimeout(() => { + this.closePopup(); + }, 500); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + + this.buttonSubmit.disabled = false; + this.buttonSubmit.classList.remove('button--loading'); + this.buttonSubmit.classList.remove('button--success'); + } + } +} diff --git a/src/components/popup/popup.scss b/src/components/popup/popup.scss new file mode 100644 index 0000000..6e4d035 --- /dev/null +++ b/src/components/popup/popup.scss @@ -0,0 +1,78 @@ +.popup { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + background: rgba($color-black, 0.6); + padding: 0 60px; + z-index: 100; + + @include mobile { + padding: 0 10px; + } + + &.open { + display: flex; + align-items: center; + justify-content: center; + animation: popup-fade 0.5s ease forwards; + } + + &__content { + position: relative; + display: flex; + flex-direction: column; + max-width: 560px; + height: auto; + padding: 32px; + border-radius: 9px; + background: $color-white; + overflow: hidden; + transition: all 0.3s ease; + + @include mobile { + padding: 24px 12px; + } + } + + &__title { + @include font-h4; + } + + &__close { + position: absolute; + top: 24px; + right: 24px; + width: 20px; + height: 20px; + background-image: url('../../assets/icons/popup-close-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + cursor: pointer; + transition: transform 0.3s ease-in-out; + + @include mobile { + top: 12px; + right: 12px; + } + + &:not(:disabled):hover, + &:not(:disabled):active { + transform: scale(1.15); + } + } +} + +@keyframes popup-fade { + from { + opacity: 0; + } + to { + opacity: 1; + } +} diff --git a/src/components/popup/popup.test.ts b/src/components/popup/popup.test.ts new file mode 100644 index 0000000..d76b390 --- /dev/null +++ b/src/components/popup/popup.test.ts @@ -0,0 +1,25 @@ +import PopupPassword from './popup-password'; + +const popupHTML = ``; + +describe('Popup', () => { + const popup: HTMLElement = new PopupPassword().getElement(); + + it('should render correct html-element', () => { + expect(popup.outerHTML).toBe(popupHTML); + }); + + it('should active popup', () => { + document.body.append(popup); + const isPopup = document.querySelector('.popup') as HTMLElement; + expect(isPopup.classList.contains('open')).toBe(true); + }); + + it('should close popup', () => { + document.body.append(popup); + const closeBtn = document.querySelector('.popup__close') as HTMLElement; + closeBtn.click(); + const isPopup = document.querySelector('.popup') as HTMLElement; + expect(isPopup.classList.contains('open')).toBe(false); + }); +}); diff --git a/src/components/product-card/product-card.scss b/src/components/product-card/product-card.scss new file mode 100644 index 0000000..5704f5e --- /dev/null +++ b/src/components/product-card/product-card.scss @@ -0,0 +1,173 @@ +.product-card { + border-radius: 8px; + box-shadow: 0px 0px 40px 0px rgba(0, 0, 0, 0.08); + position: relative; + display: flex; + flex-direction: column; + + &__media { + height: 252px; + background: $color-bg-secondary; + border-radius: 8px; + overflow: hidden; + cursor: pointer; + + img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; + transition: scale 0.3s ease-in-out; + } + + &--placeholder { + background-image: url('../../assets/img/placeholder-image.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + + &:hover { + img { + scale: 1.2; + } + } + } + + &__content { + padding: 32px; + height: calc(100% - 252px); + display: flex; + flex-direction: column; + position: relative; + } + + &__middle { + display: flex; + align-items: center; + + &-divider { + color: $color-primary; + opacity: 0.2; + margin: 0 12px; + } + } + + &__price { + color: $color-price; + font: $font-button; + + &--old { + text-decoration: line-through; + color: $color-secondary-40; + } + + &--new { + color: $color-error; + margin-left: 6px; + } + } + + &__days { + font: $font-label; + } + + &__bottom { + display: flex; + align-items: flex-end; + justify-content: space-between; + margin-top: auto; + } + + &__reviews { + background: $color-bg-light; + padding: 4px 12px; + color: $color-secondary-60; + font: $font-xs; + border-radius: 100px; + } + + &__button { + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease-in-out; + + @include pre-tablet { + opacity: 1; + pointer-events: all; + } + + &--added { + opacity: 1; + pointer-events: all; + background: $color-price !important; + } + } + + &__title { + @include font-h4; + margin-bottom: 10px; + } + + &__description { + margin-bottom: 16px; + } + + &__rating { + position: absolute; + top: -236px; + left: 16px; + padding: 6px 8px; + display: flex; + align-items: center; + gap: 4px; + background: $color-white; + border-radius: 100px; + font: $font-xs; + font-weight: 700; + + &::before { + content: ''; + width: 14px; + height: 14px; + background-image: url('../../assets/icons/star-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + } + + &:hover { + .product-card__button:not(.product-card__button--added) { + opacity: 1; + pointer-events: all; + } + } + + &.card-overlay-enabled { + &::before { + content: ''; + display: block; + position: absolute; + inset: 0; + z-index: 2; + background: $color-white; + opacity: 0.5; + } + + &::after { + content: ''; + position: absolute; + z-index: 3; + width: 100px; + height: 100px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-image: url('../../assets/icons/spinner-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + } + } +} diff --git a/src/components/product-card/product-card.test.ts b/src/components/product-card/product-card.test.ts new file mode 100644 index 0000000..ad550b8 --- /dev/null +++ b/src/components/product-card/product-card.test.ts @@ -0,0 +1,118 @@ +import { ProductProjection } from '@commercetools/platform-sdk'; +import ProductCard from './product-card'; + +describe('ProductCard', () => { + const mockProduct: ProductProjection = { + id: '440872b3-7de4-4d35-992f-80221313c0ce', + version: 13, + productType: { + typeId: 'product-type', + id: '31b96cba-837c-4f7b-be29-45fb85dbea58', + }, + name: { + en: 'Wildlife of the Rockies', + }, + categories: [ + { + typeId: 'category', + id: '818991f4-c138-4839-ad69-09809dda6beb', + }, + ], + categoryOrderHints: {}, + slug: { + en: 'america---safari-am---Wildlife-of-the-Rockies', + }, + metaTitle: { + en: 'Wildlife of the Rockies', + }, + metaDescription: { + en: "Experience North America's diverse wildlife in the Rocky Mountains.", + }, + variants: [], + masterVariant: { + attributes: [ + { + name: 'rating', + value: '4.6', + }, + { + name: 'reviews', + value: '70', + }, + { + name: 'days', + value: '6', + }, + { + name: 'inStock', + value: '19', + }, + { + name: 'location', + value: 'Banff, Jasper National Parks, Canada', + }, + { + name: 'shortDescription', + value: "Experience North America's diverse wildlife in the Rocky Mountains.", + }, + { + name: 'adventureStyle', + value: 'Safari', + }, + { + name: 'aboutTour', + value: + "Route: Depart from Denver, USA, and venture into the Rocky Mountains to observe North America's diverse wildlife. Group Size: Intimate group of 6-8 wildlife enthusiasts. Activities: Wildlife tracking, guided hikes, observing bighorn sheep and elk, learning about Rocky Mountain ecosystems.", + }, + ], + assets: [], + images: [ + { + url: 'https://firebasestorage.googleapis.com/v0/b/aillery.appspot.com/o/images%2F43%2Fphoto-1682685796002-e05458d61f07.jpg?alt=media&token=18a7f29d-e9be-4694-bc3e-a56f31e70a77', + dimensions: { + w: 2071, + h: 1381, + }, + }, + ], + prices: [ + { + id: '3ce8271a-a18c-4850-aebd-20ae95525ead', + value: { + type: 'centPrecision', + currencyCode: 'USD', + centAmount: 165000, + fractionDigits: 2, + }, + country: 'US', + }, + ], + key: 'tour43', + sku: 'tour-43', + id: 1, + }, + searchKeywords: {}, + hasStagedChanges: false, + published: true, + taxCategory: { + typeId: 'tax-category', + id: 'ed35c239-a7a5-45c8-a820-3f464a87aa8d', + }, + priceMode: 'Embedded', + createdAt: '2023-08-30T12:42:27.667Z', + lastModifiedAt: '2023-09-08T19:38:26.588Z', + }; + const productCard = new ProductCard(mockProduct).getElement(); + + it('should be defined', () => { + expect(productCard).toBeDefined(); + }); + it('should have the correct title text', () => { + const titleElement = productCard.querySelector('.product-card__title'); + expect(titleElement?.textContent).toBe('Wildlife of the Rockies'); + }); + it('should have a button with the correct class', () => { + const buttonElement = productCard.querySelector('.product-card__button'); + expect(buttonElement?.classList.contains('button--cart')).toBe(true); + }); +}); diff --git a/src/components/product-card/product-card.ts b/src/components/product-card/product-card.ts new file mode 100644 index 0000000..bf679a4 --- /dev/null +++ b/src/components/product-card/product-card.ts @@ -0,0 +1,156 @@ +import { TypedMoney, type ProductProjection } from '@commercetools/platform-sdk'; +import { ICategory } from '../../types/types'; +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import Link from '../link/link'; +import categories from '../../constants/categories'; +import subcategories from '../../constants/subcategories'; +import formatPrice from '../../utils/formatPrice'; +import addToCart from '../../services/basket/addToCart'; +import Notification from '../notification/notification'; +import cartStore from '../../store/cart-store'; +import './product-card.scss'; + +export default class ProductCard extends BaseComponent<'div'> { + private cartButton: HTMLButtonElement; + private productId: string; + + constructor(product: ProductProjection) { + super('div', ['product-card']); + + this.productId = product.id; + + this.cartButton = this.createButtonCart(); + + this.createMarkup(product); + this.addSubscribtion(); + } + + private createButtonCart(): HTMLButtonElement { + const classes = this.isProductInCart() + ? ['product-card__button', 'product-card__button--added', 'button--cart'] + : ['product-card__button', 'button--cart']; + const isDisabled = this.isProductInCart(); + const button = new Button('button', '', classes, isDisabled, () => this.onAddToCart(this.productId)).getElement(); + + return button; + } + + private createMarkup(product: ProductProjection): void { + const title: string = product.name.en; + const description: string = product.metaDescription?.en || ''; + const image: string = product.masterVariant.images?.[0]?.url || ''; + const reviews: string = product.masterVariant.attributes?.[1]?.value || '0'; + const standardPrice: TypedMoney | undefined = product.masterVariant.prices?.[0]?.value; + const discountedPrice: TypedMoney | undefined = product.masterVariant.prices?.[0]?.discounted?.value; + const days: string = product.masterVariant.attributes?.[2]?.value || ''; + const rating: string = product.masterVariant.attributes?.[0]?.value || ''; + + const linkToProduct = this.createLinkToProduct(product.slug.en, this.productId); + + const cardMedia = new Link('', ['product-card__media'], linkToProduct).getElement(); + const cardImage: HTMLImageElement = new BaseComponent('img', ['product-card__image']).getElement(); + const cardRating = new BaseComponent('div', ['product-card__rating'], rating).getElement(); + if (image) { + cardImage.src = image; + cardMedia.append(cardImage); + } else { + cardMedia.classList.add('product-card__media--placeholder'); + } + + const cardContent = new BaseComponent('div', ['product-card__content']).getElement(); + const cardTitle = new BaseComponent('h4', ['product-card__title'], title).getElement(); + const cardDescription = new BaseComponent('p', ['product-card__description'], description).getElement(); + + const cardMiddle = new BaseComponent('div', ['product-card__middle']).getElement(); + const cardPrice = new BaseComponent('span', ['product-card__price']).getElement(); + const cardPriceDisc = new BaseComponent('span', ['product-card__price', 'product-card__price--new']).getElement(); + + if (standardPrice) { + cardPrice.textContent = formatPrice( + standardPrice.currencyCode, + standardPrice.centAmount, + standardPrice.fractionDigits + ); + cardMiddle.append(cardPrice); + } + + if (discountedPrice) { + cardPriceDisc.textContent = formatPrice( + discountedPrice.currencyCode, + discountedPrice.centAmount, + discountedPrice.fractionDigits + ); + cardPrice.classList.add('product-card__price--old'); + cardMiddle.append(cardPriceDisc); + } + + const cardMiddleDivider = new BaseComponent('div', ['product-card__middle-divider'], '|').getElement(); + const cardDays = new BaseComponent('span', ['product-card__days'], `${days} days`).getElement(); + cardMiddle.append(cardMiddleDivider, cardDays); + + const cardBottom = new BaseComponent('div', ['product-card__bottom']).getElement(); + const cardReviews = new BaseComponent('p', ['product-card__reviews'], `${reviews}+ Reviews`).getElement(); + + cardBottom.append(cardReviews, this.cartButton); + + cardContent.append(cardRating, cardTitle, cardDescription, cardMiddle, cardBottom); + + this.node.append(cardMedia, cardContent); + } + + private createLinkToProduct(slug: string, id: string): string { + const parts: string[] = slug.split('---'); + + const [categorySlug, subcategorySlug] = parts; + + const currentCategory: ICategory | undefined = categories.find((item) => item.slug === categorySlug); + const currentsubCategory: ICategory | undefined = subcategories[categorySlug]?.find( + (item) => item.slug === subcategorySlug + ); + + if (currentCategory && !currentsubCategory) return `/shop/${categorySlug}/${id}`; + if (!currentCategory && !currentsubCategory) return `/shop/${id}`; + if (!currentCategory) return `/shop/${id}`; + + return `/shop/${categorySlug}/${subcategorySlug}/${id}`; + } + + private async onAddToCart(id: string): Promise { + try { + this.cartButton.disabled = true; + this.node.classList.add('card-overlay-enabled'); + + const cart = await addToCart(id); + cartStore.dispatch({ type: 'UPDATE_CART', cart }); + new Notification('success', 'Tour has been successfully added to cart!').showNotification(); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + + this.cartButton.disabled = false; + } finally { + this.node.classList.remove('card-overlay-enabled'); + } + } + + private isProductInCart(): boolean { + const { cart } = cartStore.getState(); + return !!cart?.lineItems.find((item) => item.productId === this.productId); + } + + private addSubscribtion(): void { + cartStore.subscribe((state) => { + if (state.cart?.lineItems.find((item) => item.productId === this.productId)) { + this.cartButton.classList.add('product-card__button--added'); + this.cartButton.disabled = true; + } else { + this.cartButton.classList.remove('product-card__button--added'); + this.cartButton.disabled = false; + } + }); + } +} diff --git a/src/components/product-list/product-list.scss b/src/components/product-list/product-list.scss new file mode 100644 index 0000000..452142d --- /dev/null +++ b/src/components/product-list/product-list.scss @@ -0,0 +1,37 @@ +.product-list { + padding: 48px 0; + + &__container { + @include container; + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 24px; + position: relative; + + @include laptop { + grid-template-columns: repeat(3, 1fr); + } + + @include pre-tablet { + grid-template-columns: repeat(2, 1fr); + } + + @include mobile { + grid-template-columns: 1fr; + } + + &--loading { + &::after { + position: absolute; + top: 0; + left: 50%; + transform: translateY(-50%); + content: 'Loading'; + } + } + } + + &__empty { + @include font-h4; + } +} diff --git a/src/components/product-list/product-list.ts b/src/components/product-list/product-list.ts new file mode 100644 index 0000000..5dc3676 --- /dev/null +++ b/src/components/product-list/product-list.ts @@ -0,0 +1,38 @@ +import { type ProductProjection } from '@commercetools/platform-sdk'; +import BaseComponent from '../base-component'; +import ProductCard from '../product-card/product-card'; +import './product-list.scss'; + +export default class ProductList extends BaseComponent<'section'> { + private items: ProductProjection[]; + private cards: HTMLDivElement[]; + private container: HTMLDivElement; + + constructor(items: ProductProjection[]) { + super('section', ['product-list']); + + this.items = items; + this.cards = []; + this.container = new BaseComponent('div', ['product-list__container']).getElement(); + + this.createMarkup(); + } + + private async createMarkup(): Promise { + if (this.items.length) { + this.cards = this.items.map((item) => { + return new ProductCard(item).getElement(); + }); + this.container.append(...this.cards); + } else { + const emptyListText = new BaseComponent('div', ['product-list__empty'], 'No tours found').getElement(); + this.container.append(emptyListText); + } + + this.node.append(this.container); + } + + public addNewProducts(cards: HTMLElement[]): void { + this.container.append(...cards); + } +} diff --git a/src/components/product/product.scss b/src/components/product/product.scss new file mode 100644 index 0000000..8f630ed --- /dev/null +++ b/src/components/product/product.scss @@ -0,0 +1,129 @@ +.product { + display: flex; + flex-direction: column; + gap: 40px; + width: calc(50% - 12px); + padding: 64px; + background-color: $color-bg-card; + border-radius: 8px; + + @include tablet { + gap: 20px; + padding: 32px; + } + + @include laptop { + width: 80%; + } + + @include mobile { + width: 100%; + } + + &__routes { + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + opacity: 0.5; + } + + &__info { + display: flex; + flex-direction: column; + gap: 16px; + + @include tablet { + gap: 8px; + } + } + + &__title { + @include font-h2; + } + + &__opinion { + display: flex; + gap: 10px; + align-items: center; + color: $color-secondary-40; + } + + &__rating { + position: relative; + display: flex; + align-items: center; + padding: 4px 8px 4px 28px; + font-weight: 700; + font-size: 14px; + color: $color-primary; + background-color: white; + border-radius: 30px; + + &::before { + position: absolute; + display: block; + content: ''; + left: 8px; + width: 16px; + height: 16px; + background: url('../../assets/icons/star.svg') center/cover no-repeat; + } + } + + &__stock { + display: flex; + align-items: center; + padding-left: 22px; + position: relative; + font-weight: 700; + + &::before { + position: absolute; + display: block; + content: ''; + left: 0; + width: 18px; + height: 18px; + background: url('../../assets/icons/check.svg') center/cover no-repeat; + } + } + + &__add-to-cart { + & button { + width: 100%; + box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.08); + } + } + + &__about { + display: flex; + flex-direction: column; + gap: 16px; + + @include tablet { + gap: 8px; + } + + &-item { + display: flex; + flex-direction: column; + gap: 5px; + padding-bottom: 16px; + border-bottom: 1px solid rgba(0, 19, 41, 0.12); + + @include tablet { + padding-bottom: 8px; + } + + &:nth-last-child(1) { + padding-bottom: 0; + border: none; + } + + & p { + font-size: 14px; + margin-left: 5px; + } + } + } +} diff --git a/src/components/product/product.ts b/src/components/product/product.ts new file mode 100644 index 0000000..b8408c7 --- /dev/null +++ b/src/components/product/product.ts @@ -0,0 +1,219 @@ +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import { Price, ProductData, TypedMoney } from '@commercetools/platform-sdk'; +import formatPrice from '../../utils/formatPrice'; +import Notification from '../notification/notification'; +import addToCart from '../../services/basket/addToCart'; +import removeProductFromCart from '../../services/basket/removeProductFromCart'; +import cartStore from '../../store/cart-store'; +import './product.scss'; + +interface ProductAttributes { + [name: string]: string; +} + +export default class Product extends BaseComponent<'div'> { + private productForm: HTMLDivElement = new BaseComponent('div').getElement(); + private cartButton: HTMLButtonElement = new Button('button', 'Cart').getElement(); + private productData: ProductData | null = null; + private productAttributes: ProductAttributes = { + rating: '-', + reviews: '0', + days: 'Please ask about tour duration by writing to us at this.is.this@gmail.com', + inStock: 'Please check availability by writing to us at this.is.this@gmail.com', + location: 'Paradise', + shortDescription: 'No information about this tour', + adventureStyle: 'Relax', + aboutTour: 'No information about this tour', + }; + private productId: string; + private removeFromCartBtn = new Button('button', 'Remove From Cart', ['button--white'], false, () => + this.onRemoveFromCart() + ).getElement(); + private addToCartBtn = new Button('button', 'Add To Cart', [], false, () => this.onAddToCart()).getElement(); + + constructor(productId: string, productData: ProductData) { + super('div', ['product']); + + this.productData = productData; + this.productId = productId; + + this.createMarkup(); + } + + private createMarkup(): void { + this.getProductAttributes(); + + const productInfo = this.drawProductInfo(); + this.productForm = this.drawProductForm(); + const productAbout = this.drawProductAbout(); + + this.node.append(productInfo, this.productForm, productAbout); + } + + private drawProductPrice(): HTMLDivElement { + const productPrices = new BaseComponent('div', ['product__prices']).getElement(); + + const prices: Price[] | undefined = this.productData?.masterVariant.prices; + + if (prices?.length) { + const standardPrice: TypedMoney = prices[0].value; + const discountedPrice: TypedMoney | undefined = prices[0].discounted?.value; + + const productPrice = new BaseComponent( + 'span', + ['product-card__price'], + formatPrice(standardPrice.currencyCode, standardPrice.centAmount, standardPrice.fractionDigits) + ).getElement(); + + productPrices.append(productPrice); + + if (discountedPrice) { + const productDiscountedPrice = new BaseComponent( + 'span', + ['product-card__price', 'product-card__price--new'], + formatPrice(discountedPrice.currencyCode, discountedPrice.centAmount, discountedPrice.fractionDigits) + ).getElement(); + + productPrice.classList.add('product-card__price--old'); + productPrices.append(productDiscountedPrice); + } + } + + return productPrices; + } + + private drawProductInfo(): HTMLDivElement { + const title = this.productData?.name.en || 'Unnamed tour'; + const { rating, reviews, inStock, shortDescription, adventureStyle } = this.productAttributes; + + const productRoutes = new BaseComponent('p', ['product__routes'], adventureStyle).getElement(); + const productInfo = new BaseComponent('div', ['product__info']).getElement(); + const productOpinion = new BaseComponent('div', ['product__opinion']).getElement(); + const productTitle = new BaseComponent('h2', ['product__title'], title).getElement(); + const productPrice = this.drawProductPrice(); + const productRating = new BaseComponent('p', ['product__rating'], rating).getElement(); + const productReviews = new BaseComponent('p', ['product__reviews'], `${reviews}+ Reviews`).getElement(); + const productDescription = new BaseComponent('p', ['product__description'], shortDescription).getElement(); + const productStock = new BaseComponent('p', ['product__stock'], `${inStock} In Stock`).getElement(); + + productOpinion.append(productRating, productReviews); + productInfo.append(productRoutes, productTitle, productPrice, productOpinion, productDescription, productStock); + + return productInfo; + } + + private getProductAttributes(): void { + const attributes = this.productData?.masterVariant.attributes; + + if (attributes) { + for (const key of attributes) { + if (key.name in this.productAttributes) { + this.productAttributes[key.name] = key.value; + } + } + } + } + + private drawProductForm(): HTMLDivElement { + const productForm = new BaseComponent('div', ['product__add-to-cart']).getElement(); + + this.drawButton(); + + productForm.append(this.cartButton); + + return productForm; + } + + private drawButton(): void { + if (this.isProductInCart()) { + this.cartButton = this.removeFromCartBtn; + } else { + this.cartButton = this.addToCartBtn; + } + } + + private drawProductAbout(): HTMLUListElement { + const { aboutTour, location } = this.productAttributes; + + const productAbout = new BaseComponent('ul', ['product__about']).getElement(); + const productAboutItem = new BaseComponent('li', ['product__about-item'], 'About Tour').getElement(); + const productLocationItem = new BaseComponent('li', ['product__about-item'], 'Location').getElement(); + + aboutTour + .slice(0, -1) + .split('.') + .forEach((sentence) => { + const aboutTourSentence = new BaseComponent('p', ['product__description'], `${sentence}.`).getElement(); + + productAboutItem.append(aboutTourSentence); + }); + + const productLocation = new BaseComponent('p', ['product__description'], location).getElement(); + + productLocationItem.append(productLocation); + productAbout.append(productAboutItem, productLocationItem); + + return productAbout; + } + + private async onAddToCart(): Promise { + try { + this.cartButton.disabled = true; + this.node.classList.add('card-overlay-enabled'); + + const updatedCart = await addToCart(this.productId); + cartStore.dispatch({ type: 'UPDATE_CART', cart: updatedCart }); + new Notification('success', 'Tour has been successfully added to cart!').showNotification(); + + this.cartButton = this.removeFromCartBtn; + + this.productForm.innerHTML = ''; + this.productForm.append(this.cartButton); + + this.cartButton.disabled = false; + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + } finally { + this.cartButton.disabled = false; + this.node.classList.remove('card-overlay-enabled'); + } + } + + private async onRemoveFromCart(): Promise { + try { + this.cartButton.disabled = true; + this.node.classList.add('card-overlay-enabled'); + + const updatedCart = await removeProductFromCart(this.productId); + + cartStore.dispatch({ type: 'UPDATE_CART', cart: updatedCart }); + new Notification('success', 'Tour has been successfully removed from cart!').showNotification(); + + this.cartButton = this.addToCartBtn; + + this.productForm.innerHTML = ''; + this.productForm.append(this.cartButton); + + this.cartButton.disabled = false; + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + } finally { + this.cartButton.disabled = false; + this.node.classList.remove('card-overlay-enabled'); + } + } + + private isProductInCart(): boolean { + const { cart } = cartStore.getState(); + return !!cart?.lineItems.find((item) => item.productId === this.productId); + } +} diff --git a/src/components/promo-codes/promo-codes-list.test.ts b/src/components/promo-codes/promo-codes-list.test.ts new file mode 100644 index 0000000..c03524e --- /dev/null +++ b/src/components/promo-codes/promo-codes-list.test.ts @@ -0,0 +1,38 @@ +import PromoCodesList from './promo-codes-list'; + +describe('PromoCodesList Component', () => { + const promoCodesList = new PromoCodesList().getElement(); + + it('should render without errors', () => { + expect(promoCodesList).toBeDefined(); + }); + + it('should have the correct tag name', () => { + expect(promoCodesList.tagName).toBe('UL'); + }); + + it('should have the "promo-codes-list" class', () => { + expect(promoCodesList.classList.contains('promo-codes-list')).toBe(true); + }); + + it('should render promo code items', () => { + const promoCodeItems = promoCodesList.querySelectorAll('.promo-codes-item'); + expect(promoCodeItems.length).toBeGreaterThan(0); + }); + + it('should handle copy promo code', () => { + const clipboardMock = { + writeText: jest.fn(), + }; + Object.defineProperty(global.navigator, 'clipboard', { + value: clipboardMock, + }); + + const promoCodeItem = promoCodesList.querySelector('.promo-codes-item')!; + const copyButton: HTMLButtonElement | null = promoCodeItem.querySelector('.promo-codes-item__button'); + + copyButton!.click(); + + expect(clipboardMock.writeText).toHaveBeenCalled(); + }); +}); diff --git a/src/components/promo-codes/promo-codes-list.ts b/src/components/promo-codes/promo-codes-list.ts new file mode 100644 index 0000000..285f112 --- /dev/null +++ b/src/components/promo-codes/promo-codes-list.ts @@ -0,0 +1,53 @@ +import promoCodes from '../../constants/promoCodes'; +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import InputField from '../input/input'; +import Notification from '../notification/notification'; +import './promo-codes.scss'; + +export default class PromoCodesList extends BaseComponent<'ul'> { + constructor() { + super('ul', ['promo-codes-list']); + this.renderPromoCodesList(); + } + + private handleCopyPromoCode(code: string): void { + navigator.clipboard.writeText(code); + new Notification('success', 'This Promo Code is successfully saved to clipboard!').showNotification(); + } + + private renderPromoCodesList(): void { + promoCodes.forEach((obj) => { + const item = new BaseComponent('li', ['promo-codes-item']).getElement(); + + const firstWrapp = new BaseComponent('div', ['promo-codes-item__wrapp']).getElement(); + const itemImg = new BaseComponent('span', ['promo-codes-item__img', obj.code]).getElement(); + const itemTitle = new BaseComponent('h4', ['promo-codes-item__title'], obj.title).getElement(); + const itemDescr = new BaseComponent('h4', ['promo-codes-item__descr'], obj.descr).getElement(); + firstWrapp.append(itemImg, itemTitle, itemDescr); + + const secondWrapp = new BaseComponent('div', ['promo-codes-item__wrapp']).getElement(); + const itemActions = new BaseComponent('div', ['promo-codes-item__actions']).getElement(); + const itemInput = new InputField('text', '', '', '', ['promo-codes-item__input']); + itemInput.setValue(obj.code); + itemInput.setAttribute('readonly', 'readonly'); + const inputBtn = new Button('button', 'Copy', ['promo-codes-item__button'], false, () => + this.handleCopyPromoCode(obj.code) + ).getElement(); + + itemActions.append(itemInput.getElement(), inputBtn); + + const itemDateText = new BaseComponent( + 'p', + ['promo-codes-item__date'], + `Promo Code valid until ${obj.expirationDate}` + ).getElement(); + + secondWrapp.append(itemActions, itemDateText); + + item.append(firstWrapp, secondWrapp); + + this.node.append(item); + }); + } +} diff --git a/src/components/promo-codes/promo-codes.scss b/src/components/promo-codes/promo-codes.scss new file mode 100644 index 0000000..bc7c48d --- /dev/null +++ b/src/components/promo-codes/promo-codes.scss @@ -0,0 +1,139 @@ +.promo-codes { + padding: 104px 0; + background-color: $color-bg-light; + + @include mobile { + padding: 60px 0; + } + + &__container { + @include container; + } + + &__title { + @include font-h2; + margin-bottom: 48px; + } + + &-list { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-gap: 24px; + gap: 24px; + + @include laptop { + grid-template-columns: repeat(2, 1fr); + } + + @include mobile { + grid-template-columns: repeat(1, 1fr); + } + } + + &-item { + padding: 32px; + background: $color-white; + border-radius: 8px; + display: flex; + flex-direction: column; + justify-content: space-between; + + &__img { + margin-bottom: 24px; + display: block; + width: 116px; + height: 116px; + border-radius: 8px; + background-color: #fff; + background-image: url('../../assets/img/placeholder-image.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + overflow: hidden; + + &.FAMILYFUN { + background-image: url('../../assets/img/promo-codes/FAMILYFUN.jpg'); + } + &.LASTCHANCE { + background-image: url('../../assets/img/promo-codes/LASTCHANCE.jpg'); + } + &.CRUISE100 { + background-image: url('../../assets/img/promo-codes/CRUISE100.jpg'); + } + &.GROUP24 { + background-image: url('../../assets/img/promo-codes/GROUP24.jpg'); + } + } + + &__title { + @include font-h4; + margin-bottom: 12px; + } + + &__descr { + margin-bottom: 67px; + + @include small-mobile { + margin-bottom: 30px; + } + } + + &__actions { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16px; + + @media (max-width: 1600px) { + flex-direction: column; + } + + @include laptop { + flex-direction: row; + } + + @include small-mobile { + flex-direction: column; + } + } + + &__input { + width: 100%; + + & label { + margin-bottom: 0; + } + + & input { + height: 55px; + font: $font-label; + background: $color-bg-light; + border: 1px solid $color-bg-light; + } + } + + &__button { + margin: 0 0 0 8px; + + @media (max-width: 1600px) { + margin: 12px 0 0 0; + width: 100%; + } + + @include laptop { + margin: 0 0 0 8px; + width: auto; + } + + @include small-mobile { + margin: 12px 0 0 0; + width: 100%; + } + } + + &__date { + font: $font-xs; + opacity: 0.5; + } + } +} diff --git a/src/components/promo-codes/promo-codes.test.ts b/src/components/promo-codes/promo-codes.test.ts new file mode 100644 index 0000000..552f532 --- /dev/null +++ b/src/components/promo-codes/promo-codes.test.ts @@ -0,0 +1,28 @@ +import PromoCodes from './promo-codes'; + +describe('PromoCodes', () => { + const promoCodes = new PromoCodes().getElement(); + + it('should render without errors', () => { + expect(promoCodes).toBeDefined(); + }); + + it('should have the correct tag name', () => { + expect(promoCodes.tagName).toBe('SECTION'); + }); + + it('should have the "promo-codes" class', () => { + expect(promoCodes.classList.contains('promo-codes')).toBe(true); + }); + + it('should render a title', () => { + const title = promoCodes.querySelector('.promo-codes__title'); + expect(title).toBeDefined(); + expect(title?.textContent).toBe('Your Passport to Savings: Travel Promo Deals'); + }); + + it('should render a PromoCodesList', () => { + const promoCodesList = promoCodes.querySelector('.promo-codes__container .promo-codes-list'); + expect(promoCodesList).toBeDefined(); + }); +}); diff --git a/src/components/promo-codes/promo-codes.ts b/src/components/promo-codes/promo-codes.ts new file mode 100644 index 0000000..78367eb --- /dev/null +++ b/src/components/promo-codes/promo-codes.ts @@ -0,0 +1,24 @@ +import BaseComponent from '../base-component'; +import PromoCodesList from './promo-codes-list'; +import './promo-codes.scss'; + +export default class PromoCodes extends BaseComponent<'section'> { + constructor() { + super('section', ['promo-codes']); + this.renderPromoCodes(); + } + + private renderPromoCodes(): void { + const container = new BaseComponent('div', ['promo-codes__container']).getElement(); + const title = new BaseComponent( + 'h2', + ['promo-codes__title'], + 'Your Passport to Savings: Travel Promo Deals' + ).getElement(); + const list = new PromoCodesList().getElement(); + + container.append(title, list); + + this.node.append(container); + } +} diff --git a/src/components/select/select-type.ts b/src/components/select/select-type.ts new file mode 100644 index 0000000..1d46457 --- /dev/null +++ b/src/components/select/select-type.ts @@ -0,0 +1,50 @@ +import BaseComponent from '../base-component'; +import './select.scss'; + +export default class SelectTypeField extends BaseComponent<'div'> { + private labelElement: HTMLLabelElement; + private selectElement: HTMLSelectElement; + + constructor(name: string = '', classes: string[] = []) { + super('div', ['form-field', ...classes]); + + this.labelElement = new BaseComponent('label', ['form-field__label'], 'Type').getElement(); + this.selectElement = new BaseComponent('select', ['form-field__input']).getElement(); + + this.setAttributes(name); + + this.createSelectField(); + + this.node.append(this.labelElement, this.selectElement); + } + + public getValue(): string | undefined { + return this.selectElement.value.trim(); + } + + public setValue(firstValue: boolean | undefined, secondValue: boolean | undefined): void { + if (firstValue && secondValue) { + this.selectElement.value = 'Billing, Shipping'; + } else if (firstValue) { + this.selectElement.value = 'Billing'; + } else { + this.selectElement.value = 'Shipping'; + } + } + + private setAttributes(name: string = ''): void { + this.selectElement.name = name; + this.selectElement.id = name; + this.labelElement.setAttribute('for', name); + } + + private createSelectField(): void { + const types = ['Billing', 'Shipping', 'Billing, Shipping']; + types.forEach((type) => { + const option = new BaseComponent('option', ['form-field__input']).getElement(); + option.value = type; + option.text = type; + this.selectElement.appendChild(option); + }); + } +} diff --git a/src/components/select/select.scss b/src/components/select/select.scss new file mode 100644 index 0000000..6784618 --- /dev/null +++ b/src/components/select/select.scss @@ -0,0 +1,50 @@ +.select-field { + position: relative; + display: flex; + border-radius: 6px; + overflow: hidden; + + &__select { + appearance: none; + outline: none; + border: 0; + box-shadow: none; + flex: 1; + padding: 16px 24px; + width: 260px; + font: $font-main; + color: $color-primary; + background-color: rgba($color-primary, 0.03); + background-image: none; + cursor: pointer; + } + + &__select::-ms-expand { + display: none; + } + + &::after { + position: absolute; + top: 50%; + right: 24px; + display: block; + content: ''; + width: 20px; + height: 20px; + background-image: url('../../assets/icons/chevron-up.svg'); + transform: translateY(-50%) rotate(180deg); + background-position: center; + background-size: cover; + pointer-events: none; + } + + &__option { + &[value=''] { + display: none; + + .select--sort & { + display: block; + } + } + } +} diff --git a/src/components/select/select.ts b/src/components/select/select.ts new file mode 100644 index 0000000..e6f3f42 --- /dev/null +++ b/src/components/select/select.ts @@ -0,0 +1,60 @@ +import shopStore from '../../store/shop-store'; +import BaseComponent from '../base-component'; +import './select.scss'; + +interface IOption { + label: string; + value: string; +} + +export default class SelectField extends BaseComponent<'div'> { + private selectElement: HTMLSelectElement; + + constructor(name: string = '', options: IOption[], classes: string[] = []) { + super('div', ['select-field', ...classes]); + + this.selectElement = new BaseComponent('select', ['select-field__select']).getElement(); + + this.renderSelect(name, options); + this.setListener(); + } + + private renderSelect(name: string, options: IOption[]): void { + this.selectElement.id = name; + this.selectElement.name = name; + + const optionsElements = options.map((option): HTMLOptionElement => { + const optionEl = new BaseComponent('option', ['select-field__option'], option.label).getElement(); + optionEl.value = option.value; + if (name === 'price' && shopStore.getState().filterPrice === option.value) { + optionEl.selected = true; + } + if (name === 'days' && shopStore.getState().filterDays === option.value) { + optionEl.selected = true; + } + if (name === 'sort' && shopStore.getState().sortValue === option.value) { + optionEl.selected = true; + } + return optionEl; + }); + + this.selectElement.append(...optionsElements); + + this.node.append(this.selectElement); + } + + private setListener(): void { + this.selectElement.addEventListener('change', (event) => { + event.preventDefault(); + if (event.currentTarget instanceof HTMLSelectElement && event.currentTarget.id === 'price') { + shopStore.dispatch({ type: 'SET_FILTER_PRICE', newFilterPrice: event.currentTarget.value }); + } + if (event.currentTarget instanceof HTMLSelectElement && event.currentTarget.id === 'days') { + shopStore.dispatch({ type: 'SET_FILTER_DAYS', newFilterDays: event.currentTarget.value }); + } + if (event.currentTarget instanceof HTMLSelectElement && event.currentTarget.id === 'sort') { + shopStore.dispatch({ type: 'SET_SORT_VALUE', newSortValue: event.currentTarget.value }); + } + }); + } +} diff --git a/src/components/shop-flters/shop-filters.scss b/src/components/shop-flters/shop-filters.scss new file mode 100644 index 0000000..19b1980 --- /dev/null +++ b/src/components/shop-flters/shop-filters.scss @@ -0,0 +1,8 @@ +.shop-filters { + &__form { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 24px; + } +} diff --git a/src/components/shop-flters/shop-filters.ts b/src/components/shop-flters/shop-filters.ts new file mode 100644 index 0000000..3d22c60 --- /dev/null +++ b/src/components/shop-flters/shop-filters.ts @@ -0,0 +1,51 @@ +import daysFilterOptions from '../../constants/daysFilterOptions'; +import priceFilterOptions from '../../constants/priceFilterOptions'; +import shopStore from '../../store/shop-store'; +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import Select from '../select/select'; +import './shop-filters.scss'; + +export default class ShopFilters extends BaseComponent<'div'> { + private formFilter: HTMLFormElement; + private resetButton: HTMLButtonElement; + + constructor() { + super('div', ['shop-filters']); + + this.formFilter = new BaseComponent('form', ['shop-filters__form']).getElement(); + this.resetButton = new Button('reset', 'Reset', ['button--reset'], this.checkDisableBtn(), () => { + this.formFilter.reset(); + shopStore.dispatch({ type: 'RESET_ALL_FILTERS' }); + }).getElement(); + + this.renderFilters(); + this.addSubscribtion(); + } + + private checkDisableBtn(): boolean { + const { filterPrice, filterDays } = shopStore.getState(); + if (filterPrice || filterDays) { + return false; + } + return true; + } + + private renderFilters(): void { + const selectPrice: HTMLDivElement = new Select('price', priceFilterOptions).getElement(); + const selectDays: HTMLDivElement = new Select('days', daysFilterOptions).getElement(); + + this.formFilter.append(selectPrice, selectDays, this.resetButton); + this.node.append(this.formFilter); + } + + private addSubscribtion(): void { + shopStore.subscribe((state) => { + if (state.filterPrice || state.filterDays) { + this.resetButton.disabled = false; + } else { + this.resetButton.disabled = true; + } + }); + } +} diff --git a/src/components/shop-hero/shop-hero.scss b/src/components/shop-hero/shop-hero.scss new file mode 100644 index 0000000..69ce863 --- /dev/null +++ b/src/components/shop-hero/shop-hero.scss @@ -0,0 +1,69 @@ +.shop-hero { + &__container { + @include container; + } + + &__wrapper { + display: flex; + gap: 72px; + width: 100%; + padding-bottom: 104px; + border-bottom: 1px solid $color-border; + } + + &__content { + display: flex; + flex-direction: column; + max-width: 500px; + align-self: flex-end; + } + + &__title { + @include font-h2; + margin-bottom: 24px; + } + + &__text { + font-size: 18px; + line-height: 150%; + } + + &__image { + width: 100%; + height: 300px; + border-radius: 8px; + overflow: hidden; + background-image: url('../../assets/img/shop_hero-image.jpg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + + @include tablet { + display: none; + } + + &--europe { + background-image: url('../../assets/img/shop_hero-image_europe.jpg'); + } + + &--asia { + background-image: url('../../assets/img/shop_hero-image_asia.jpg'); + } + + &--africa { + background-image: url('../../assets/img/shop_hero-image_africa.jpg'); + } + + &--america { + background-image: url('../../assets/img/shop_hero-image_america.jpg'); + } + + &--hiking { + background-image: url('../../assets/img/shop_hero-image_hiking.jpg'); + } + + &--sailing { + background-image: url('../../assets/img/shop_hero-image_sailing.jpg'); + } + } +} diff --git a/src/components/shop-hero/shop-hero.test.ts b/src/components/shop-hero/shop-hero.test.ts new file mode 100644 index 0000000..542457e --- /dev/null +++ b/src/components/shop-hero/shop-hero.test.ts @@ -0,0 +1,17 @@ +import ShopHero from './shop-hero'; + +describe('ShopHero', () => { + const shopHero: HTMLElement = new ShopHero('Europe').getElement(); + + it('should be defined', () => { + expect(shopHero).toBeDefined(); + }); + it('should have the correct title text', () => { + const titleElement = shopHero.querySelector('.shop-hero__title'); + expect(titleElement?.textContent).toBe('Europe'); + }); + it('should have the correct image class', () => { + const imageBlock = shopHero.querySelector('.shop-hero__image'); + expect(imageBlock?.classList.contains('shop-hero__image--europe')).toBe(true); + }); +}); diff --git a/src/components/shop-hero/shop-hero.ts b/src/components/shop-hero/shop-hero.ts new file mode 100644 index 0000000..60511aa --- /dev/null +++ b/src/components/shop-hero/shop-hero.ts @@ -0,0 +1,44 @@ +import BaseComponent from '../base-component'; +import './shop-hero.scss'; + +export default class ShopHero extends BaseComponent<'section'> { + constructor(titleText: string) { + super('section', ['shop-hero']); + + this.drawSection(titleText); + } + + private drawSection(titleText: string): void { + const container: HTMLDivElement = new BaseComponent('div', ['shop-hero__container']).getElement(); + const wrapper: HTMLDivElement = new BaseComponent('div', ['shop-hero__wrapper']).getElement(); + const content: HTMLDivElement = new BaseComponent('div', ['shop-hero__content']).getElement(); + const title: HTMLHeadingElement = new BaseComponent('h2', ['shop-hero__title'], titleText).getElement(); + const text: HTMLParagraphElement = new BaseComponent( + 'p', + ['shop-hero__text'], + 'Satisfy your wanderlust with our collection of exclusive tours tailored to quench your thirst for exploration.' + ).getElement(); + const imageBlock = new BaseComponent('div', ['shop-hero__image']).getElement(); + + if (titleText === 'Europe') { + imageBlock.classList.add('shop-hero__image--europe'); + } else if (titleText === 'Asia') { + imageBlock.classList.add('shop-hero__image--asia'); + } else if (titleText === 'Africa') { + imageBlock.classList.add('shop-hero__image--africa'); + } else if (titleText === 'America') { + imageBlock.classList.add('shop-hero__image--america'); + } else if (titleText === 'Hiking & Trekking') { + imageBlock.classList.add('shop-hero__image--hiking'); + } else if (titleText === 'Sailing') { + imageBlock.classList.add('shop-hero__image--sailing'); + } else if (titleText === 'Safari') { + imageBlock.classList.add('shop-hero__image--africa'); + } + + content.append(title, text); + wrapper.append(content, imageBlock); + container.append(wrapper); + this.node.append(container); + } +} diff --git a/src/components/shop-search/shop-search.scss b/src/components/shop-search/shop-search.scss new file mode 100644 index 0000000..c8dcca2 --- /dev/null +++ b/src/components/shop-search/shop-search.scss @@ -0,0 +1,66 @@ +.shop-search { + margin-top: 48px; + + &__container { + @include container; + } + + &__form { + display: flex; + align-items: center; + gap: 24px; + } + + &__input-field { + width: 544px; + position: relative; + + @include mobile { + width: auto; + min-width: 0; + } + } + + &__input { + width: 100%; + height: 56px; + border: solid 1px $color-border; + transition: border 0.3s ease-in-out; + + &:focus, + &:active, + &:hover { + border: 1px solid $color-secondary-60; + } + } + + &__button { + height: 56px; + + @include mobile { + padding: 16px; + } + } + + &__reset { + position: absolute; + top: 50%; + right: 10px; + transform: translateY(-50%); + width: 15px; + height: 15px; + background-image: url('../../assets/icons/popup-close-icon.svg'); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + cursor: pointer; + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease-in-out; + + &--visible { + opacity: 1; + pointer-events: all; + } + } +} diff --git a/src/components/shop-search/shop-search.ts b/src/components/shop-search/shop-search.ts new file mode 100644 index 0000000..cf46eca --- /dev/null +++ b/src/components/shop-search/shop-search.ts @@ -0,0 +1,81 @@ +import shopStore from '../../store/shop-store'; +import BaseComponent from '../base-component'; +import Button from '../button/button'; +import './shop-search.scss'; +import '../input/input.scss'; + +export default class ShopSearch extends BaseComponent<'div'> { + private formSearch: HTMLFormElement; + private searchInput: HTMLInputElement; + private searchButton: HTMLButtonElement; + private resetButton: HTMLDivElement; + + constructor(initialValue?: string) { + super('div', ['shop-search']); + + this.formSearch = new BaseComponent('form', ['shop-search__form']).getElement(); + this.searchInput = new BaseComponent('input', ['form-field__input', 'shop-search__input']).getElement(); + this.searchButton = new Button('submit', 'Search', ['shop-search__button'], true).getElement(); + this.resetButton = new BaseComponent('div', ['shop-search__reset']).getElement(); + + this.searchInput.id = 'search'; + this.searchInput.name = 'search'; + this.searchInput.placeholder = 'Search'; + + if (initialValue) { + this.searchInput.value = initialValue; + this.searchButton.disabled = false; + this.resetButton.classList.add('shop-search__reset--visible'); + } + + this.renderSearchPanel(); + this.setListeners(); + } + + private renderSearchPanel(): void { + const container: HTMLDivElement = new BaseComponent('div', ['shop-search__container']).getElement(); + const inputWrapper: HTMLDivElement = new BaseComponent('div', ['shop-search__input-field']).getElement(); + + inputWrapper.append(this.searchInput, this.resetButton); + this.formSearch.append(inputWrapper, this.searchButton); + container.append(this.formSearch); + this.node.append(container); + } + + private getSearchValue(): string | undefined { + return new FormData(this.formSearch).get('search')?.toString(); + } + + private onSubmit(event: SubmitEvent): void { + event.preventDefault(); + + const searchValue = this.getSearchValue(); + + if (searchValue !== undefined && searchValue !== shopStore.getState().searchValue) { + shopStore.dispatch({ type: 'SET_SEARCH_VALUE', newSearchValue: searchValue }); + } + } + + private resetSearch(): void { + this.formSearch.reset(); + this.resetButton.classList.remove('shop-search__reset--visible'); + this.searchButton.disabled = true; + + if (shopStore.getState().searchValue !== '') { + shopStore.dispatch({ type: 'SET_SEARCH_VALUE', newSearchValue: '' }); + } + } + + private setListeners(): void { + this.searchInput.addEventListener('input', (event) => { + if (event.currentTarget instanceof HTMLInputElement && event.currentTarget.value) { + this.searchButton.disabled = false; + this.resetButton.classList.add('shop-search__reset--visible'); + } else { + this.resetSearch(); + } + }); + this.formSearch.addEventListener('submit', (event) => this.onSubmit(event)); + this.resetButton.addEventListener('click', () => this.resetSearch()); + } +} diff --git a/src/components/shop-sort/shop-sort.scss b/src/components/shop-sort/shop-sort.scss new file mode 100644 index 0000000..ecbb6a1 --- /dev/null +++ b/src/components/shop-sort/shop-sort.scss @@ -0,0 +1,9 @@ +.shop-sort { + display: flex; + align-items: center; + gap: 12px; + + @include mobile { + flex-wrap: wrap; + } +} diff --git a/src/components/shop-sort/shop-sort.ts b/src/components/shop-sort/shop-sort.ts new file mode 100644 index 0000000..d7c8dcf --- /dev/null +++ b/src/components/shop-sort/shop-sort.ts @@ -0,0 +1,19 @@ +import sortShopOptions from '../../constants/sortShopOptions'; +import BaseComponent from '../base-component'; +import Select from '../select/select'; +import './shop-sort.scss'; + +export default class ShopSort extends BaseComponent<'div'> { + constructor() { + super('div', ['shop-sort']); + + this.renderSort(); + } + + private renderSort(): void { + const selectSortLabel: HTMLSpanElement = new BaseComponent('span', [], 'Sort By:').getElement(); + const selectSort: HTMLDivElement = new Select('sort', sortShopOptions, ['select--sort']).getElement(); + + this.node.append(selectSortLabel, selectSort); + } +} diff --git a/src/components/slider/slider.scss b/src/components/slider/slider.scss new file mode 100644 index 0000000..8caf519 --- /dev/null +++ b/src/components/slider/slider.scss @@ -0,0 +1,101 @@ +.product__slider { + display: flex; + flex-direction: column; + width: calc(50% - 12px); + gap: 24px; + user-select: none; + + @include laptop { + width: 80%; + } + + @include mobile { + width: 100%; + } + + .swiper { + width: 100%; + + &-list { + display: flex; + + .swiper-slide { + width: 25%; + aspect-ratio: 3/2; + opacity: 0.4; + + &-thumb-active { + opacity: 1; + } + } + } + + &-view { + display: flex; + + .swiper-slide { + width: 100%; + aspect-ratio: 3/2; + + &-active { + cursor: zoom-in; + } + } + } + + &-wrapper { + width: 100%; + display: flex; + } + + &-slide img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 8px; + } + } + + &_modal { + display: flex; + justify-content: center; + max-width: 100%; + max-height: 80vh; + user-select: none; + z-index: 20; + + .swiper-view { + max-height: 100%; + width: 100%; + } + + .swiper-slide { + display: flex; + justify-content: center; + width: 100%; + } + + & img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 8px; + } + } +} + +.swiper-button { + &-next, + &-prev { + opacity: 0.6; + color: #ffffff; + cursor: pointer; + transition: opacity 0.3s ease; + + &:hover { + opacity: 1; + } + } +} diff --git a/src/components/slider/slider.ts b/src/components/slider/slider.ts new file mode 100644 index 0000000..64139ce --- /dev/null +++ b/src/components/slider/slider.ts @@ -0,0 +1,170 @@ +import Swiper from 'swiper'; +import BaseComponent from '../base-component'; +import { Image } from '@commercetools/platform-sdk'; +import { Navigation, Thumbs } from 'swiper/modules'; +import 'swiper/css/navigation'; +import 'swiper/css'; +import './slider.scss'; + +interface IMainComponents { + sliderView: HTMLDivElement; + sliderBtnNext: HTMLDivElement; + sliderBtnPrev: HTMLDivElement; + sliderList: HTMLDivElement; +} + +export default class ProductSlider extends BaseComponent<'div'> { + private images: Image[]; + private sliderView: HTMLElement; + private sliderList: HTMLElement; + private sliderBtnNext: HTMLElement; + private sliderBtnPrev: HTMLElement; + private modalWindow: HTMLElement; + + constructor(images: Image[]) { + super('div', ['product__slider']); + this.images = images; + + const mainComponents = this.initMainComponents(); + this.sliderView = mainComponents.sliderView; + this.sliderList = mainComponents.sliderList; + this.sliderBtnNext = mainComponents.sliderBtnNext; + this.sliderBtnPrev = mainComponents.sliderBtnPrev; + this.modalWindow = new BaseComponent('div', ['popup', 'open']).getElement(); + this.modalWindow.addEventListener('click', this.onBackdropClick.bind(this)); + + this.createMarkup(); + } + + private initMainComponents(): IMainComponents { + const sliderView = new BaseComponent('div', ['swiper', 'swiper-view']).getElement(); + const sliderBtnNext = new BaseComponent('div', ['swiper-button-next']).getElement(); + const sliderBtnPrev = new BaseComponent('div', ['swiper-button-prev']).getElement(); + const sliderList = new BaseComponent('div', ['swiper', 'swiper-list']).getElement(); + + return { + sliderView, + sliderBtnNext, + sliderBtnPrev, + sliderList, + }; + } + + private createMarkup(): void { + const swiperViewWrapper = new BaseComponent('div', ['swiper-wrapper']).getElement(); + this.setOpenListener(swiperViewWrapper); + + const swiperListWrapper = new BaseComponent('div', ['swiper-wrapper']).getElement(); + + for (let i = 0; i < this.images.length; i++) { + const imageViewContainer = new BaseComponent('div', ['swiper-slide']).getElement(); + const imageView = new BaseComponent('img').getElement(); + imageView.src = this.images[i].url; + + const imageListContainer = new BaseComponent('div', ['swiper-slide']).getElement(); + const imageList = new BaseComponent('img').getElement(); + imageList.src = this.images[i].url; + + imageViewContainer.append(imageView); + imageListContainer.append(imageList); + + swiperViewWrapper.append(imageViewContainer); + swiperListWrapper.append(imageListContainer); + } + + this.sliderView.append(swiperViewWrapper, this.sliderBtnNext, this.sliderBtnPrev); + this.sliderList.append(swiperListWrapper); + + this.node.append(this.sliderView, this.sliderList); + + this.initSwiper(); + } + + private initSwiper(): void { + const swiperList = new Swiper(this.sliderList, { + loop: true, + spaceBetween: 10, + slidesPerView: 4, + freeMode: true, + watchSlidesProgress: true, + }); + + new Swiper(this.sliderView, { + loop: true, + spaceBetween: 24, + modules: [Navigation, Thumbs], + navigation: { + nextEl: this.sliderBtnNext, + prevEl: this.sliderBtnPrev, + }, + thumbs: { + swiper: swiperList, + }, + }); + } + + private setOpenListener(element: HTMLElement): void { + element.addEventListener('click', (event) => { + event.preventDefault(); + + if (event.target instanceof HTMLElement) { + const firstSlide: HTMLElement | null = event.target.closest('.swiper-slide-active'); + const imageIndex = Number(firstSlide?.getAttribute('data-swiper-slide-index') || 0); + + this.openModal(imageIndex); + } + }); + } + + private openModal(index: number): void { + const modalContainer = new BaseComponent('div', ['product__slider_modal']).getElement(); + const modalView = this.sliderView.cloneNode(true); + + modalView.innerHTML = ''; + + const modalViewWrapper = new BaseComponent('div', ['swiper-wrapper']).getElement(); + const modalBtnNext = this.sliderBtnNext.cloneNode(true); + const modalBtnPrev = this.sliderBtnPrev.cloneNode(true); + + for (let i = 0; i < this.images.length; i++) { + const imageViewContainer = new BaseComponent('div', ['swiper-slide']).getElement(); + const imageView = new BaseComponent('img').getElement(); + imageView.src = this.images[i].url; + + imageViewContainer.append(imageView); + + modalViewWrapper.append(imageViewContainer); + } + + modalView.append(modalViewWrapper, modalBtnNext, modalBtnPrev); + + modalContainer.append(modalView); + this.modalWindow.append(modalContainer); + + document.body.append(this.modalWindow); + + new Swiper(modalView, { + loop: true, + spaceBetween: 24, + modules: [Navigation], + navigation: { + nextEl: modalBtnNext, + prevEl: modalBtnPrev, + }, + initialSlide: index, + }); + } + + onBackdropClick(event: MouseEvent): void { + event.preventDefault(); + + if (event.target instanceof HTMLElement) { + if (event.target.classList.contains('popup')) this.removeModalWindow(); + } + } + + private removeModalWindow(): void { + this.modalWindow.innerHTML = ''; + this.modalWindow.remove(); + } +} diff --git a/src/components/sup/sup.scss b/src/components/sup/sup.scss new file mode 100644 index 0000000..4d7f9b5 --- /dev/null +++ b/src/components/sup/sup.scss @@ -0,0 +1,10 @@ +.sup { + margin: 0 3px; + padding: 2px 6px 3px; + font-size: 10px; + font-weight: 700; + text-align: center; + white-space: nowrap; + border-radius: 8px; + background: rgba(#ff8a00, 0.5); +} diff --git a/src/components/sup/sup.test.ts b/src/components/sup/sup.test.ts new file mode 100644 index 0000000..3986601 --- /dev/null +++ b/src/components/sup/sup.test.ts @@ -0,0 +1,15 @@ +import Sup from './sup'; + +describe('Sup', () => { + const sup: HTMLElement = new Sup('Sub text', ['sup-test-class']).getElement(); + + it('should render correct html-element', () => { + expect(sup.outerHTML).toBe('Sub text'); + }); + it('should render correct textContent', () => { + expect(sup.textContent).toBe('Sub text'); + }); + it('should render correct classList', () => { + expect(sup.classList.contains('sup-test-class')).toBe(true); + }); +}); diff --git a/src/components/sup/sup.ts b/src/components/sup/sup.ts new file mode 100644 index 0000000..e8a40d5 --- /dev/null +++ b/src/components/sup/sup.ts @@ -0,0 +1,8 @@ +import BaseComponent from '../base-component'; +import './sup.scss'; + +export default class Sup extends BaseComponent<'sup'> { + constructor(text: string, classes: string[] = []) { + super('sup', ['sup', ...classes], text); + } +} diff --git a/src/constants/aboutUsMembers.ts b/src/constants/aboutUsMembers.ts new file mode 100644 index 0000000..ad84641 --- /dev/null +++ b/src/constants/aboutUsMembers.ts @@ -0,0 +1,36 @@ +import { IAboutUsMember } from '../types/interfaces'; + +const aboutUsMembers: IAboutUsMember[] = [ + { + name: 'Andrew Suponev', + role: 'Team Lead, Front-End Developer', + imgClass: 'andrew', + about: `Since childhood I loved to stay up late and create websites using basic HTML and CSS. But, unfortunately, after graduation, my life path and IT missed each other. Now I'm 29 years old, I dream be a web developer and contribute to society by doing what I love.`, + contributions: [ + 'Configured project setup', + 'Implemented interaction with commercetools', + 'Create Signup Page', + 'Created Catalog page', + ], + link: 'https://github.com/elsuppo', + }, + { + name: 'Yauheni Baltsevich', + role: 'Front-End Developer', + imgClass: 'yauheni', + about: + 'My main goal is to become a Software Engeener. Currently, I live for permanent residence in Poland, it was here that I firmly decided that I would become a Software Engeneer, since this is a profession in which I definitely see myself.', + contributions: ['Сonfigured Jest', 'Configured TypeScript', 'Created Signin Page', 'Created Detailed Product page'], + link: 'https://github.com/eugenebalts', + }, + { + name: 'Maksim Lisianskii', + role: 'Front-End Developer', + imgClass: 'maksim', + about: `I'm middle Front-end Developer living in Saint-Petersburg. I'm currently learning TypeScript and React and I enjoy making beautiful web sites on HTML,CSS and JavaScript.`, + contributions: ['Configured Bundler', 'Implemented Routing', 'Created Account Page', 'Created Adresses Page'], + link: 'https://github.com/MaxLisyanskiy', + }, +]; + +export default aboutUsMembers; diff --git a/src/constants/aboutUsMethods.ts b/src/constants/aboutUsMethods.ts new file mode 100644 index 0000000..a76f75a --- /dev/null +++ b/src/constants/aboutUsMethods.ts @@ -0,0 +1,29 @@ +interface IAboutUsMethods { + title: string; + description: string; +} + +const aboutUsMethods: IAboutUsMethods[] = [ + { + title: 'Correct team formation and distribution of roles', + description: + 'This is the initial stage of project team development, where all involved participants get to know each other. The leader of the project establishes favorable relationships and interactions within the work group. The team studies the main goals and objectives, begins to develop common norms and agree on values, as well as the distribution of roles in the team.', + }, + { + title: 'Apply project management methodologies', + description: + 'Methodologies help to record the completion time of different types of tasks and correct weak points in time. We used Kanban and Scrum methodologies.', + }, + { + title: 'Set up team communication', + description: + 'Decide on a fixed daily time, "sunday retrospectives" - meetings where they discuss the past week and decide what processes can be improved, chat and a Discord channel - necessary things that we have implemented for convenient communication in the team!', + }, + { + title: 'Provide team members with regular feedback and task reviews', + description: + 'Feedback from each team member helps our team understand how we are doing the job - what we are already doing well and what skills need to be improved. Also, a code-review before merging is a way to look at the code from a different perspective and identify errors that might have been missed, suggest or recommend good practices, and it also improves the reviewer’s ability to see other people’s code.', + }, +]; + +export default aboutUsMethods; diff --git a/src/constants/addressInputs.ts b/src/constants/addressInputs.ts new file mode 100644 index 0000000..9485af6 --- /dev/null +++ b/src/constants/addressInputs.ts @@ -0,0 +1,42 @@ +export const AddressInputs = { + main: [ + { + type: 'text', + name: 'streetName', + label: 'Street', + placeholder: 'Street', + }, + { + type: 'text', + name: 'city', + label: 'City', + placeholder: 'City', + }, + { + type: 'text', + name: 'postalCode', + label: 'Postcode', + placeholder: 'Postcode', + }, + { + type: 'text', + name: 'country', + label: 'Country', + placeholder: 'Country', + }, + ], + checkboxes: [ + { + type: 'checkbox', + name: 'checkboxDefaultBilling', + label: 'Set Billing address as default', + placeholder: '', + }, + { + type: 'checkbox', + name: 'checkboxDefaultShipping', + label: 'Set Shipping address as default', + placeholder: '', + }, + ], +}; diff --git a/src/constants/categories.ts b/src/constants/categories.ts new file mode 100644 index 0000000..9f2c88c --- /dev/null +++ b/src/constants/categories.ts @@ -0,0 +1,26 @@ +import { ICategory } from '../types/types'; + +const categories: ICategory[] = [ + { + slug: 'europe', + label: 'Europe', + url: '/shop/europe', + }, + { + slug: 'asia', + label: 'Asia', + url: '/shop/asia', + }, + { + slug: 'america', + label: 'America', + url: '/shop/america', + }, + { + slug: 'africa', + label: 'Africa', + url: '/shop/africa', + }, +]; + +export default categories; diff --git a/src/constants/daysFilterOptions.ts b/src/constants/daysFilterOptions.ts new file mode 100644 index 0000000..e4b8624 --- /dev/null +++ b/src/constants/daysFilterOptions.ts @@ -0,0 +1,28 @@ +const daysFilterOptions = [ + { + label: 'Days', + value: '', + }, + { + label: '0 - 5 days', + value: '"0","1","2","3","4","5"', + }, + { + label: '6 - 10 days', + value: '"6","7","8","9","10"', + }, + { + label: '11 - 15 days', + value: '"11","12","13","14","15"', + }, + { + label: '16 - 20 days', + value: '"16","17","18","19","20"', + }, + { + label: 'over 20 days', + value: '"21","22","23","24","25"', + }, +]; + +export default daysFilterOptions; diff --git a/src/constants/detailsEditInputs.ts b/src/constants/detailsEditInputs.ts new file mode 100644 index 0000000..d5d2a0d --- /dev/null +++ b/src/constants/detailsEditInputs.ts @@ -0,0 +1,43 @@ +export const detailsEditInputs = { + main: [ + { + type: 'text', + name: 'firstName', + label: 'First Name', + placeholder: 'First Name', + }, + { + type: 'text', + name: 'lastName', + label: 'Last Name', + placeholder: 'Last Name', + }, + { + type: 'date', + name: 'dateOfBirth', + label: 'Date of birth', + placeholder: 'Date of birth', + }, + { + type: 'email', + name: 'email', + label: 'Email', + placeholder: 'Email', + }, + ], + passwords: [ + { + type: 'password', + name: 'currentPassword', + label: 'Current Password', + placeholder: 'Current Password', + }, + + { + type: 'password', + name: 'newPassword', + label: 'New password', + placeholder: 'New password', + }, + ], +}; diff --git a/src/constants/formValidationRules.ts b/src/constants/formValidationRules.ts new file mode 100644 index 0000000..8464d26 --- /dev/null +++ b/src/constants/formValidationRules.ts @@ -0,0 +1,74 @@ +interface IValidationRule { + rule: RegExp; + errorText: string; + secondErrorText?: string; +} + +interface IValidationRules { + password: IValidationRule; + newPassword: IValidationRule; + firstName: IValidationRule; + lastName: IValidationRule; + email: IValidationRule; + birthDate: IValidationRule; + streetShipping: IValidationRule; + cityShipping: IValidationRule; + postcodeShipping: IValidationRule; + streetBilling: IValidationRule; + cityBilling: IValidationRule; + postcodeBilling: IValidationRule; +} + +const formValidationRules: IValidationRules = { + password: { + rule: /^(?=.*\p{Lu})(?=.*\p{Ll})(?=.*\d).{8,}$/u, + errorText: 'Requires minimum 8 characters, 1 uppercase, 1 lowercase and 1 number', + }, + newPassword: { + rule: /^(?=.*\p{Lu})(?=.*\p{Ll})(?=.*\d).{8,}$/u, + errorText: 'Requires minimum 8 characters, 1 uppercase, 1 lowercase and 1 number', + secondErrorText: 'The new password must be different from the current password', + }, + firstName: { + rule: /^[^\d!@#$%^&*()_+[\]{};':"\\|,.<>/?]+$/, + errorText: 'Requires at least one letter, no special characters or numbers', + }, + lastName: { + rule: /^[^\d!@#$%^&*()_+[\]{};':"\\|,.<>/?]+$/, + errorText: 'Requires at least one letter, no special characters or numbers', + }, + email: { + rule: /^\S+@\S+\.\S+$/, + errorText: 'Requires a valid email address (e.g., example@email.com)', + }, + birthDate: { + rule: /^\d{4}-\d{2}-\d{2}$/, + errorText: 'Please enter your date of birth in the format "dd.mm.yyyy"', + }, + streetShipping: { + rule: /^.+$/, + errorText: 'Requires at least one letter', + }, + cityShipping: { + rule: /^[^\d!@#$%^&*()_+[\]{};':"\\|,.<>/?]+$/, + errorText: 'Requires at least one letter, no special characters or numbers', + }, + postcodeShipping: { + rule: /^\d{5}$/, + errorText: 'Requires exactly 5 digits, follow the format for the country (e.g., 12345 for the U.S)', + }, + streetBilling: { + rule: /^.+$/, + errorText: 'Requires at least one letter', + }, + cityBilling: { + rule: /^[^\d!@#$%^&*()_+[\]{};':"\\|,.<>/?]+$/, + errorText: 'Requires at least one letter, no special characters or numbers', + }, + postcodeBilling: { + rule: /^\d{5}$/, + errorText: 'Requires exactly 5 digits, follow the format for the country (e.g., 12345 for the U.S)', + }, +}; + +export default formValidationRules; diff --git a/src/constants/priceFilterOptions.ts b/src/constants/priceFilterOptions.ts new file mode 100644 index 0000000..46be987 --- /dev/null +++ b/src/constants/priceFilterOptions.ts @@ -0,0 +1,28 @@ +const priceFilterOptions = [ + { + label: 'Price', + value: '', + }, + { + label: 'under $1,500', + value: 'range (* to 150000)', + }, + { + label: '$1,500 - $2,000', + value: 'range (150000 to 200000)', + }, + { + label: '$2,000 - $2,500', + value: 'range (200000 to 250000)', + }, + { + label: '$2,500 - $3,000', + value: 'range (250000 to 300000)', + }, + { + label: 'over $3,000', + value: 'range (300000 to *)', + }, +]; + +export default priceFilterOptions; diff --git a/src/constants/productsOptions.ts b/src/constants/productsOptions.ts new file mode 100644 index 0000000..04b3514 --- /dev/null +++ b/src/constants/productsOptions.ts @@ -0,0 +1,2 @@ +export const BASE_PRODUCT_OFFSET: number = 0; +export const BASE_PRODUCT_LIMIT: number = 12; diff --git a/src/constants/promoCodes.ts b/src/constants/promoCodes.ts new file mode 100644 index 0000000..bfdb943 --- /dev/null +++ b/src/constants/promoCodes.ts @@ -0,0 +1,30 @@ +import { IPromoCodes } from '../types/interfaces'; + +const promoCodes: IPromoCodes[] = [ + { + title: 'Family Getaway Deal: Kids Stay Free', + descr: 'Have an unforgettable family getaway where kids stay for free with promo code FAMILYFUN.', + code: 'FAMILYFUN', + expirationDate: '09/25/2023, 11:59 PM', + }, + { + title: 'Last-Minute Wanderlust: 10% Off Any Booking', + descr: 'Embrace your last-minute wanderlust and enjoy 10% off any booking with promo code LASTCHANCE.', + code: 'LASTCHANCE', + expirationDate: '10/01/2023, 11:59 PM', + }, + { + title: 'Cruise in Style: $100 Off Ocean View Cabins', + descr: 'Cruise in style! Get $100 off ocean view cabins with promo code CRUISE100.', + code: 'CRUISE100', + expirationDate: '10/08/2023, 11:59 PM', + }, + { + title: 'Group Adventure: 25% Off for Parties of 4 or More', + descr: 'Plan a group adventure and enjoy a 25% discount for parties of 4 or more with promo code GROUP24.', + code: 'GROUP24', + expirationDate: '12/25/2023, 11:59 PM', + }, +]; + +export default promoCodes; diff --git a/src/constants/signupInputs.ts b/src/constants/signupInputs.ts new file mode 100644 index 0000000..53559b1 --- /dev/null +++ b/src/constants/signupInputs.ts @@ -0,0 +1,96 @@ +export const signupInputs = { + infoInputs: [ + { + type: 'text', + name: 'firstName', + label: 'First Name', + placeholder: 'First Name', + }, + { + type: 'text', + name: 'lastName', + label: 'Last Name', + placeholder: 'Last Name', + }, + { + type: 'email', + name: 'email', + label: 'Email', + placeholder: 'Email', + }, + { + type: 'password', + name: 'password', + label: 'Password', + placeholder: 'Password', + }, + { + type: 'date', + name: 'birthDate', + label: 'Date of birth', + placeholder: 'Date of birth', + }, + { + type: 'text', + name: 'country', + label: 'Country', + placeholder: 'Country', + }, + ], + addressInputs: [ + { + type: 'text', + name: 'streetShipping', + label: 'Shipping address (street)', + placeholder: 'Street', + }, + { + type: 'text', + name: 'cityShipping', + label: 'Shipping address (city)', + placeholder: 'City', + }, + { + type: 'text', + name: 'postcodeShipping', + label: 'Shipping address (postcode)', + placeholder: 'Postcode', + }, + { + type: 'checkbox', + name: 'checkboxAddress', + label: 'The shipping address matches the billing address', + placeholder: '', + }, + { + type: 'text', + name: 'streetBilling', + label: 'Billing address (street)', + placeholder: 'Street', + }, + { + type: 'text', + name: 'cityBilling', + label: 'Billing address (city)', + placeholder: 'City', + }, + { + type: 'text', + name: 'postcodeBilling', + label: 'Billing address (postcode)', + placeholder: 'Postcode', + }, + { + type: 'checkbox', + name: 'checkboxDefaultShipping', + label: 'Set Shipping address as default', + placeholder: '', + }, + { + type: 'checkbox', + name: 'checkboxDefaultBilling', + label: 'Set Billing address as default', + placeholder: '', + }, + ], +}; diff --git a/src/constants/sortShopOptions.ts b/src/constants/sortShopOptions.ts new file mode 100644 index 0000000..d14c3d6 --- /dev/null +++ b/src/constants/sortShopOptions.ts @@ -0,0 +1,24 @@ +const sortShopOptions = [ + { + label: 'Default', + value: '', + }, + { + label: 'By price (ascending)', + value: 'price asc', + }, + { + label: 'By price (descending)', + value: 'price desc', + }, + { + label: 'By title (A - Z)', + value: 'name.en asc', + }, + { + label: 'By title (Z - A)', + value: 'name.en desc', + }, +]; + +export default sortShopOptions; diff --git a/src/constants/subcategories.ts b/src/constants/subcategories.ts new file mode 100644 index 0000000..81c2171 --- /dev/null +++ b/src/constants/subcategories.ts @@ -0,0 +1,134 @@ +import { ICategory } from '../types/types'; + +const subcategories: { [key: string]: ICategory[] } = { + europe: [ + { + slug: '', + label: 'All Tours', + url: '/shop', + }, + { + slug: 'europe', + label: 'All in Europe', + url: '/shop/europe', + }, + { + slug: 'hiking-trekking-eu', + label: 'Hiking & Trekking', + url: '/shop/europe/hiking-trekking-eu', + }, + { + slug: 'explorer-eu', + label: 'Explorer', + url: '/shop/europe/explorer-eu', + }, + { + slug: 'safari-eu', + label: 'Safari', + url: '/shop/europe/safari-eu', + }, + { + slug: 'sailing-eu', + label: 'Sailing', + url: '/shop/europe/sailing-eu', + }, + ], + asia: [ + { + slug: '', + label: 'All Tours', + url: '/shop', + }, + { + slug: 'asia', + label: 'All in Asia', + url: '/shop/asia', + }, + { + slug: 'hiking-trekking-as', + label: 'Hiking & Trekking', + url: '/shop/asia/hiking-trekking-as', + }, + { + slug: 'explorer-as', + label: 'Explorer', + url: '/shop/asia/explorer-as', + }, + { + slug: 'safari-as', + label: 'Safari', + url: '/shop/asia/safari-as', + }, + { + slug: 'sailing-as', + label: 'Sailing', + url: '/shop/asia/sailing-as', + }, + ], + america: [ + { + slug: '', + label: 'All Tours', + url: '/shop', + }, + { + slug: 'america', + label: 'All in America', + url: '/shop/america', + }, + { + slug: 'hiking-trekking-am', + label: 'Hiking & Trekking', + url: '/shop/america/hiking-trekking-am', + }, + { + slug: 'explorer-am', + label: 'Explorer', + url: '/shop/america/explorer-am', + }, + { + slug: 'safari-am', + label: 'Safari', + url: '/shop/america/safari-am', + }, + { + slug: 'sailing-am', + label: 'Sailing', + url: '/shop/america/sailing-am', + }, + ], + africa: [ + { + slug: '', + label: 'All Tours', + url: '/shop', + }, + { + slug: 'africa', + label: 'All in Africa', + url: '/shop/africa', + }, + { + slug: 'hiking-trekking-af', + label: 'Hiking & Trekking', + url: '/shop/africa/hiking-trekking-af', + }, + { + slug: 'explorer-af', + label: 'Explorer', + url: '/shop/africa/explorer-af', + }, + { + slug: 'safari-af', + label: 'Safari', + url: '/shop/africa/safari-af', + }, + { + slug: 'sailing-af', + label: 'Sailing', + url: '/shop/africa/sailing-af', + }, + ], +}; + +export default subcategories; diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..bb197ca --- /dev/null +++ b/src/index.html @@ -0,0 +1,9 @@ + + + + + + <%= htmlWebpackPlugin.options.title %> + + + diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..fecdbfb --- /dev/null +++ b/src/index.ts @@ -0,0 +1,43 @@ +import { createRouter } from './router'; +import Header from './components/header/header'; +import Footer from './components/footer/footer'; +import getUser from './services/getUser'; +import userStore from './store/user-store'; +import Notification from './components/notification/notification'; +import getCart from './services/basket/getCart'; +import cartStore from './store/cart-store'; +import './styles/index.scss'; + +class App { + public async start() { + const header = new Header().getElement(); + const main = document.createElement('main'); + const footer = new Footer().getElement(); + + document.body.append(header, main, footer); + + try { + const token = localStorage.getItem('token'); + if (token) { + const customer = await getUser(token); + userStore.dispatch({ type: 'SET_IS_AUTH', isAuth: true }); + userStore.dispatch({ type: 'ADD_CUSTOMER', customer }); + } + const cart = await getCart(); + cartStore.dispatch({ type: 'UPDATE_CART', cart }); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + localStorage.removeItem('token'); + } + + createRouter(main); + } +} + +const app: App = new App(); + +app.start(); diff --git a/src/pages/about-us-page/about-us-page.scss b/src/pages/about-us-page/about-us-page.scss new file mode 100644 index 0000000..a9bb5c5 --- /dev/null +++ b/src/pages/about-us-page/about-us-page.scss @@ -0,0 +1,14 @@ +.about-us-page { + &__container { + @include container; + } + + &__title { + @include font-h1; + max-width: 1025px; + + & span { + color: $color-logo; + } + } +} diff --git a/src/pages/about-us-page/about-us-page.ts b/src/pages/about-us-page/about-us-page.ts new file mode 100644 index 0000000..5876f94 --- /dev/null +++ b/src/pages/about-us-page/about-us-page.ts @@ -0,0 +1,46 @@ +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import { IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import AboutUsList from '../../components/about-us/about-us-list'; +import AboutUsCollaboration from '../../components/about-us/about-us-collaboration'; +import AboutUsRSSchool from '../../components/about-us/about-us-rsschool-link'; +import './about-us-page.scss'; + +const breadcrumbsLinks: IBreadcrumbLink[] = [ + { + pageName: 'Home', + pageHref: AppRoutesPath.MAIN, + }, +]; + +export default class AboutUsPage extends BaseComponent<'div'> { + private breadcrumbs: HTMLElement; + private aboutUsContainer: HTMLElement; + + constructor() { + super('div', ['about-us-page']); + + this.breadcrumbs = new Breadcrumbs(breadcrumbsLinks, 'About Us').getElement(); + + this.aboutUsContainer = new BaseComponent('div', ['about-us-page__container']).getElement(); + this.renderAboutUsSection(); + + this.node.append(this.breadcrumbs, this.aboutUsContainer); + } + + private renderAboutUsSection(): void { + const sectionTitle = new BaseComponent( + 'h1', + ['about-us-page__title'], + 'Discover Our Team: Meet the Faces Behind' + ).getElement(); + sectionTitle.insertAdjacentHTML('beforeend', ' this is this.'); + + const aboutUsList = new AboutUsList().getElement(); + const aboutUsCollaboration = new AboutUsCollaboration().getElement(); + const aboutUsRSSchool = new AboutUsRSSchool().getElement(); + + this.aboutUsContainer.append(sectionTitle, aboutUsList, aboutUsCollaboration, aboutUsRSSchool); + } +} diff --git a/src/pages/account-page/account-page.scss b/src/pages/account-page/account-page.scss new file mode 100644 index 0000000..da86be3 --- /dev/null +++ b/src/pages/account-page/account-page.scss @@ -0,0 +1,29 @@ +.account-page { + padding-bottom: 50px; + + &__container { + @include container; + display: flex; + + @include tablet { + flex-direction: column; + } + } + + &__details { + width: 50%; + margin-right: 24px; + @include tablet { + width: 100%; + margin-right: 0; + } + } + + &__addresses { + width: 50%; + @include tablet { + margin-top: 30px; + width: 100%; + } + } +} diff --git a/src/pages/account-page/account-page.ts b/src/pages/account-page/account-page.ts new file mode 100644 index 0000000..c384292 --- /dev/null +++ b/src/pages/account-page/account-page.ts @@ -0,0 +1,45 @@ +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import AccountDetails from '../../components/account/account-details/account-details'; +import AccountAddresses from '../../components/account/account-addresses/account-addresses'; +import { IBreadcrumbLink } from '../../types/interfaces'; +import { AccountInfoMode } from '../../types/enums'; +import { AppRoutesPath } from '../../router/types'; +import './account-page.scss'; + +const breadcrumbsLinks: IBreadcrumbLink[] = [ + { + pageName: 'Home', + pageHref: AppRoutesPath.MAIN, + }, +]; + +export default class AccountPage extends BaseComponent<'div'> { + private breadcrumbs: HTMLElement; + private container: HTMLElement; + private detailsSection: HTMLElement; + private addressesSection: HTMLElement; + private userProfileMode: AccountInfoMode = AccountInfoMode.SHOW; + + constructor() { + super('div', ['account-page']); + + this.breadcrumbs = new Breadcrumbs(breadcrumbsLinks, 'Account', true).getElement(); + this.container = new BaseComponent('div', ['account-page__container']).getElement(); + this.detailsSection = new BaseComponent('section', ['account-page__details']).getElement(); + this.addressesSection = new BaseComponent('section', ['account-page__addresses']).getElement(); + + this.detailsSection.append(new AccountDetails(this.userProfileMode, this.changeUserProfileMode).getElement()); + this.addressesSection.append(new AccountAddresses().getElement()); + + this.container.append(this.detailsSection, this.addressesSection); + + this.node.append(this.breadcrumbs, this.container); + } + + private changeUserProfileMode = (): void => { + this.detailsSection.innerHTML = ''; + this.userProfileMode = this.userProfileMode === AccountInfoMode.SHOW ? AccountInfoMode.EDIT : AccountInfoMode.SHOW; + this.detailsSection.append(new AccountDetails(this.userProfileMode, this.changeUserProfileMode).getElement()); + }; +} diff --git a/src/pages/addresses-page/addresses-page.scss b/src/pages/addresses-page/addresses-page.scss new file mode 100644 index 0000000..90b1478 --- /dev/null +++ b/src/pages/addresses-page/addresses-page.scss @@ -0,0 +1,24 @@ +.addresses-page { + padding-bottom: 50px; + + &__container { + @include container; + } + + &__title-wrapp { + display: flex; + align-items: center; + justify-content: space-between; + } + + &__title { + @include font-h3; + } + + &__add-btn { + margin-top: 32px; + &.hidden { + display: none; + } + } +} diff --git a/src/pages/addresses-page/addresses-page.ts b/src/pages/addresses-page/addresses-page.ts new file mode 100644 index 0000000..ef26965 --- /dev/null +++ b/src/pages/addresses-page/addresses-page.ts @@ -0,0 +1,138 @@ +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import Link from '../../components/link/link'; +import Button from '../../components/button/button'; +import Address from '../../components/address/address'; +import Notification from '../../components/notification/notification'; +import userStore from '../../store/user-store'; +import removeAddress from '../../services/addresses/removeAddress'; +import changeVisibleAddressesBtns from '../../utils/change-visible-addresses-btns'; +import { IAddressData, IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import { AddressesMode } from '../../types/enums'; +import './addresses-page.scss'; + +const breadcrumbsLinks: IBreadcrumbLink[] = [ + { + pageName: 'Home', + pageHref: AppRoutesPath.MAIN, + }, + { + pageName: 'Account', + pageHref: AppRoutesPath.ACCOUNT, + }, +]; + +export default class AddressesPage extends BaseComponent<'div'> { + private breadcrumbs: HTMLElement; + private container: HTMLElement; + private addressesSection: HTMLElement; + private addressesListWrapp: HTMLElement; + private addresses: HTMLDivElement[] = []; + private addNewAddressBtn: HTMLButtonElement | null = null; + + constructor() { + super('div', ['addresses-page']); + + this.breadcrumbs = new Breadcrumbs(breadcrumbsLinks, 'Addresses').getElement(); + this.container = new BaseComponent('div', ['addresses-page__container']).getElement(); + this.addressesSection = new BaseComponent('section', ['addresses-page__section']).getElement(); + this.addressesListWrapp = new BaseComponent('div', ['addresses-page__list']).getElement(); + this.addressesSection.append(this.addressesListWrapp); + + this.container.append(this.addressesSection); + + this.renderAddressesSection(); + this.renderAddressesList(); + + this.node.append(this.breadcrumbs, this.container); + } + + private renderAddressesSection = (): void => { + const titleWrapp = new BaseComponent('div', ['addresses-page__title-wrapp']).getElement(); + const sectionTitle = new BaseComponent('h1', ['addresses-page__title'], 'Addresses').getElement(); + const returnToAccountLink = new Link('Return To Account', ['link--return'], AppRoutesPath.ACCOUNT).getElement(); + this.addNewAddressBtn = new Button( + 'button', + '+ Add New Address', + ['button--add-address', 'addresses-page__add-btn'], + false, + this.renderNewAddressForm + ).getElement(); + + titleWrapp.append(sectionTitle, returnToAccountLink); + + this.addressesSection.prepend(titleWrapp, this.addNewAddressBtn); + }; + + private renderAddressesList = (): void => { + const { customer } = userStore.getState(); + + this.addressesListWrapp.innerHTML = ''; + + if (customer && customer?.addresses.length > 0) { + customer?.addresses.forEach((item) => { + const obj: IAddressData = { + address: item, + billingAddressIds: customer.billingAddressIds, + shippingAddressIds: customer.shippingAddressIds, + defaultBillingAddressId: customer.defaultBillingAddressId, + defaultShippingAddressId: customer.defaultShippingAddressId, + }; + + const address = new Address( + AddressesMode.SHOW, + obj, + (type: AddressesMode) => this.onChangeForm(type), + (id: string) => this.onDeleteAddress(id) + ).getElement(); + this.addressesListWrapp.append(address); + this.addresses.push(address); + }); + } + }; + + private renderNewAddressForm = (): void => { + const newAddress = new Address(AddressesMode.NEW, null, this.onSubmitNewForm, (id: string) => + this.onCancelNewForm(id) + ).getElement(); + this.addressesListWrapp.prepend(newAddress); + this.addNewAddressBtn?.classList.add('hidden'); + + changeVisibleAddressesBtns(this.addresses, true); + }; + + private onChangeForm = (type: AddressesMode): void => { + this.addNewAddressBtn?.classList.toggle('hidden', type === AddressesMode.EDIT); + changeVisibleAddressesBtns(this.addresses, type === AddressesMode.EDIT); + if (type === AddressesMode.SHOW) this.renderAddressesList(); + }; + + private onSubmitNewForm = (): void => { + this.onCancelNewForm('new'); + this.renderAddressesList(); + }; + + private onCancelNewForm = (id: string): void => { + if (id === 'new') { + this.addNewAddressBtn?.classList.remove('hidden'); + this.addressesListWrapp?.firstChild?.remove(); + changeVisibleAddressesBtns(this.addresses, false); + } + }; + + private onDeleteAddress = async (id: string): Promise => { + try { + await removeAddress(id); + + new Notification('success', 'The selected address was successfully deleted!').showNotification(); + this.renderAddressesList(); + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + } else { + console.error(error); + } + } + }; +} diff --git a/src/pages/basket-page/basket-page.scss b/src/pages/basket-page/basket-page.scss new file mode 100644 index 0000000..34c404f --- /dev/null +++ b/src/pages/basket-page/basket-page.scss @@ -0,0 +1,19 @@ +.basket-page { + &__section { + @include container; + } + + &__title { + @include font-h3; + margin-bottom: 24px; + } + + &__loading { + @include container; + @include font-h4; + margin: 48px 0; + display: flex; + align-items: center; + justify-content: center; + } +} diff --git a/src/pages/basket-page/basket-page.ts b/src/pages/basket-page/basket-page.ts new file mode 100644 index 0000000..4c3904a --- /dev/null +++ b/src/pages/basket-page/basket-page.ts @@ -0,0 +1,96 @@ +import { Cart } from '@commercetools/platform-sdk'; +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import { IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import BasketEmpty from '../../components/basket-empty/basket-empty'; +import Notification from '../../components/notification/notification'; +import BasketItems from '../../components/basket-items/basket-items'; +import BasketTotal from '../../components/basket-total/basket-total'; +import getCart from '../../services/basket/getCart'; +import cartStore from '../../store/cart-store'; +import './basket-page.scss'; + +const breadcrumbsLinks: IBreadcrumbLink[] = [ + { + pageName: 'Home', + pageHref: AppRoutesPath.MAIN, + }, +]; + +export default class BasketPage extends BaseComponent<'div'> { + private cart: Cart | undefined; + private basketMainSection: HTMLElement | undefined; + private basketTotalSection: HTMLElement | undefined; + + constructor() { + super('div', ['basket-page']); + + this.cart = undefined; + + this.renderBreadcrumbs(); + this.renderTitle(); + this.renderMainContent(); + this.addSubscribtion(); + } + + private renderBreadcrumbs(): void { + const breadcrumbs = new Breadcrumbs(breadcrumbsLinks, 'Basket').getElement(); + + this.node.append(breadcrumbs); + } + + private renderTitle(): void { + const basketTitleSection = new BaseComponent('section', ['basket-page__section']).getElement(); + const basketPageTitle = new BaseComponent('h3', ['basket-page__title'], 'Shopping Cart').getElement(); + + basketTitleSection.append(basketPageTitle); + + this.node.append(basketTitleSection); + } + + private async renderMainContent(): Promise { + const loadingElement = new BaseComponent('div', ['basket-page__loading'], 'Loading...').getElement(); + + try { + this.node.append(loadingElement); + + this.cart = await getCart(); + cartStore.dispatch({ type: 'UPDATE_CART', cart: this.cart }); + + if (this.cart && this.cart.lineItems.length > 0) { + this.basketMainSection = new BasketItems(this.cart.lineItems).getElement(); + this.basketTotalSection = new BasketTotal(this.cart).getElement(); + this.node.append(this.basketMainSection, this.basketTotalSection); + } else { + this.basketMainSection = new BasketEmpty().getElement(); + this.node.append(this.basketMainSection); + } + } catch (error) { + if (error instanceof Error) { + new Notification('error', error.message).showNotification(); + if (error.message === 'invalid_token') { + localStorage.removeItem('tokenAnon'); + localStorage.removeItem('token'); + } + } else { + console.error(error); + } + + this.basketMainSection = new BasketEmpty().getElement(); + this.node.append(this.basketMainSection); + } finally { + loadingElement.remove(); + } + } + + private addSubscribtion(): void { + cartStore.subscribe((state) => { + if (state.cart?.lineItems.length === 0 && this.basketMainSection) { + this.basketMainSection.innerHTML = ''; + this.basketTotalSection?.remove(); + this.basketMainSection.append(new BasketEmpty().getElement()); + } + }); + } +} diff --git a/src/pages/catalog-page/catalog-page.scss b/src/pages/catalog-page/catalog-page.scss new file mode 100644 index 0000000..2f55253 --- /dev/null +++ b/src/pages/catalog-page/catalog-page.scss @@ -0,0 +1,27 @@ +.catalog-page { + &__loading { + @include container; + @include font-h4; + margin: 48px 0; + display: flex; + align-items: center; + justify-content: center; + } +} + +.shop-controls { + margin-top: 48px; + + &__container { + @include container; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 16px; + + @include mobile { + gap: 60px; + } + } +} diff --git a/src/pages/catalog-page/catalog-page.ts b/src/pages/catalog-page/catalog-page.ts new file mode 100644 index 0000000..b217d54 --- /dev/null +++ b/src/pages/catalog-page/catalog-page.ts @@ -0,0 +1,235 @@ +import { type ProductProjection } from '@commercetools/platform-sdk'; +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import { IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import { ICategory } from '../../types/types'; +import ProductList from '../../components/product-list/product-list'; +import CategoryList from '../../components/category-list/category-list'; +import getProducts from '../../services/getProducts'; +import subcategories from '../../constants/subcategories'; +import categories from '../../constants/categories'; +import ShopHero from '../../components/shop-hero/shop-hero'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import ShopFilters from '../../components/shop-flters/shop-filters'; +import shopStore from '../../store/shop-store'; +import ShopSort from '../../components/shop-sort/shop-sort'; +import ShopSearch from '../../components/shop-search/shop-search'; +import { BASE_PRODUCT_LIMIT, BASE_PRODUCT_OFFSET } from '../../constants/productsOptions'; +import ProductCard from '../../components/product-card/product-card'; +import './catalog-page.scss'; + +export default class CatalogPage extends BaseComponent<'div'> { + private products: ProductProjection[]; + private categorySlug: string; + private subcategorySlug: string; + private breadcrumbsLinks: IBreadcrumbLink[]; + private currentPage: string; + private heroTitleText: string; + private catalogSection: ProductList; + + private productsOffset: number = BASE_PRODUCT_OFFSET; + private productsTotal: number = BASE_PRODUCT_LIMIT; + private isLoading: boolean = false; + private shouldLoad: boolean = false; + + constructor() { + super('div', ['catalog-page']); + + this.products = []; + this.categorySlug = ''; + this.subcategorySlug = ''; + this.breadcrumbsLinks = [{ pageName: 'Home', pageHref: AppRoutesPath.MAIN }]; + this.currentPage = 'Shop'; + this.heroTitleText = 'Shop All'; + this.catalogSection = new ProductList(this.products); + + shopStore.unsubscribe(); + this.renderPage(); + this.addSubscribtion(); + } + + private renderPage(): void { + const isPage = this.parseUrl(); + + if (!isPage) { + changeUrlEvent(AppRoutesPath.NOT_FOUND); + } else { + this.renderBreadcrumbs(); + this.renderHeroSection(); + this.renderCategoryList(); + this.renderSearchPanel(); + this.renderControls(); + this.renderProductList(); + } + } + + private parseUrl(): boolean { + const url: string = window.location.pathname; + const parts: string[] = url.split('/').filter((part) => part !== ''); + + if (parts.length === 3) { + this.categorySlug = parts[parts.length - 2]; + this.subcategorySlug = parts[parts.length - 1]; + + const currentCategory: ICategory | undefined = categories.find((item) => item.slug === this.categorySlug); + const currentsubCategory: ICategory | undefined = subcategories[this.categorySlug]?.find( + (item) => item.slug === this.subcategorySlug + ); + + if (!currentCategory || !currentsubCategory) return false; + + this.breadcrumbsLinks = [ + { pageName: 'Home', pageHref: AppRoutesPath.MAIN }, + { pageName: 'Shop', pageHref: AppRoutesPath.SHOP }, + { pageName: currentCategory.label, pageHref: `/shop/${this.categorySlug}` }, + ]; + this.currentPage = currentsubCategory.label; + this.heroTitleText = this.currentPage; + + return true; + } + + if (parts.length === 2) { + this.categorySlug = parts[parts.length - 1]; + + const currentCategory: ICategory | undefined = categories.find((item) => item.slug === this.categorySlug); + + if (!currentCategory) return false; + + this.breadcrumbsLinks = [ + { pageName: 'Home', pageHref: AppRoutesPath.MAIN }, + { pageName: 'Shop', pageHref: AppRoutesPath.SHOP }, + ]; + this.currentPage = currentCategory.label; + this.heroTitleText = this.currentPage; + + return true; + } + + return true; + } + + private renderBreadcrumbs(): void { + const breadcrumbs: HTMLDivElement = new Breadcrumbs(this.breadcrumbsLinks, this.currentPage).getElement(); + this.node.append(breadcrumbs); + } + + private renderHeroSection(): void { + const heroSection: HTMLElement = new ShopHero(this.heroTitleText).getElement(); + this.node.append(heroSection); + } + + private renderControls(): void { + const shopControls: HTMLDivElement = new BaseComponent('div', ['shop-controls']).getElement(); + const container: HTMLDivElement = new BaseComponent('div', ['shop-controls__container']).getElement(); + const filtersElement: HTMLElement = new ShopFilters().getElement(); + const sortElement: HTMLElement = new ShopSort().getElement(); + + container.append(filtersElement, sortElement); + shopControls.append(container); + + this.node.append(shopControls); + } + + private renderCategoryList(): void { + let categoryList: ICategory[] = []; + let titleCategoryEl: string = 'Categories'; + + if (this.categorySlug) { + categoryList = subcategories[this.categorySlug]; + titleCategoryEl = 'Subcategories'; + } else { + categoryList = categories; + } + + const categoryListElement: HTMLDivElement = new CategoryList( + titleCategoryEl, + categoryList, + this.subcategorySlug ? this.subcategorySlug : this.categorySlug + ).getElement(); + + this.node.append(categoryListElement); + } + + private renderSearchPanel(): void { + const { searchValue } = shopStore.getState(); + + const searchPanel = new ShopSearch(searchValue).getElement(); + + this.node.append(searchPanel); + } + + private handleGettingProducts = async (isFirstRender: boolean): Promise => { + const { filterPrice, filterDays, sortValue, searchValue } = shopStore.getState(); + + const response = await getProducts( + this.categorySlug, + this.subcategorySlug, + filterPrice, + filterDays, + sortValue, + searchValue, + (this.productsOffset = isFirstRender ? BASE_PRODUCT_OFFSET : this.productsOffset + BASE_PRODUCT_LIMIT) + ); + + this.products = response?.products || []; + this.productsOffset = response?.offset || BASE_PRODUCT_OFFSET; + this.productsTotal = response?.total || BASE_PRODUCT_LIMIT; + + if (response?.total && response?.total > BASE_PRODUCT_LIMIT) { + this.shouldLoad = true; + } else { + this.shouldLoad = false; + } + }; + + private infiniteLoading = async (): Promise => { + const footer = document.querySelector('footer'); + + if (this.isLoading || !this.shouldLoad) return; + + if (window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - footer.clientHeight) { + if (this.productsOffset < this.productsTotal - 10) { + this.isLoading = true; + + const loadingElement = new BaseComponent('div', ['catalog-page__loading'], 'Loading...').getElement(); + this.node.append(loadingElement); + + await this.handleGettingProducts(false); + + const newProducts: HTMLElement[] = []; + this.products.forEach((item) => newProducts.push(new ProductCard(item).getElement())); + + loadingElement.remove(); + + this.catalogSection.addNewProducts(newProducts); + + this.isLoading = false; + } + } + }; + + private renderProductList = async (): Promise => { + this.catalogSection.getElement().remove(); + + const loadingElement = new BaseComponent('div', ['catalog-page__loading'], 'Loading...').getElement(); + this.node.append(loadingElement); + + await this.handleGettingProducts(true); + + this.catalogSection = new ProductList(this.products); + loadingElement.remove(); + + this.node.append(this.catalogSection.getElement()); + + window.addEventListener('scroll', this.infiniteLoading); + window.addEventListener('resize', this.infiniteLoading); + }; + + private addSubscribtion(): void { + shopStore.subscribe(() => { + this.renderProductList(); + }); + } +} diff --git a/src/pages/login-page/login-page.scss b/src/pages/login-page/login-page.scss new file mode 100644 index 0000000..4f7aada --- /dev/null +++ b/src/pages/login-page/login-page.scss @@ -0,0 +1,18 @@ +.login-page { + display: flex; + flex-direction: column; +} + +.login-section { + margin-bottom: 104px; + + @include mobile { + margin-bottom: 80px; + } + + &__container { + @include container; + display: flex; + justify-content: center; + } +} diff --git a/src/pages/login-page/login-page.ts b/src/pages/login-page/login-page.ts new file mode 100644 index 0000000..d540f69 --- /dev/null +++ b/src/pages/login-page/login-page.ts @@ -0,0 +1,48 @@ +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import LoginForm from '../../components/form/login-form'; +import Banner from '../../components/banner/banner'; +import { IBannerContent, IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import './login-page.scss'; + +const breadcrumbsLinks: IBreadcrumbLink[] = [ + { + pageName: 'Home', + pageHref: AppRoutesPath.MAIN, + }, +]; + +const bannerContent: IBannerContent = { + title: 'Discover the World: Book Unforgettable Journeys Today!', + text: 'Our expertly crafted itineraries take you beyond the ordinary, unveiling the hidden gems of captivating destinations across the globe.', +}; + +export default class LoginPage extends BaseComponent<'div'> { + private breadcrumbs: HTMLElement; + private loginSection: HTMLElement; + private bannerSection: HTMLElement; + + constructor() { + super('div', ['login-page']); + + this.breadcrumbs = new Breadcrumbs(breadcrumbsLinks, 'Log In').getElement(); + + this.loginSection = new BaseComponent('section', ['login-section']).getElement(); + this.renderSignupSection(); + + this.bannerSection = new Banner(bannerContent.title, bannerContent.text).getElement(); + + this.node.append(this.breadcrumbs, this.loginSection, this.bannerSection); + } + + private renderSignupSection(): void { + const container: HTMLElement = new BaseComponent('div', ['login-section__container']).getElement(); + + const signupForm: HTMLDivElement = new LoginForm().getElement(); + + container.append(signupForm); + + this.loginSection.append(container); + } +} diff --git a/src/pages/main-page/main-page.scss b/src/pages/main-page/main-page.scss new file mode 100644 index 0000000..000d9d2 --- /dev/null +++ b/src/pages/main-page/main-page.scss @@ -0,0 +1,7 @@ +.temporary-section { + display: flex; + align-items: center; + justify-content: center; + height: 100dvh; + @include font-h1; +} diff --git a/src/pages/main-page/main-page.ts b/src/pages/main-page/main-page.ts new file mode 100644 index 0000000..33a6ae0 --- /dev/null +++ b/src/pages/main-page/main-page.ts @@ -0,0 +1,24 @@ +import BaseComponent from '../../components/base-component'; +import Banner from '../../components/banner/banner'; +import { IBannerContent } from '../../types/interfaces'; +import PromoCodes from '../../components/promo-codes/promo-codes'; +import './main-page.scss'; + +const bannerContent: IBannerContent = { + title: 'Wanderlust Dreams: Unveil the World with Exclusive Tours', + text: 'Satisfy your wanderlust with our collection of exclusive tours tailored to quench your thirst for exploration.', +}; + +export default class MainPage extends BaseComponent<'div'> { + private bannerSection: HTMLElement; + private promoCodesSection: HTMLElement; + + constructor() { + super('div', ['main-page']); + + this.bannerSection = new Banner(bannerContent.title, bannerContent.text, ['banner--main-page']).getElement(); + this.promoCodesSection = new PromoCodes().getElement(); + + this.node.append(this.bannerSection, this.promoCodesSection); + } +} diff --git a/src/pages/not-found-page/not-found-page.scss b/src/pages/not-found-page/not-found-page.scss new file mode 100644 index 0000000..b5648f4 --- /dev/null +++ b/src/pages/not-found-page/not-found-page.scss @@ -0,0 +1,34 @@ +.not-found-page { + display: flex; + flex-direction: column; +} + +.not-found-section { + margin: 275px 0; + + @include mobile { + margin: 80px 0; + } + + &__container { + @include container; + } + + &__wrapper { + display: flex; + flex-direction: column; + align-items: center; + } + + &__title { + @include font-h1; + text-align: center; + margin-bottom: 24px; + } + + &__descr { + font: $font-subtitle; + text-align: center; + margin-bottom: 32px; + } +} diff --git a/src/pages/not-found-page/not-found-page.ts b/src/pages/not-found-page/not-found-page.ts new file mode 100644 index 0000000..763d181 --- /dev/null +++ b/src/pages/not-found-page/not-found-page.ts @@ -0,0 +1,55 @@ +import BaseComponent from '../../components/base-component'; +import Banner from '../../components/banner/banner'; +import Button from '../../components/button/button'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import { AppRoutesPath } from '../../router/types'; +import { IBannerContent } from '../../types/interfaces'; +import './not-found-page.scss'; + +interface ISectionContent { + title: string; + descr: string; +} + +const bannerContent: IBannerContent = { + title: 'Wanderlust Dreams: Unveil the World with Exclusive Tours', + text: 'Satisfy your wanderlust with our collection of exclusive tours tailored to quench your thirst for exploration.', +}; + +const sectionContent: ISectionContent = { + title: '404: Destination Not Found', + descr: `Looks like this path hasn't been explored yet. Let's navigate you back to familiar terrain.`, +}; + +export default class NotFoundPage extends BaseComponent<'div'> { + private notFoundSection: HTMLElement; + private bannerSection: HTMLElement; + + constructor() { + super('div', ['not-found-page']); + + this.notFoundSection = new BaseComponent('section', ['not-found-section']).getElement(); + this.renderSignupSection(); + + this.bannerSection = new Banner(bannerContent.title, bannerContent.text).getElement(); + + this.node.append(this.notFoundSection, this.bannerSection); + } + + private renderSignupSection(): void { + const container: HTMLElement = new BaseComponent('div', ['not-found-section__container']).getElement(); + + const notFoundWrapper = new BaseComponent('div', ['not-found-section__wrapper']).getElement(); + const notFoundTitle = new BaseComponent('h1', ['not-found-section__title'], sectionContent.title).getElement(); + const notFoundDescr = new BaseComponent('h3', ['not-found-section__descr'], sectionContent.descr).getElement(); + const notFoundBtn = new Button('button', 'Back to home page', ['button'], false, () => + changeUrlEvent(AppRoutesPath.MAIN) + ).getElement(); + + notFoundWrapper.append(notFoundTitle, notFoundDescr, notFoundBtn); + + container.append(notFoundWrapper); + + this.notFoundSection.append(container); + } +} diff --git a/src/pages/product-page/product-page.scss b/src/pages/product-page/product-page.scss new file mode 100644 index 0000000..7763634 --- /dev/null +++ b/src/pages/product-page/product-page.scss @@ -0,0 +1,15 @@ +.product-page { + padding-bottom: 48px; + + &__container { + @include container; + display: flex; + justify-content: flex-end; + gap: 24px; + + @include laptop { + flex-direction: column; + align-items: center; + } + } +} diff --git a/src/pages/product-page/product-page.ts b/src/pages/product-page/product-page.ts new file mode 100644 index 0000000..b4db3d8 --- /dev/null +++ b/src/pages/product-page/product-page.ts @@ -0,0 +1,117 @@ +import './product-page.scss'; +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import { IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import Product from '../../components/product/product'; +import getProductById from '../../services/getProductById'; +import { ProductData } from '@commercetools/platform-sdk'; +import { changeUrlEvent } from '../../utils/change-url-event'; +import Notification from '../../components/notification/notification'; +import categories from '../../constants/categories'; +import subcategories from '../../constants/subcategories'; +import { ICategory } from '../../types/types'; +import ProductSlider from '../../components/slider/slider'; + +export default class ProductPage extends BaseComponent<'div'> { + private productData: ProductData | null = null; + private productId: string = ''; + private breadcrumbsLinks: IBreadcrumbLink[] = []; + private isPage: boolean; + + constructor() { + super('div', ['product-page']); + + this.isPage = this.parseUrl(); + if (this.isPage) { + this.createMarkup(); + } else { + changeUrlEvent(AppRoutesPath.NOT_FOUND); + } + } + + private parseUrl(): boolean { + const url: string = window.location.pathname; + const parts: string[] = url.split('/').filter((part) => part !== ''); + + if (parts.length === 4) { + const categorySlug = parts[parts.length - 3]; + const subcategorySlug = parts[parts.length - 2]; + this.productId = parts[parts.length - 1]; + + const currentCategory: ICategory | undefined = categories.find((item) => item.slug === categorySlug); + const currentSubcategory: ICategory | undefined = subcategories[categorySlug]?.find( + (item) => item.slug === subcategorySlug + ); + + if (!currentCategory || !currentSubcategory) return false; + + this.breadcrumbsLinks = [ + { pageName: 'Home', pageHref: AppRoutesPath.MAIN }, + { pageName: 'Shop', pageHref: AppRoutesPath.SHOP }, + { pageName: currentCategory.label, pageHref: `/shop/${categorySlug}` }, + { pageName: currentSubcategory.label, pageHref: `/shop/${categorySlug}/${subcategorySlug}` }, + ]; + + return true; + } + + if (parts.length === 3) { + const categorySlug = parts[parts.length - 2]; + this.productId = parts[parts.length - 1]; + + const currentCategory: ICategory | undefined = categories.find((item) => item.slug === categorySlug); + + if (!currentCategory) return false; + + this.breadcrumbsLinks = [ + { pageName: 'Home', pageHref: AppRoutesPath.MAIN }, + { pageName: 'Shop', pageHref: AppRoutesPath.SHOP }, + { pageName: currentCategory.label, pageHref: `/shop/${categorySlug}` }, + ]; + + return true; + } + + if (parts.length === 2) { + this.productId = parts[parts.length - 1]; + + this.breadcrumbsLinks = [ + { pageName: 'Home', pageHref: AppRoutesPath.MAIN }, + { pageName: 'Shop', pageHref: AppRoutesPath.SHOP }, + ]; + + return true; + } + + return true; + } + + private async getProductData(id: string): Promise { + try { + const product = await getProductById(id); + + this.productData = product.masterData.current; + } catch (err) { + if (err instanceof Error) new Notification('error', err.message).showNotification(); + + changeUrlEvent(AppRoutesPath.NOT_FOUND); + } + } + + private async createMarkup(): Promise { + await this.getProductData(this.productId); + + const productName = this.productData?.name.en || 'Unnamed tour'; + const productImages = this.productData?.masterVariant.images || []; + + const slider = new ProductSlider(productImages).getElement(); + const product = new Product(this.productId, this.productData!).getElement(); + + const breadcrumbs = new Breadcrumbs(this.breadcrumbsLinks, productName).getElement(); + const container = new BaseComponent('div', ['product-page__container']).getElement(); + + container.append(slider, product); + this.node.append(breadcrumbs, container); + } +} diff --git a/src/pages/signup-page/signup-page.scss b/src/pages/signup-page/signup-page.scss new file mode 100644 index 0000000..bfec7fd --- /dev/null +++ b/src/pages/signup-page/signup-page.scss @@ -0,0 +1,16 @@ +.signup-page { + display: flex; + flex-direction: column; +} + +.signup-section { + margin-bottom: 104px; + + @include mobile { + margin-bottom: 80px; + } + + &__container { + @include container; + } +} diff --git a/src/pages/signup-page/signup-page.ts b/src/pages/signup-page/signup-page.ts new file mode 100644 index 0000000..a0ee233 --- /dev/null +++ b/src/pages/signup-page/signup-page.ts @@ -0,0 +1,48 @@ +import BaseComponent from '../../components/base-component'; +import Breadcrumbs from '../../components/breadcrumbs/breadcrumbs'; +import SignupForm from '../../components/form/signup-form'; +import Banner from '../../components/banner/banner'; +import { IBannerContent, IBreadcrumbLink } from '../../types/interfaces'; +import { AppRoutesPath } from '../../router/types'; +import './signup-page.scss'; + +const breadcrumbsLinks: IBreadcrumbLink[] = [ + { + pageName: 'Home', + pageHref: AppRoutesPath.MAIN, + }, +]; + +const bannerContent: IBannerContent = { + title: 'Discover the World: Book Unforgettable Journeys Today!', + text: 'Our expertly crafted itineraries take you beyond the ordinary, unveiling the hidden gems of captivating destinations across the globe.', +}; + +export default class SignupPage extends BaseComponent<'div'> { + private breadcrumbs: HTMLElement; + private signupSection: HTMLElement; + private bannerSection: HTMLElement; + + constructor() { + super('div', ['signup-page']); + + this.breadcrumbs = new Breadcrumbs(breadcrumbsLinks, 'Create Account').getElement(); + + this.signupSection = new BaseComponent('section', ['signup-section']).getElement(); + this.renderSignupSection(); + + this.bannerSection = new Banner(bannerContent.title, bannerContent.text).getElement(); + + this.node.append(this.breadcrumbs, this.signupSection, this.bannerSection); + } + + private renderSignupSection(): void { + const container: HTMLElement = new BaseComponent('div', ['signup-section__container']).getElement(); + + const signupForm = new SignupForm().getElement(); + + container.append(signupForm); + + this.signupSection.append(container); + } +} diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..f30530a --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,71 @@ +import { AppRoute, AppRoutesPath, MiddlewareTypes } from './types'; +import { ROUTES, NOT_FOUND_ROUTE, MAIN_ROUTE, LOGIN_ROUTE } from './routes'; +import { accountMiddleware, authMiddleware } from '../utils/router-middleware'; +import Notification from '../components/notification/notification'; + +const LOGGED_IN_ERROR_DURATION: number = 3000; + +export class Router { + constructor( + private readonly routes: AppRoute[], + private onHashChange: (route: AppRoute) => void + ) { + window.addEventListener('changeURL', this.onHashChangeHandler.bind(this) as EventListener); + window.addEventListener('popstate', this.onHashChangeHandler.bind(this)); + this.onHashChangeHandler(); + } + + private handleMiddlewareError(type: MiddlewareTypes): void { + if (type === MiddlewareTypes.AUTH) { + new Notification('error', 'You are already logged in!', LOGGED_IN_ERROR_DURATION).showNotification(); + window.history.pushState({}, '', AppRoutesPath.MAIN); + this.onHashChange(MAIN_ROUTE); + } else { + new Notification('error', 'You need to be logged in!', LOGGED_IN_ERROR_DURATION).showNotification(); + window.history.pushState({}, '', AppRoutesPath.LOGIN); + this.onHashChange(LOGIN_ROUTE); + } + } + + private onHashChangeHandler(): void { + const pathname: string[] = location.pathname.split('/').slice(1); + + const matchedRoute: AppRoute | undefined = this.routes.find((route) => { + const routePathSegments: string[] = route.path.split('/').slice(1); + + if (routePathSegments.length !== pathname.length) { + return false; + } + + const match: boolean = routePathSegments.every((routePathSegment: string, i: number): boolean => { + return routePathSegment === pathname[i] || routePathSegment[0] === ':'; + }); + + return match; + }); + + if (!matchedRoute) { + this.onHashChange(NOT_FOUND_ROUTE); + } else if (authMiddleware(matchedRoute.path)) { + this.handleMiddlewareError(MiddlewareTypes.AUTH); + } else if (accountMiddleware(matchedRoute.path)) { + this.handleMiddlewareError(MiddlewareTypes.ACCOUNT); + } else { + this.onHashChange(matchedRoute); + } + } +} + +export function createRouter(routerOutlet: HTMLElement): Router { + return new Router(ROUTES, (route) => { + if (route) { + routerOutlet.innerHTML = ''; + routerOutlet.append(route.component()); + + document.body?.scrollIntoView({ + behavior: 'smooth', + block: 'start', + }); + } + }); +} diff --git a/src/router/routes.ts b/src/router/routes.ts new file mode 100644 index 0000000..41cb722 --- /dev/null +++ b/src/router/routes.ts @@ -0,0 +1,69 @@ +import { AppRoute, AppRoutesPath } from './types'; + +import MainPage from '../pages/main-page/main-page'; +import LoginPage from '../pages/login-page/login-page'; +import SignupPage from '../pages/signup-page/signup-page'; +import NotFoundPage from '../pages/not-found-page/not-found-page'; +import CatalogPage from '../pages/catalog-page/catalog-page'; +import ProductPage from '../pages/product-page/product-page'; +import AccountPage from '../pages/account-page/account-page'; +import AddressesPage from '../pages/addresses-page/addresses-page'; +import BasketPage from '../pages/basket-page/basket-page'; +import AboutUsPage from '../pages/about-us-page/about-us-page'; + +export const MAIN_ROUTE: AppRoute = { + path: AppRoutesPath.MAIN, + component: () => new MainPage().getElement(), +}; + +export const LOGIN_ROUTE: AppRoute = { + path: AppRoutesPath.LOGIN, + component: () => new LoginPage().getElement(), +}; + +export const NOT_FOUND_ROUTE: AppRoute = { + path: AppRoutesPath.NOT_FOUND, + component: () => new NotFoundPage().getElement(), +}; + +export const ROUTES: AppRoute[] = [ + MAIN_ROUTE, + LOGIN_ROUTE, + { + path: AppRoutesPath.SIGN_UP, + component: () => new SignupPage().getElement(), + }, + { + path: AppRoutesPath.ACCOUNT, + component: () => new AccountPage().getElement(), + }, + { + path: AppRoutesPath.ACCOUNT_ADDRESSES, + component: () => new AddressesPage().getElement(), // TODO: Change page-component when implemented + }, + { + path: AppRoutesPath.SHOP, + component: () => new CatalogPage().getElement(), + }, + { + path: AppRoutesPath.CATEGORY, + component: () => new CatalogPage().getElement(), + }, + { + path: AppRoutesPath.SUBCATEGORY, + component: () => new CatalogPage().getElement(), + }, + { + path: AppRoutesPath.PRODUCT, + component: () => new ProductPage().getElement(), + }, + { + path: AppRoutesPath.BASKET, + component: () => new BasketPage().getElement(), + }, + { + path: AppRoutesPath.ABOUT_US, + component: () => new AboutUsPage().getElement(), + }, + NOT_FOUND_ROUTE, +]; diff --git a/src/router/types.ts b/src/router/types.ts new file mode 100644 index 0000000..7151298 --- /dev/null +++ b/src/router/types.ts @@ -0,0 +1,25 @@ +export interface AppRoute { + path: AppRoutesPath; + component: () => HTMLElement; +} + +export enum AppRoutesPath { + MAIN = '/', + LOGIN = '/login', + SIGN_UP = '/registration', + ACCOUNT = '/account', + ACCOUNT_ADDRESSES = '/account/addresses', + SHOP = '/shop', + CATEGORY = '/shop/:category', + SUBCATEGORY = '/shop/:category/:subcategory', + PRODUCT = '/shop/:category/:subcategory/:id', + BASKET = '/basket', + ABOUT_US = '/about-us', + NOT_FOUND = '/404', + ANCHOR = '#', +} + +export enum MiddlewareTypes { + AUTH = 'auth', + ACCOUNT = 'account', +} diff --git a/src/services/TokenCache.ts b/src/services/TokenCache.ts new file mode 100644 index 0000000..9bca4e0 --- /dev/null +++ b/src/services/TokenCache.ts @@ -0,0 +1,21 @@ +import { TokenCache, TokenStore } from '@commercetools/sdk-client-v2'; + +export default class MyTokenCache implements TokenCache { + private token: TokenStore; + + constructor() { + this.token = { + token: '', + refreshToken: '', + expirationTime: 0, + }; + } + + set(newToken: TokenStore) { + this.token = newToken; + } + + get() { + return this.token; + } +} diff --git a/src/services/addresses/addAddress.ts b/src/services/addresses/addAddress.ts new file mode 100644 index 0000000..49a83fc --- /dev/null +++ b/src/services/addresses/addAddress.ts @@ -0,0 +1,28 @@ +import { ClientResponse, Customer, MyCustomerAddAddressAction, _BaseAddress } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import apiExistingToken from '../apiExistingToken'; + +export default async function addAddress(data: _BaseAddress): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const action: MyCustomerAddAddressAction = { + action: 'addAddress', + address: data, + }; + + const body = { + body: { + version: Number(customer?.version), + actions: [action], + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken).me().post(body).execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/addresses/addTypeAddressID.ts b/src/services/addresses/addTypeAddressID.ts new file mode 100644 index 0000000..83330e4 --- /dev/null +++ b/src/services/addresses/addTypeAddressID.ts @@ -0,0 +1,33 @@ +import { + ClientResponse, + Customer, + MyBusinessUnitAddBillingAddressIdAction, + MyBusinessUnitAddShippingAddressIdAction, +} from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import apiExistingToken from '../apiExistingToken'; + +export default async function addTypeAddressID(type: string, id: string): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const action: MyBusinessUnitAddBillingAddressIdAction | MyBusinessUnitAddShippingAddressIdAction = { + action: type === 'Billing' ? 'addBillingAddressId' : 'addShippingAddressId', + addressId: id, + }; + + const body = { + body: { + version: Number(customer?.version), + actions: [action], + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken).me().post(body).execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/addresses/changeAddress.ts b/src/services/addresses/changeAddress.ts new file mode 100644 index 0000000..bed69f2 --- /dev/null +++ b/src/services/addresses/changeAddress.ts @@ -0,0 +1,29 @@ +import { ClientResponse, Customer, MyCustomerChangeAddressAction, _BaseAddress } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import apiExistingToken from '../apiExistingToken'; + +export default async function changeAddress(id: string, data: _BaseAddress): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const action: MyCustomerChangeAddressAction = { + action: 'changeAddress', + addressId: id, + address: data, + }; + + const body = { + body: { + version: Number(customer?.version), + actions: [action], + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken).me().post(body).execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/addresses/removeAddress.ts b/src/services/addresses/removeAddress.ts new file mode 100644 index 0000000..882cdc2 --- /dev/null +++ b/src/services/addresses/removeAddress.ts @@ -0,0 +1,28 @@ +import { ClientResponse, Customer, MyCustomerRemoveAddressAction } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import apiExistingToken from '../apiExistingToken'; + +export default async function removeAddress(id: string): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const action: MyCustomerRemoveAddressAction = { + action: 'removeAddress', + addressId: id, + }; + + const body = { + body: { + version: Number(customer?.version), + actions: [action], + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken).me().post(body).execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/addresses/removeTypeAddressID.ts b/src/services/addresses/removeTypeAddressID.ts new file mode 100644 index 0000000..4e99352 --- /dev/null +++ b/src/services/addresses/removeTypeAddressID.ts @@ -0,0 +1,33 @@ +import { + ClientResponse, + Customer, + MyBusinessUnitRemoveBillingAddressIdAction, + MyBusinessUnitRemoveShippingAddressIdAction, +} from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import apiExistingToken from '../apiExistingToken'; + +export default async function removeTypeAddressID(type: string, id: string): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const action: MyBusinessUnitRemoveBillingAddressIdAction | MyBusinessUnitRemoveShippingAddressIdAction = { + action: type === 'Billing' ? 'removeBillingAddressId' : 'removeShippingAddressId', + addressId: id, + }; + + const body = { + body: { + version: Number(customer?.version), + actions: [action], + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken).me().post(body).execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/addresses/setDefaultTypeAddress.ts b/src/services/addresses/setDefaultTypeAddress.ts new file mode 100644 index 0000000..5acbe55 --- /dev/null +++ b/src/services/addresses/setDefaultTypeAddress.ts @@ -0,0 +1,33 @@ +import { + ClientResponse, + Customer, + MyCustomerSetDefaultBillingAddressAction, + MyCustomerSetDefaultShippingAddressAction, +} from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import apiExistingToken from '../apiExistingToken'; + +export default async function setDefaultTypeAddress(type: string, id: string): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const action: MyCustomerSetDefaultBillingAddressAction | MyCustomerSetDefaultShippingAddressAction = { + action: type === 'Billing' ? 'setDefaultBillingAddress' : 'setDefaultShippingAddress', + addressId: id.trim() === '' ? undefined : id, + }; + + const body = { + body: { + version: Number(customer?.version), + actions: [action], + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken).me().post(body).execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/apiExistingToken.ts b/src/services/apiExistingToken.ts new file mode 100644 index 0000000..6e121e1 --- /dev/null +++ b/src/services/apiExistingToken.ts @@ -0,0 +1,26 @@ +import { + ClientBuilder, + HttpMiddlewareOptions, + type ExistingTokenMiddlewareOptions, +} from '@commercetools/sdk-client-v2'; +import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'; + +const projectKey: string = process.env.CTP_PROJECT_KEY || ''; + +export default function apiExistingToken(token: string) { + const options: ExistingTokenMiddlewareOptions = { + force: false, + }; + + const httpMiddlewareOptions: HttpMiddlewareOptions = { + host: process.env.CTP_API_URL || '', + fetch, + }; + + const ctpClient = new ClientBuilder() + .withProjectKey(projectKey) + .withExistingTokenFlow(`Bearer ${token}`, options) + .withHttpMiddleware(httpMiddlewareOptions) + .build(); + return createApiBuilderFromCtpClient(ctpClient).withProjectKey({ projectKey }); +} diff --git a/src/services/apiRefreshToken.ts b/src/services/apiRefreshToken.ts new file mode 100644 index 0000000..a47aa7a --- /dev/null +++ b/src/services/apiRefreshToken.ts @@ -0,0 +1,35 @@ +import { + ClientBuilder, + type TokenCache, + type HttpMiddlewareOptions, + type RefreshAuthMiddlewareOptions, +} from '@commercetools/sdk-client-v2'; +import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'; + +const projectKey: string = process.env.CTP_PROJECT_KEY || ''; + +export default function apiRefreshToken(refreshToken: string, tokenCache: TokenCache) { + const options: RefreshAuthMiddlewareOptions = { + host: process.env.CTP_AUTH_URL || '', + projectKey, + credentials: { + clientId: process.env.CTP_CLIENT_ID || '', + clientSecret: process.env.CTP_CLIENT_SECRET || '', + }, + refreshToken, + tokenCache, + fetch, + }; + + const httpMiddlewareOptions: HttpMiddlewareOptions = { + host: process.env.CTP_API_URL || '', + fetch, + }; + + const ctpClient = new ClientBuilder() + .withProjectKey(projectKey) + .withRefreshTokenFlow(options) + .withHttpMiddleware(httpMiddlewareOptions) + .build(); + return createApiBuilderFromCtpClient(ctpClient).withProjectKey({ projectKey }); +} diff --git a/src/services/apiRootAnonymus.ts b/src/services/apiRootAnonymus.ts new file mode 100644 index 0000000..51a44ac --- /dev/null +++ b/src/services/apiRootAnonymus.ts @@ -0,0 +1,36 @@ +import { + ClientBuilder, + type AnonymousAuthMiddlewareOptions, + type HttpMiddlewareOptions, + TokenCache, +} from '@commercetools/sdk-client-v2'; +import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'; + +export default function apiRootAnonymus(tokenCache?: TokenCache) { + const projectKey: string = process.env.CTP_PROJECT_KEY || ''; + + const anonymousAuthMiddlewareOptions: AnonymousAuthMiddlewareOptions = { + host: process.env.CTP_AUTH_URL || '', + projectKey, + credentials: { + clientId: process.env.CTP_CLIENT_ID || '', + clientSecret: process.env.CTP_CLIENT_SECRET || '', + }, + scopes: [process.env.CTP_SCOPES || ''], + tokenCache, + fetch, + }; + + const httpMiddlewareOptions: HttpMiddlewareOptions = { + host: process.env.CTP_API_URL || '', + fetch, + }; + + const ctpClient = new ClientBuilder() + .withProjectKey(projectKey) + .withAnonymousSessionFlow(anonymousAuthMiddlewareOptions) + .withHttpMiddleware(httpMiddlewareOptions) + .build(); + + return createApiBuilderFromCtpClient(ctpClient).withProjectKey({ projectKey }); +} diff --git a/src/services/apiRootCredentials.ts b/src/services/apiRootCredentials.ts new file mode 100644 index 0000000..31d74d4 --- /dev/null +++ b/src/services/apiRootCredentials.ts @@ -0,0 +1,30 @@ +import { ClientBuilder, type AuthMiddlewareOptions, type HttpMiddlewareOptions } from '@commercetools/sdk-client-v2'; +import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'; + +export default function apiRootCredentials() { + const projectKey: string = process.env.CTP_PROJECT_KEY || ''; + + const authMiddlewareOptions: AuthMiddlewareOptions = { + host: process.env.CTP_AUTH_URL || '', + projectKey, + credentials: { + clientId: process.env.CTP_CLIENT_ID || '', + clientSecret: process.env.CTP_CLIENT_SECRET || '', + }, + scopes: [process.env.CTP_SCOPES || ''], + fetch, + }; + + const httpMiddlewareOptions: HttpMiddlewareOptions = { + host: process.env.CTP_API_URL || '', + fetch, + }; + + const ctpClient = new ClientBuilder() + .withProjectKey(projectKey) + .withClientCredentialsFlow(authMiddlewareOptions) + .withHttpMiddleware(httpMiddlewareOptions) + .build(); + + return createApiBuilderFromCtpClient(ctpClient).withProjectKey({ projectKey }); +} diff --git a/src/services/apiRootPassword.ts b/src/services/apiRootPassword.ts new file mode 100644 index 0000000..fbe0a0d --- /dev/null +++ b/src/services/apiRootPassword.ts @@ -0,0 +1,40 @@ +import { + ClientBuilder, + TokenCache, + type PasswordAuthMiddlewareOptions, + type HttpMiddlewareOptions, +} from '@commercetools/sdk-client-v2'; +import { createApiBuilderFromCtpClient } from '@commercetools/platform-sdk'; + +const projectKey: string = process.env.CTP_PROJECT_KEY || ''; + +export default function apiRootPassword(email: string, password: string, tokenCache: TokenCache) { + const options: PasswordAuthMiddlewareOptions = { + host: process.env.CTP_AUTH_URL || '', + projectKey, + credentials: { + clientId: process.env.CTP_CLIENT_ID || '', + clientSecret: process.env.CTP_CLIENT_SECRET || '', + user: { + username: email, + password, + }, + }, + scopes: [process.env.CTP_SCOPES || ''], + tokenCache, + fetch, + }; + + const httpMiddlewareOptions: HttpMiddlewareOptions = { + host: process.env.CTP_API_URL || '', + fetch, + }; + + const ctpClient = new ClientBuilder() + .withProjectKey(projectKey) + .withPasswordFlow(options) + .withHttpMiddleware(httpMiddlewareOptions) + .build(); + + return createApiBuilderFromCtpClient(ctpClient).withProjectKey({ projectKey }); +} diff --git a/src/services/basket/addDiscountToCart.ts b/src/services/basket/addDiscountToCart.ts new file mode 100644 index 0000000..d472682 --- /dev/null +++ b/src/services/basket/addDiscountToCart.ts @@ -0,0 +1,79 @@ +import { ClientResponse, Cart, MyCartRemoveDiscountCodeAction } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import createAnonymusCart from './createAnonymusCart'; +import getActiveCart from './getActiveCart'; +import apiExistingToken from '../apiExistingToken'; +import Notification from '../../components/notification/notification'; +import createUserCart from './createUserCart'; + +export default async function addDiscountToCart(code: string): Promise { + const { isAuth } = userStore.getState(); + let cart: Cart; + let token: string | null; + + if (!isAuth) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + await createAnonymusCart(); + token = localStorage.getItem('tokenAnon'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + + cart = await getActiveCart(token); + } else { + token = localStorage.getItem('token'); + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + + try { + cart = await getActiveCart(token); + } catch { + cart = await createUserCart(token); + } + } + + function removeAllDiscountes(): MyCartRemoveDiscountCodeAction[] | [] { + const result: MyCartRemoveDiscountCodeAction[] = []; + + cart.discountCodes.forEach((item) => { + result.push({ + action: 'removeDiscountCode', + discountCode: { + typeId: item.discountCode.typeId, + id: item.discountCode.id, + }, + }); + }); + + return result; + } + + const response: ClientResponse = await apiExistingToken(token) + .me() + .carts() + .withId({ + ID: cart.id, + }) + .post({ + body: { + version: cart.version, + actions: [ + ...removeAllDiscountes(), + { + action: 'addDiscountCode', + code, + }, + ], + }, + }) + .execute(); + + return response?.body; +} diff --git a/src/services/basket/addToCart.ts b/src/services/basket/addToCart.ts new file mode 100644 index 0000000..b860183 --- /dev/null +++ b/src/services/basket/addToCart.ts @@ -0,0 +1,62 @@ +import { ClientResponse, Cart } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import createAnonymusCart from './createAnonymusCart'; +import getActiveCart from './getActiveCart'; +import apiExistingToken from '../apiExistingToken'; +import Notification from '../../components/notification/notification'; +import createUserCart from './createUserCart'; + +export default async function addToCart(productId: string): Promise { + const { isAuth } = userStore.getState(); + let cart: Cart; + let token: string | null; + + if (!isAuth) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + await createAnonymusCart(); + token = localStorage.getItem('tokenAnon'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + + cart = await getActiveCart(token); + } else { + token = localStorage.getItem('token'); + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + + try { + cart = await getActiveCart(token); + } catch { + cart = await createUserCart(token); + } + } + + const response: ClientResponse = await apiExistingToken(token) + .me() + .carts() + .withId({ + ID: cart.id, + }) + .post({ + body: { + version: cart.version, + actions: [ + { + action: 'addLineItem', + productId, + }, + ], + }, + }) + .execute(); + + return response?.body; +} diff --git a/src/services/basket/changeCartItemQuantity.ts b/src/services/basket/changeCartItemQuantity.ts new file mode 100644 index 0000000..0e0bd2e --- /dev/null +++ b/src/services/basket/changeCartItemQuantity.ts @@ -0,0 +1,63 @@ +import { ClientResponse, Cart } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import createAnonymusCart from './createAnonymusCart'; +import getActiveCart from './getActiveCart'; +import apiExistingToken from '../apiExistingToken'; +import Notification from '../../components/notification/notification'; +import createUserCart from './createUserCart'; + +export default async function changeCartItemQuantity(lineItemId: string, quantity: number): Promise { + const { isAuth } = userStore.getState(); + let cart: Cart; + let token: string | null; + + if (!isAuth) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + await createAnonymusCart(); + token = localStorage.getItem('tokenAnon'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + + cart = await getActiveCart(token); + } else { + token = localStorage.getItem('token'); + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + + try { + cart = await getActiveCart(token); + } catch { + cart = await createUserCart(token); + } + } + + const response: ClientResponse = await apiExistingToken(token) + .me() + .carts() + .withId({ + ID: cart.id, + }) + .post({ + body: { + version: cart.version, + actions: [ + { + action: 'changeLineItemQuantity', + lineItemId, + quantity, + }, + ], + }, + }) + .execute(); + + return response?.body; +} diff --git a/src/services/basket/createAnonymusCart.ts b/src/services/basket/createAnonymusCart.ts new file mode 100644 index 0000000..5916e00 --- /dev/null +++ b/src/services/basket/createAnonymusCart.ts @@ -0,0 +1,24 @@ +import { Cart, ClientResponse } from '@commercetools/platform-sdk'; +import apiRootAnonymus from '../apiRootAnonymus'; +import MyTokenCache from '../TokenCache'; + +export default async function createAnonymusCart(): Promise { + const tokenCache = new MyTokenCache(); + + const response: ClientResponse = await apiRootAnonymus(tokenCache) + .me() + .carts() + .post({ + body: { + currency: 'USD', + country: 'US', + }, + }) + .execute(); + + const { token, refreshToken } = tokenCache.get(); + if (token) localStorage.setItem('tokenAnon', token); + if (refreshToken) localStorage.setItem('refreshTokenAnon', refreshToken); + + return response.body; +} diff --git a/src/services/basket/createUserCart.ts b/src/services/basket/createUserCart.ts new file mode 100644 index 0000000..8f16555 --- /dev/null +++ b/src/services/basket/createUserCart.ts @@ -0,0 +1,17 @@ +import { Cart, ClientResponse } from '@commercetools/platform-sdk'; +import apiExistingToken from '../apiExistingToken'; + +export default async function createUserCart(token: string): Promise { + const response: ClientResponse = await apiExistingToken(token) + .me() + .carts() + .post({ + body: { + currency: 'USD', + country: 'US', + }, + }) + .execute(); + + return response.body; +} diff --git a/src/services/basket/getActiveCart.ts b/src/services/basket/getActiveCart.ts new file mode 100644 index 0000000..c3a63bb --- /dev/null +++ b/src/services/basket/getActiveCart.ts @@ -0,0 +1,8 @@ +import { Cart, ClientResponse } from '@commercetools/platform-sdk'; +import apiExistingToken from '../apiExistingToken'; + +export default async function getActiveCart(token: string): Promise { + const response: ClientResponse = await apiExistingToken(token).me().activeCart().get().execute(); + + return response.body; +} diff --git a/src/services/basket/getCart.ts b/src/services/basket/getCart.ts new file mode 100644 index 0000000..c9b7442 --- /dev/null +++ b/src/services/basket/getCart.ts @@ -0,0 +1,69 @@ +import { Cart } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import createUserCart from './createUserCart'; +import Notification from '../../components/notification/notification'; +import createAnonymusCart from './createAnonymusCart'; +import getAnonActiveCart from '../getAnonActiveCart'; +import getActiveCart from './getActiveCart'; + +export default async function getCart(): Promise { + let token: string | null; + let refreshToken: string | null; + const { isAuth } = userStore.getState(); + + if (isAuth) { + token = localStorage.getItem('token'); + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + + try { + return await getActiveCart(token); + } catch { + return await createUserCart(token); + } + } else { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + try { + return await createAnonymusCart(); + } catch (error) { + if (error instanceof Error) { + new Notification( + 'error', + 'Something went wrong! Please try to log in or try again later.' + ).showNotification(); + } else { + console.error(error); + } + return; + } + } + + try { + return await getActiveCart(token); + } catch (error) { + if (error instanceof Error) { + if (error.message === 'invalid_token') { + localStorage.removeItem('tokenAnon'); + localStorage.removeItem('token'); + + refreshToken = localStorage.getItem('refreshTokenAnon'); + if (!refreshToken) { + new Notification( + 'error', + 'Something went wrong! Please try to log in or try again later.' + ).showNotification(); + return; + } + return await getAnonActiveCart(refreshToken); + } + } else { + console.error(error); + } + return await createAnonymusCart(); + } + } +} diff --git a/src/services/basket/removeCart.ts b/src/services/basket/removeCart.ts new file mode 100644 index 0000000..3d9a2d1 --- /dev/null +++ b/src/services/basket/removeCart.ts @@ -0,0 +1,37 @@ +import userStore from '../../store/user-store'; +import createAnonymusCart from './createAnonymusCart'; +import Notification from '../../components/notification/notification'; +import { Cart } from '@commercetools/platform-sdk'; +import createUserCart from './createUserCart'; + +export default async function removeCart(): Promise { + const { isAuth } = userStore.getState(); + let token: string | null; + let cart: Cart | undefined = undefined; + + if (!isAuth) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + + cart = await createAnonymusCart(); + } else { + token = localStorage.getItem('token'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + + cart = await createUserCart(token); + } + + return cart; +} diff --git a/src/services/basket/removeDiscountCart.ts b/src/services/basket/removeDiscountCart.ts new file mode 100644 index 0000000..5374941 --- /dev/null +++ b/src/services/basket/removeDiscountCart.ts @@ -0,0 +1,73 @@ +import { ClientResponse, Cart, MyCartRemoveDiscountCodeAction } from '@commercetools/platform-sdk'; +import userStore from '../../store/user-store'; +import createAnonymusCart from './createAnonymusCart'; +import getActiveCart from './getActiveCart'; +import apiExistingToken from '../apiExistingToken'; +import Notification from '../../components/notification/notification'; +import createUserCart from './createUserCart'; + +export default async function removeDiscountCart(): Promise { + const { isAuth } = userStore.getState(); + let cart: Cart; + let token: string | null; + + if (!isAuth) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + await createAnonymusCart(); + token = localStorage.getItem('tokenAnon'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + + cart = await getActiveCart(token); + } else { + token = localStorage.getItem('token'); + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + + try { + cart = await getActiveCart(token); + } catch { + cart = await createUserCart(token); + } + } + + function removeAllDiscountes(): MyCartRemoveDiscountCodeAction[] | [] { + const result: MyCartRemoveDiscountCodeAction[] = []; + + cart.discountCodes.forEach((item) => { + result.push({ + action: 'removeDiscountCode', + discountCode: { + typeId: item.discountCode.typeId, + id: item.discountCode.id, + }, + }); + }); + + return result; + } + + const response: ClientResponse = await apiExistingToken(token) + .me() + .carts() + .withId({ + ID: cart.id, + }) + .post({ + body: { + version: cart.version, + actions: [...removeAllDiscountes()], + }, + }) + .execute(); + + return response?.body; +} diff --git a/src/services/basket/removeProductFromCart.ts b/src/services/basket/removeProductFromCart.ts new file mode 100644 index 0000000..227bd01 --- /dev/null +++ b/src/services/basket/removeProductFromCart.ts @@ -0,0 +1,56 @@ +import userStore from '../../store/user-store'; +import createAnonymusCart from './createAnonymusCart'; +import Notification from '../../components/notification/notification'; +import getActiveCart from './getActiveCart'; +import apiExistingToken from '../apiExistingToken'; +import { Cart } from '@commercetools/platform-sdk'; + +export default async function removeProductFromCart(productId: string): Promise { + const { isAuth } = userStore.getState(); + let token: string | null; + + if (!isAuth) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + await createAnonymusCart(); + token = localStorage.getItem('tokenAnon'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + } else { + token = localStorage.getItem('token'); + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + + const cart: Cart = await getActiveCart(token); + + const cartItem = cart.lineItems.filter((item) => item.productId === productId); + + const response = await apiExistingToken(token) + .me() + .carts() + .withId({ + ID: cart.id, + }) + .post({ + body: { + version: cart.version, + actions: [ + { + action: 'removeLineItem', + lineItemId: cartItem[0].id, + }, + ], + }, + }) + .execute(); + + return response?.body; +} diff --git a/src/services/changePassword.ts b/src/services/changePassword.ts new file mode 100644 index 0000000..0b7d9aa --- /dev/null +++ b/src/services/changePassword.ts @@ -0,0 +1,28 @@ +import { ClientResponse, Customer, MyCustomerChangePassword } from '@commercetools/platform-sdk'; +import userStore from '../store/user-store'; +import apiExistingToken from './apiExistingToken'; + +export default async function changePassword(currentPassword: string, newPassword: string): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const sendData: { body: MyCustomerChangePassword } = { + body: { + version: Number(customer?.version), + currentPassword, + newPassword, + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken) + .me() + .password() + .post(sendData) + .execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/getAllCategories.ts b/src/services/getAllCategories.ts new file mode 100644 index 0000000..aa0838c --- /dev/null +++ b/src/services/getAllCategories.ts @@ -0,0 +1,8 @@ +import { type Category } from '@commercetools/platform-sdk'; +import apiRootCredentials from './apiRootCredentials'; + +export default async function getAllCategories(): Promise { + const response = await apiRootCredentials().categories().get().execute(); + + return response.body.results; +} diff --git a/src/services/getAnonActiveCart.ts b/src/services/getAnonActiveCart.ts new file mode 100644 index 0000000..d79d04d --- /dev/null +++ b/src/services/getAnonActiveCart.ts @@ -0,0 +1,17 @@ +import { Cart, ClientResponse } from '@commercetools/platform-sdk'; +import apiRefreshToken from './apiRefreshToken'; +import MyTokenCache from './TokenCache'; + +export default async function getAnonActiveCart(refreshToken: string): Promise { + const tokenCache = new MyTokenCache(); + const response: ClientResponse = await apiRefreshToken(refreshToken, tokenCache) + .me() + .activeCart() + .get() + .execute(); + + const { token } = tokenCache.get(); + if (token) localStorage.setItem('tokenAnon', token); + + return response.body; +} diff --git a/src/services/getDiscountCode.ts b/src/services/getDiscountCode.ts new file mode 100644 index 0000000..ca211e7 --- /dev/null +++ b/src/services/getDiscountCode.ts @@ -0,0 +1,51 @@ +import { Cart, ClientResponse, DiscountCode } from '@commercetools/platform-sdk'; +import userStore from '../store/user-store'; +import createAnonymusCart from './basket/createAnonymusCart'; +import getActiveCart from './basket/getActiveCart'; +import apiExistingToken from './apiExistingToken'; +import Notification from '../components/notification/notification'; +import createUserCart from './basket/createUserCart'; + +export default async function getDiscountCode(): Promise { + const { isAuth } = userStore.getState(); + let cart: Cart; + let token: string | null; + + if (!isAuth) { + token = localStorage.getItem('tokenAnon'); + + if (!token) { + await createAnonymusCart(); + token = localStorage.getItem('tokenAnon'); + + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + } + + cart = await getActiveCart(token); + } else { + token = localStorage.getItem('token'); + if (!token) { + new Notification('error', 'Something went wrong! Please try to log in or try again later.').showNotification(); + return; + } + + try { + cart = await getActiveCart(token); + } catch { + cart = await createUserCart(token); + } + } + + const response: ClientResponse = await apiExistingToken(token) + .discountCodes() + .withId({ + ID: cart?.discountCodes[0]?.discountCode?.id || '', + }) + .get() + .execute(); + + return response?.body; +} diff --git a/src/services/getProductById.ts b/src/services/getProductById.ts new file mode 100644 index 0000000..bdc7ac3 --- /dev/null +++ b/src/services/getProductById.ts @@ -0,0 +1,8 @@ +import { ClientResponse, Product } from '@commercetools/platform-sdk'; +import apiRootCredentials from './apiRootCredentials'; + +export default async function getProductById(ID: string): Promise { + const response: ClientResponse = await apiRootCredentials().products().withId({ ID }).get().execute(); + + return response.body; +} diff --git a/src/services/getProducts.ts b/src/services/getProducts.ts new file mode 100644 index 0000000..fdbf903 --- /dev/null +++ b/src/services/getProducts.ts @@ -0,0 +1,85 @@ +import { + Category, + type ClientResponse, + type ProductProjection, + type ProductProjectionPagedQueryResponse, +} from '@commercetools/platform-sdk'; +import apiRootCredentials from './apiRootCredentials'; +import getAllCategories from './getAllCategories'; +import { BASE_PRODUCT_LIMIT, BASE_PRODUCT_OFFSET } from '../constants/productsOptions'; + +interface IProductsResponse { + products: ProductProjection[]; + offset: number; + total: number; +} + +export default async function getProducts( + categoryName?: string, + subcategoryName?: string, + filterPrice: string = '', + filterDays: string = '', + sortValue: string = '', + searchValue: string = '', + offset: number = BASE_PRODUCT_OFFSET, + limit: number = BASE_PRODUCT_LIMIT +): Promise { + try { + const allCategories: Category[] = await getAllCategories(); + + let categoryId = ''; + const filter: string[] = []; + let filterQuery: string = ''; + let sort: string = ''; + const searchQuery = { + 'text.en': '', + }; + + if (subcategoryName) { + categoryId = allCategories.find((item) => item.key === subcategoryName)?.id || ''; + filter.push(`categories.id:"${categoryId}"`); + } else if (categoryName) { + categoryId = allCategories.find((item) => item.key === categoryName)?.id || ''; + filter.push(`categories.id: subtree("${categoryId}")`); + } + + if (filterPrice) { + filterQuery = `variants.price.centAmount:${filterPrice}`; + } + + if (filterDays) { + filter.push(`variants.attributes.days:${filterDays}`); + } + + if (sortValue) { + sort = sortValue; + } + + if (searchValue) { + searchQuery['text.en'] = searchValue; + } + + const response: ClientResponse = await apiRootCredentials() + .productProjections() + .search() + .get({ + queryArgs: { + ...(filter.length ? { filter } : {}), + ...(filterQuery ? { 'filter.query': filterQuery } : {}), + ...(sort ? { sort } : {}), + ...(searchValue ? searchQuery : {}), + limit, + offset, + }, + }) + .execute(); + + return { + products: response.body.results, + offset: response.body.offset ?? BASE_PRODUCT_OFFSET, + total: response.body.total ?? BASE_PRODUCT_LIMIT, + }; + } catch (error) { + console.log(error); + } +} diff --git a/src/services/getUser.ts b/src/services/getUser.ts new file mode 100644 index 0000000..ae39625 --- /dev/null +++ b/src/services/getUser.ts @@ -0,0 +1,8 @@ +import { ClientResponse, Customer } from '@commercetools/platform-sdk'; +import apiExistingToken from './apiExistingToken'; + +export default async function getUser(token: string): Promise { + const customer: ClientResponse = await apiExistingToken(token).me().get().execute(); + + return customer.body; +} diff --git a/src/services/signinUser.ts b/src/services/signinUser.ts new file mode 100644 index 0000000..8059273 --- /dev/null +++ b/src/services/signinUser.ts @@ -0,0 +1,43 @@ +import { ClientResponse, Customer, CustomerSignInResult } from '@commercetools/platform-sdk'; +import { ISigninData } from '../types/interfaces'; +import apiRootPassword from './apiRootPassword'; +import MyTokenCache from './TokenCache'; +import userStore from '../store/user-store'; +import apiExistingToken from './apiExistingToken'; + +export default async function signinUser(body: ISigninData): Promise { + const tokenCache = new MyTokenCache(); + + const tokenAnon: string | null = localStorage.getItem('tokenAnon'); + + if (tokenAnon) { + await apiExistingToken(tokenAnon) + .me() + .login() + .post({ + body: { + email: body.email, + password: body.password, + activeCartSignInMode: 'UseAsNewActiveCustomerCart', + }, + }) + .execute(); + + localStorage.removeItem('tokenAnon'); + } + + const response: ClientResponse = await apiRootPassword(body.email, body.password, tokenCache) + .me() + .login() + .post({ + body, + }) + .execute(); + + const { token } = tokenCache.get(); + if (token) localStorage.setItem('token', token); + userStore.dispatch({ type: 'SET_IS_AUTH', isAuth: true }); + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response?.body?.customer }); + + return response?.body?.customer; +} diff --git a/src/services/signupUser.ts b/src/services/signupUser.ts new file mode 100644 index 0000000..ac4d3dc --- /dev/null +++ b/src/services/signupUser.ts @@ -0,0 +1,21 @@ +import { Customer } from '@commercetools/platform-sdk'; +import { ISignupData } from '../types/interfaces'; +import apiRootCredentials from './apiRootCredentials'; +import signinUser from './signinUser'; + +export default async function signupUser(body: ISignupData): Promise { + await apiRootCredentials() + .me() + .signup() + .post({ + body, + }) + .execute(); + + const customer: Customer = await signinUser({ + email: body.email, + password: body.password, + }); + + return customer; +} diff --git a/src/services/updateUser.ts b/src/services/updateUser.ts new file mode 100644 index 0000000..ff49078 --- /dev/null +++ b/src/services/updateUser.ts @@ -0,0 +1,23 @@ +import { ClientResponse, Customer, MyCustomerUpdateAction } from '@commercetools/platform-sdk'; +import userStore from '../store/user-store'; +import apiExistingToken from './apiExistingToken'; + +export default async function updateUser(data: MyCustomerUpdateAction[]): Promise { + const { customer } = userStore.getState(); + + const currentToken = localStorage.getItem('token'); + const parsenToken = currentToken ? currentToken : ''; + + const body = { + body: { + version: Number(customer?.version), + actions: data, + }, + }; + + const response: ClientResponse = await apiExistingToken(parsenToken).me().post(body).execute(); + + userStore.dispatch({ type: 'ADD_CUSTOMER', customer: response.body }); + + return response.body; +} diff --git a/src/services/userLogout.ts b/src/services/userLogout.ts new file mode 100644 index 0000000..e780c6a --- /dev/null +++ b/src/services/userLogout.ts @@ -0,0 +1,7 @@ +import userStore from '../store/user-store'; + +export default function userLogout() { + localStorage.removeItem('token'); + userStore.dispatch({ type: 'SET_IS_AUTH', isAuth: false }); + userStore.dispatch({ type: 'REMOVE_CUSTOMER' }); +} diff --git a/src/store/base-store.ts b/src/store/base-store.ts new file mode 100644 index 0000000..74fef45 --- /dev/null +++ b/src/store/base-store.ts @@ -0,0 +1,35 @@ +export interface IStore { + getState: () => T; + subscribe: (fn: (state: T) => void) => void; + dispatch: (action: A) => void; + unsubscribe: () => void; +} + +export default class BaseStore implements IStore { + private subscribers: ((state: T) => void)[]; + private currentState: T; + private reducer: (state: T, action: A) => T; + + constructor(reducer: (state: T, action: A) => T, initialState: T) { + this.subscribers = []; + this.currentState = initialState; + this.reducer = reducer; + } + + getState(): T { + return this.currentState; + } + + subscribe(fn: (state: T) => void): void { + this.subscribers.push(fn); + } + + dispatch(action: A): void { + this.currentState = this.reducer(this.currentState, action); + this.subscribers.forEach((fn) => fn(this.currentState)); + } + + unsubscribe(): void { + this.subscribers = []; + } +} diff --git a/src/store/cart-store.ts b/src/store/cart-store.ts new file mode 100644 index 0000000..6e7d626 --- /dev/null +++ b/src/store/cart-store.ts @@ -0,0 +1,35 @@ +import { Cart } from '@commercetools/platform-sdk'; +import BaseStore, { IStore } from './base-store'; + +interface ICartState { + cart: Cart | undefined; +} + +interface ICartAction { + type: string; + cart?: Cart; +} + +const initialState: ICartState = { + cart: undefined, +}; + +const reducer = (state: ICartState, action: ICartAction): ICartState => { + const newState: ICartState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case 'UPDATE_CART': + if (action.cart) { + newState.cart = action.cart; + } + return newState; + case 'REMOVE_ITEMS': + newState.cart = undefined; + return newState; + default: + return newState; + } +}; + +const cartStore: IStore = new BaseStore(reducer, initialState); + +export default cartStore; diff --git a/src/store/shop-store.ts b/src/store/shop-store.ts new file mode 100644 index 0000000..6731d46 --- /dev/null +++ b/src/store/shop-store.ts @@ -0,0 +1,57 @@ +import BaseStore, { IStore } from './base-store'; + +interface IShopState { + filterPrice: string; + filterDays: string; + sortValue: string; + searchValue: string; +} + +interface IShopAction { + type: string; + newFilterPrice?: string; + newFilterDays?: string; + newSortValue?: string; + newSearchValue?: string; +} + +const initialState: IShopState = { + filterPrice: '', + filterDays: '', + sortValue: '', + searchValue: '', +}; + +const reducer = (state: IShopState, action: IShopAction): IShopState => { + const newState: IShopState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case 'SET_FILTER_PRICE': + if (action.newFilterPrice) newState.filterPrice = action.newFilterPrice; + return newState; + case 'SET_FILTER_DAYS': + if (action.newFilterDays) newState.filterDays = action.newFilterDays; + return newState; + case 'SET_SORT_VALUE': + if (action.newSortValue !== undefined) newState.sortValue = action.newSortValue; + return newState; + case 'SET_SEARCH_VALUE': + if (action.newSearchValue !== undefined) newState.searchValue = action.newSearchValue; + return newState; + case 'RESET_FILTER_PRICE': + newState.filterPrice = ''; + return newState; + case 'RESET_FILTER_DAYS': + newState.filterDays = ''; + return newState; + case 'RESET_ALL_FILTERS': + newState.filterPrice = ''; + newState.filterDays = ''; + return newState; + default: + return newState; + } +}; + +const shopStore: IStore = new BaseStore(reducer, initialState); + +export default shopStore; diff --git a/src/store/user-store.ts b/src/store/user-store.ts new file mode 100644 index 0000000..debf9b7 --- /dev/null +++ b/src/store/user-store.ts @@ -0,0 +1,39 @@ +import BaseStore, { IStore } from './base-store'; +import { Customer } from '@commercetools/platform-sdk'; + +interface IUserState { + isAuth: boolean; + customer: Customer | null; +} + +interface IUserAction { + type: string; + isAuth?: boolean; + customer?: Customer; +} + +const initialState: IUserState = { + isAuth: false, + customer: null, +}; + +const reducer = (state: IUserState, action: IUserAction): IUserState => { + const newState: IUserState = JSON.parse(JSON.stringify(state)); + switch (action.type) { + case 'SET_IS_AUTH': + if (action.isAuth !== undefined) newState.isAuth = action.isAuth; + return newState; + case 'ADD_CUSTOMER': + if (action.customer) newState.customer = action.customer; + return newState; + case 'REMOVE_CUSTOMER': + newState.customer = null; + return newState; + default: + return newState; + } +}; + +const userStore: IStore = new BaseStore(reducer, initialState); + +export default userStore; diff --git a/src/styles/base/_fonts.scss b/src/styles/base/_fonts.scss new file mode 100644 index 0000000..d812be5 --- /dev/null +++ b/src/styles/base/_fonts.scss @@ -0,0 +1,2 @@ +@import url('https://fonts.googleapis.com/css2?family=Gloock&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500;600;700&display=swap'); diff --git a/src/styles/base/_variables.scss b/src/styles/base/_variables.scss new file mode 100644 index 0000000..af834c2 --- /dev/null +++ b/src/styles/base/_variables.scss @@ -0,0 +1,165 @@ +// colors +$color-black: #000000; +$color-white: #ffffff; +$color-primary: #001329; +$color-secondary-40: #99a1a9; +$color-secondary-60: #66717f; +$color-bg-secondary: #d9d9d9; +$color-bg-light: #f5f6f7; +$color-gray: #f2f2f2; +$color-price: #2b8813; +$color-rating: #fcc400; +$color-logo: #ff8a00; +$color-button: #0058c1; +$color-button-hover: #1969c7; +$color-bg-card: #f5f6f6; +$color-border: #e0e3e5; +$color-error: #ef4444; +$color-success: #2b8813; + +// breakpoints +$width-small-mobile: 500px; +$width-mobile: 768px; +$width-tablet: 1024px; +$width-pre-tablet: 1200px; +$width-laptop: 1440px; + +@mixin small-mobile { + @media (max-width: $width-small-mobile) { + @content; + } +} + +@mixin mobile { + @media (max-width: $width-mobile) { + @content; + } +} + +@mixin tablet { + @media (max-width: $width-tablet) { + @content; + } +} + +@mixin pre-tablet { + @media (max-width: $width-pre-tablet) { + @content; + } +} + +@mixin laptop { + @media (max-width: $width-laptop) { + @content; + } +} + +@mixin desktop { + @media (min-width: $width-tablet) { + @content; + } +} + +// fonts +$font-family-jakarta: 'Plus Jakarta Sans', sans-serif; +$font-family-gloock: 'Gloock', serif; + +$font-main: 500 16px/1.5 $font-family-jakarta; +$font-subtitle: 500 18px/1.5 $font-family-jakarta; +$font-logo: 400 26px/0.92 $font-family-gloock; +$font-button: 700 15px/1.5 $font-family-jakarta; +$font-label: 600 15px/1.5 $font-family-jakarta; +$font-xs: 600 12px/1.5 $font-family-jakarta; +$font-about-label: 700 11px/1.2 $font-family-jakarta; + +@mixin font-h1 { + font: 400 60px/1.2 $font-family-gloock; + + @include tablet { + font-size: 50px; + } + + @include mobile { + font-size: 36px; + } +} + +@mixin font-h2 { + font: 400 40px/1.2 $font-family-gloock; + + @include tablet { + font-size: 36px; + } + + @include mobile { + font-size: 24px; + } +} + +@mixin font-h3 { + font: 400 32px/1.4 $font-family-gloock; + + @include tablet { + font-size: 28px; + } + + @include mobile { + font-size: 22px; + } +} + +@mixin font-h4 { + font: 400 24px/1.4 $font-family-gloock; + + @include tablet { + font-size: 20px; + } + + @include mobile { + font-size: 18px; + } +} + +// container +@mixin container { + margin: 0 auto; + max-width: 1920px; + padding: 0 120px; + + @include tablet { + padding: 0 60px; + } + + @include mobile { + padding: 0 20px; + } +} + +// another + +@mixin chevron { + position: absolute; + display: block; + content: ''; + width: 20px; + height: 20px; + background-image: url('../../../assets/icons/chevron-up.svg'); + background-position: center; + background-size: cover; + transition: all 0.1s linear; +} + +@mixin account-icon { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + background: url('../../../assets/icons/account-icon.svg') center/cover; +} + +@mixin cart-icon { + width: 20px; + height: 20px; + background: url('../../../assets/icons/bag-icon.svg') center/cover; +} diff --git a/src/styles/index.scss b/src/styles/index.scss new file mode 100644 index 0000000..3ffb96e --- /dev/null +++ b/src/styles/index.scss @@ -0,0 +1,30 @@ +@import './libs/_reset.scss'; +@import './base/_fonts.scss'; + +html, +body { + height: 100%; +} + +body { + font: $font-main; + background-color: $color-white; + color: $color-primary; + display: flex; + flex-direction: column; + overflow-x: hidden; + + &.hidden { + overflow: hidden; + } +} + +header, +footer { + flex-grow: 0; + flex-shrink: 0; +} + +main { + flex-grow: 1; +} diff --git a/src/styles/libs/_reset.scss b/src/styles/libs/_reset.scss new file mode 100644 index 0000000..f410622 --- /dev/null +++ b/src/styles/libs/_reset.scss @@ -0,0 +1,110 @@ +/* Reset and base styles */ +* { + padding: 0px; + margin: 0px; + border: none; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +/* Links */ + +a, +a:link, +a:visited { + text-decoration: none; +} + +a:hover { + text-decoration: none; +} + +/* Common */ + +aside, +nav, +footer, +header, +section, +main { + display: block; +} + +h1, +h2, +h3, +h4, +h5, +h6, +p { + font-size: inherit; + font-weight: inherit; +} + +ul, +ul li { + list-style: none; +} + +img { + vertical-align: top; +} + +img, +svg { + max-width: 100%; + height: auto; +} + +address { + font-style: normal; +} + +/* Form */ + +input, +textarea, +button, +select { + font-family: inherit; + font-size: inherit; + color: inherit; + background-color: transparent; +} + +input::-ms-clear { + display: none; +} + +button, +input[type='submit'] { + display: inline-block; + box-shadow: none; + background-color: transparent; + background: none; + cursor: pointer; +} + +input:focus, +input:active, +button:focus, +button:active { + outline: none; +} + +button::-moz-focus-inner { + padding: 0; + border: 0; +} + +label { + cursor: pointer; +} + +legend { + display: block; +} diff --git a/src/types/enums.ts b/src/types/enums.ts new file mode 100644 index 0000000..404bf07 --- /dev/null +++ b/src/types/enums.ts @@ -0,0 +1,10 @@ +export enum AccountInfoMode { + EDIT = 'edit', + SHOW = 'show', +} + +export enum AddressesMode { + EDIT = 'edit', + SHOW = 'show', + NEW = 'new', +} diff --git a/src/types/interfaces.ts b/src/types/interfaces.ts new file mode 100644 index 0000000..edc1c1d --- /dev/null +++ b/src/types/interfaces.ts @@ -0,0 +1,87 @@ +import { BaseAddress } from '@commercetools/platform-sdk'; +import InputField from '../components/input/input'; +import { AppRoutesPath } from '../router/types'; + +export interface IAddress { + key: string; + country: string; + streetName: string; + city: string; + postalCode: string; +} + +export interface ISignupData { + firstName: string; + lastName: string; + email: string; + password: string; + dateOfBirth: string; + addresses: IAddress[]; + shippingAddresses?: number[]; + billingAddresses?: number[]; + defaultShippingAddress?: number; + defaultBillingAddress?: number; +} + +export interface ISigninData { + email: string; + password: string; +} + +export interface IDetailsData { + firstName: string; + lastName: string; + email: string; + dateOfBirth: string; +} + +export interface IDetailsPasswordData { + currentPassword: string; + newPassword: string; +} + +export interface IBreadcrumbLink { + pageName: string; + pageHref: AppRoutesPath | string; +} + +export interface IBannerContent { + title: string; + text: string; +} + +export interface InputFilds { + [inputName: string]: InputField; +} + +export interface IAddressData { + address: BaseAddress; + billingAddressIds: string[] | undefined; + shippingAddressIds: string[] | undefined; + defaultBillingAddressId: string | undefined; + defaultShippingAddressId: string | undefined; +} + +export interface IAddressFormData { + type: string; + streetName: string; + city: string; + postalCode: string; + country: string; +} + +export interface IAboutUsMember { + name: string; + role: string; + imgClass: string; + about: string; + contributions: string[]; + link: string; +} + +export interface IPromoCodes { + title: string; + descr: string; + code: string; + expirationDate: string; +} diff --git a/src/types/types.ts b/src/types/types.ts new file mode 100644 index 0000000..db153dc --- /dev/null +++ b/src/types/types.ts @@ -0,0 +1,20 @@ +import { AppRoutesPath } from '../router/types'; + +interface IMenuLinks { + title: string; + href: AppRoutesPath | string; +} + +interface IMenuItems extends IMenuLinks { + innerItems?: IMenuLinks[]; +} + +type ListDataType = { [key: string]: string }; + +export { IMenuItems, ListDataType }; + +export interface ICategory { + label: string; + url: string; + slug: string; +} diff --git a/src/utils/change-url-event.ts b/src/utils/change-url-event.ts new file mode 100644 index 0000000..054a306 --- /dev/null +++ b/src/utils/change-url-event.ts @@ -0,0 +1,7 @@ +import { AppRoutesPath } from '../router/types'; + +export function changeUrlEvent(href: AppRoutesPath | string): void { + window.history.pushState({}, '', href); + const changeURL = new CustomEvent('changeURL', { bubbles: true }); + window.dispatchEvent(changeURL); +} diff --git a/src/utils/change-visible-addresses-btns.ts b/src/utils/change-visible-addresses-btns.ts new file mode 100644 index 0000000..25b5fd4 --- /dev/null +++ b/src/utils/change-visible-addresses-btns.ts @@ -0,0 +1,11 @@ +export default function changeVisibleAddressesBtns(addresses: HTMLDivElement[], isDisabled: boolean): void { + addresses.forEach((item: HTMLDivElement) => { + for (const itemChild of item.children) { + if (itemChild.className === 'address__actions') { + for (const btn of itemChild.children) { + (btn as HTMLButtonElement).disabled = isDisabled; + } + } + } + }); +} diff --git a/src/utils/createBasketDiscountTotal.ts b/src/utils/createBasketDiscountTotal.ts new file mode 100644 index 0000000..dee3ed6 --- /dev/null +++ b/src/utils/createBasketDiscountTotal.ts @@ -0,0 +1,81 @@ +import { Cart } from '@commercetools/platform-sdk'; +import BaseComponent from '../components/base-component'; +import formatPrice from './formatPrice'; + +export default function createBasketDiscountTotal(cart: Cart): HTMLDivElement[] { + const pricesWrapper: HTMLDivElement[] = []; + + let subTotal: number = 0; + + cart.lineItems.forEach((item) => { + if (item.price?.discounted) { + subTotal += item.price?.discounted.value.centAmount * item.quantity || 0; + } else { + subTotal += item.price.value.centAmount * item.quantity || 0; + } + }); + + function createSubTotal(): HTMLDivElement { + const subTotalBox: HTMLDivElement = new BaseComponent('div', ['basket-total__total']).getElement(); + const subTotalLabel: HTMLSpanElement = new BaseComponent( + 'span', + ['basket-total__total-label'], + 'Subtotal' + ).getElement(); + const subTotalPrice: HTMLSpanElement = new BaseComponent('span', ['basket-total__total-price']).getElement(); + + if (cart.totalPrice.centAmount) { + subTotalPrice.textContent = formatPrice(cart.totalPrice.currencyCode, subTotal, cart.totalPrice.fractionDigits); + } + + subTotalBox.append(subTotalLabel, subTotalPrice); + return subTotalBox; + } + + function createDiscountTotal(): HTMLDivElement { + const discountBox: HTMLDivElement = new BaseComponent('div', ['basket-total__total']).getElement(); + const discountLabel: HTMLSpanElement = new BaseComponent( + 'span', + ['basket-total__total-label'], + 'Discount' + ).getElement(); + const discountPrice: HTMLSpanElement = new BaseComponent('span', [ + 'basket-total__total-price', + 'discount', + ]).getElement(); + + if (cart.totalPrice.centAmount) { + discountPrice.textContent = + '- ' + + formatPrice( + cart.totalPrice.currencyCode, + subTotal - cart.totalPrice.centAmount, + cart.totalPrice.fractionDigits + ); + } + + discountBox.append(discountLabel, discountPrice); + return discountBox; + } + + function createTotal(): HTMLDivElement { + const totalBox: HTMLDivElement = new BaseComponent('div', ['basket-total__total']).getElement(); + const totalLabel: HTMLSpanElement = new BaseComponent('span', ['basket-total__total-label'], 'Total').getElement(); + const totalPrice: HTMLSpanElement = new BaseComponent('span', ['basket-total__total-price']).getElement(); + + if (cart.totalPrice.centAmount) { + totalPrice.textContent = formatPrice( + cart.totalPrice.currencyCode, + cart.totalPrice.centAmount, + cart.totalPrice.fractionDigits + ); + } + + totalBox.append(totalLabel, totalPrice); + return totalBox; + } + + pricesWrapper.push(createSubTotal(), createDiscountTotal(), createTotal()); + + return pricesWrapper; +} diff --git a/src/utils/createBasketTotal.ts b/src/utils/createBasketTotal.ts new file mode 100644 index 0000000..1832ee0 --- /dev/null +++ b/src/utils/createBasketTotal.ts @@ -0,0 +1,53 @@ +import { Cart } from '@commercetools/platform-sdk'; +import BaseComponent from '../components/base-component'; +import formatPrice from './formatPrice'; + +export default function createBasketTotal(cart: Cart): HTMLDivElement[] { + const pricesWrapper: HTMLDivElement[] = []; + + let subTotal: number = 0; + + cart.lineItems.forEach((item) => { + subTotal += item.price.value.centAmount * item.quantity || 0; + }); + + function createSubTotal(): HTMLDivElement { + const subTotalBox: HTMLDivElement = new BaseComponent('div', ['basket-total__total']).getElement(); + const subTotalLabel: HTMLSpanElement = new BaseComponent( + 'span', + ['basket-total__total-label'], + 'Subtotal' + ).getElement(); + const subTotalPrice = new BaseComponent('span', ['basket-total__total-price']).getElement(); + + subTotalPrice.textContent = formatPrice('USD', subTotal, 2); + + subTotalBox.append(subTotalLabel, subTotalPrice); + return subTotalBox; + } + + function createTotal(): HTMLDivElement { + const totalBox: HTMLDivElement = new BaseComponent('div', ['basket-total__total']).getElement(); + const totalLabel: HTMLSpanElement = new BaseComponent('span', ['basket-total__total-label'], 'Total').getElement(); + const totalPrice = new BaseComponent('span', ['basket-total__total-price']).getElement(); + + if (cart.totalPrice.centAmount) { + totalPrice.textContent = formatPrice( + cart.totalPrice.currencyCode, + cart.totalPrice.centAmount, + cart.totalPrice.fractionDigits + ); + } + + totalBox.append(totalLabel, totalPrice); + return totalBox; + } + + if (subTotal !== cart.totalPrice.centAmount) { + pricesWrapper.push(createSubTotal()); + } + + pricesWrapper.push(createTotal()); + + return pricesWrapper; +} diff --git a/src/utils/formatPrice.ts b/src/utils/formatPrice.ts new file mode 100644 index 0000000..0c77320 --- /dev/null +++ b/src/utils/formatPrice.ts @@ -0,0 +1,10 @@ +export default function formatPrice(currency: string, price: number, fractionDigits: number): string { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency, + minimumFractionDigits: fractionDigits, + }) + .format(price / 100) + .split(',') + .join(' '); +} diff --git a/src/utils/remove-popup.ts b/src/utils/remove-popup.ts new file mode 100644 index 0000000..6472be3 --- /dev/null +++ b/src/utils/remove-popup.ts @@ -0,0 +1,4 @@ +export function removePopupFromBody(className: string): void { + const el = document.querySelector(className); + el?.remove(); +} diff --git a/src/utils/router-middleware.ts b/src/utils/router-middleware.ts new file mode 100644 index 0000000..baa2f91 --- /dev/null +++ b/src/utils/router-middleware.ts @@ -0,0 +1,18 @@ +import { AppRoutesPath } from '../router/types'; +import userStore from '../store/user-store'; + +function authMiddleware(path: AppRoutesPath): boolean { + const { isAuth } = userStore.getState(); + const isAuthPath: boolean = path === AppRoutesPath.LOGIN || path === AppRoutesPath.SIGN_UP; + + return isAuth && isAuthPath; +} + +function accountMiddleware(path: AppRoutesPath): boolean { + const { isAuth } = userStore.getState(); + const isAuthPath: boolean = path === AppRoutesPath.ACCOUNT || path === AppRoutesPath.ACCOUNT_ADDRESSES; + + return !isAuth && isAuthPath; +} + +export { authMiddleware, accountMiddleware }; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..42faea6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "skipLibCheck": true, + "moduleResolution": "node" + } +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..82ba4e0 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,94 @@ +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const EslintPlugin = require('eslint-webpack-plugin'); +const Dotenv = require('dotenv-webpack'); + +const mode = process.env.NODE_ENV || 'development'; +const devMode = mode === 'development'; +const target = devMode ? 'web' : 'browserslist'; +const devtool = devMode ? 'source-map' : undefined; + +module.exports = { + mode, + target, + devtool, + entry: path.resolve(__dirname, 'src', 'index.ts'), + output: { + filename: '[name].[contenthash:8].js', + path: path.resolve(__dirname, 'dist'), + assetModuleFilename: 'assets/[name].[contenthash:8][ext]', + clean: true, + publicPath: '/', + }, + resolve: { + extensions: ['.ts', '.js'], + }, + module: { + rules: [ + { + test: /\.(c|sa|sc)ss$/i, + use: [ + devMode ? 'style-loader' : MiniCssExtractPlugin.loader, + 'css-loader', + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [require('postcss-preset-env')], + }, + }, + }, + { + loader: 'sass-loader', + options: { + additionalData: '@import "./src/styles/base/_variables.scss";', + }, + }, + ], + }, + { + test: /\.ts$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /\.woff2?$/i, + type: 'asset/resource', + generator: { + filename: 'assets/fonts/[name][ext]', + }, + }, + { + test: /\.(png|jpg|jpeg|gif|webp)$/i, + type: 'asset/resource', + }, + { + test: /\.svg$/i, + type: 'asset/resource', + generator: { + filename: 'assets/icons/[name].[contenthash:8][ext]', + }, + }, + ], + }, + plugins: [ + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, 'src', 'index.html'), + title: 'eCommerce-Application | this-is-this-team', + filename: 'index.html', + favicon: './src/assets/favicon.png', + }), + new MiniCssExtractPlugin({ + filename: 'style.[contenthash:8].css', + }), + new EslintPlugin({ extensions: ['ts', 'js'] }), + new Dotenv(), + ], + devServer: { + port: 8888, + open: true, + hot: true, + historyApiFallback: true, + }, +};