diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..dbd559c
--- /dev/null
+++ b/.env.development
@@ -0,0 +1 @@
+VITE_PETSTORE_URL=https://localhost
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..994acdd
--- /dev/null
+++ b/.env.production
@@ -0,0 +1 @@
+VITE_PETSTORE_URL=https://petstore.production
diff --git a/.env.test b/.env.test
new file mode 100644
index 0000000..9104501
--- /dev/null
+++ b/.env.test
@@ -0,0 +1 @@
+VITE_PETSTORE_URL=https://petstore.test
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 0000000..e5468b4
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,55 @@
+module.exports = {
+ env: {
+ browser: true,
+ es2020: true,
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:import/recommended',
+ 'plugin:import/typescript',
+ 'plugin:tailwindcss/recommended',
+ ],
+ overrides: [
+ {
+ env: {
+ node: true,
+ },
+ files: ['.eslintrc.{js,cjs}'],
+ parserOptions: {
+ sourceType: 'script',
+ },
+ },
+ ],
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ },
+ plugins: ['@typescript-eslint'],
+ rules: {
+ '@typescript-eslint/no-unused-vars': [
+ 'error',
+ {
+ argsIgnorePattern: '^_',
+ destructuredArrayIgnorePattern: '^_',
+ varsIgnorePattern: '^_',
+ },
+ ],
+ 'linebreak-style': ['error', 'unix'],
+ 'no-constant-condition': ['error', { checkLoops: false }],
+ quotes: ['error', 'single', { avoidEscape: true }],
+ semi: ['error', 'always'],
+ '@typescript-eslint/consistent-type-imports': 'error',
+ 'no-param-reassign': 'error',
+ 'no-var': 'error',
+ 'prefer-const': 'error',
+ },
+ settings: {
+ 'import/resolver': {
+ node: {
+ extensions: ['.cjs', '.d.ts', '.js', '.jsx', '.mjs', '.ts', '.tsx'],
+ },
+ },
+ },
+};
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..3e2bf3e
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,62 @@
+name: CI
+
+on:
+ push:
+ pull_request:
+ branches:
+ - master
+ schedule:
+ - cron: '0 0 * * *'
+
+jobs:
+ node16:
+ name: Node 16
+ runs-on: ubuntu-22.04
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4
+ - name: checkout node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '16'
+ - run: npm install -g pnpm@latest
+ - run: pnpm install
+ - run: pnpm run build
+ - run: TZ=Europe/Zurich pnpm test -- --coverage
+ node18:
+ name: Node 18
+ runs-on: ubuntu-22.04
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4
+ - name: checkout node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '18'
+ - run: npm install -g pnpm@latest
+ - run: pnpm install
+ - run: pnpm run build
+ - run: TZ=Europe/Zurich pnpm test -- --coverage
+ node20:
+ name: Node 20
+ runs-on: ubuntu-22.04
+ steps:
+ - name: checkout
+ uses: actions/checkout@v4
+ - name: checkout node
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ - run: npm install -g pnpm@latest
+ - run: pnpm install
+ - run: pnpm run build
+ - run: TZ=Europe/Zurich pnpm test -- --coverage
+ - name: coveralls.io
+ uses: coverallsapp/github-action@master
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ - name: sonarcloud.io
+ uses: sonarsource/sonarcloud-github-action@master
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..97bee46
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+coverage
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f71a527
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2024 Dominik Zogg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5698193
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+# vue-petstore
+
+[![CI](https://github.com/chubbyts/vue-petstore/actions/workflows/ci.yml/badge.svg)](https://github.com/chubbyts/vue-petstore/actions/workflows/ci.yml)
+[![Coverage Status](https://coveralls.io/repos/github/chubbyts/vue-petstore/badge.svg?branch=master)](https://coveralls.io/github/chubbyts/vue-petstore?branch=master)
+
+[![bugs](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=bugs)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![code_smells](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=code_smells)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![coverage](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=coverage)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![duplicated_lines_density](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![ncloc](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=ncloc)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![sqale_rating](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![alert_status](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=alert_status)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![reliability_rating](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![security_rating](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=security_rating)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![sqale_index](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=sqale_index)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+[![vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=chubbyts_vue-petstore&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=chubbyts_vue-petstore)
+
+## Description
+
+This is a vuejs frontend for the petstore skeleton.
+
+## Scripts
+
+### Compiles and hot-reloads for development
+```
+pnpm start
+```
+
+### Compiles and minifies for production
+```
+pnpm build
+```
+
+### Run your unit tests
+```
+pnpm test
+```
+
+## Copyright
+
+2024 Dominik Zogg
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..ca3961f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ Petstore
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b9ecc65
--- /dev/null
+++ b/package.json
@@ -0,0 +1,69 @@
+{
+ "name": "vuw-petstore",
+ "type": "module",
+ "version": "1.0.0",
+ "description": "A skeleton vuejs app for the petstore api.",
+ "keywords": [
+ "chubbyts",
+ "skleton",
+ "vue"
+ ],
+ "author": "Dominik Zogg",
+ "license": "MIT",
+ "repository": "chubbyts/vue-petstore",
+ "scripts": {
+ "build": "vue-tsc && vite build",
+ "cs-fix": "prettier --write src *.cjs *.js *.ts",
+ "cs": "prettier --check src *.cjs *.js *.ts",
+ "develop": "vite",
+ "lint-fix": "eslint src *.cjs *.js *.ts --fix",
+ "lint": "eslint src *.cjs *.js *.ts",
+ "start": "pnpm i && pnpm cs-fix && pnpm develop",
+ "test": "vitest"
+ },
+ "dependencies": {
+ "@chubbyts/chubbyts-throwable-to-error": "^1.2.1",
+ "@vitejs/plugin-vue-jsx": "^3.1.0",
+ "autoprefixer": "^10.4.18",
+ "cross-fetch": "^4.0.0",
+ "date-fns": "^3.3.1",
+ "postcss": "^8.4.35",
+ "qs": "^6.12.0",
+ "tailwindcss": "^3.4.1",
+ "vue": "^3.4.21",
+ "vue-router": "^4.3.0",
+ "zod": "^3.22.4"
+ },
+ "devDependencies": {
+ "@chubbyts/chubbyts-function-mock": "^1.4.1",
+ "@testing-library/jest-dom": "^6.4.2",
+ "@testing-library/user-event": "^14.5.2",
+ "@testing-library/vue": "^8.0.2",
+ "@types/node": "^20.11.25",
+ "@types/prettier": "^2.7.3",
+ "@types/qs": "^6.9.12",
+ "@typescript-eslint/eslint-plugin": "^7.1.1",
+ "@typescript-eslint/parser": "^7.1.1",
+ "@vitejs/plugin-vue": "^5.0.4",
+ "@vitest/coverage-v8": "^1.3.1",
+ "eslint": "^8.57.0",
+ "eslint-plugin-import": "^2.29.1",
+ "eslint-plugin-tailwindcss": "^3.14.3",
+ "eslint-plugin-vue": "^9.23.0",
+ "jsdom": "^24.0.0",
+ "prettier": "^2.8.8",
+ "typescript": "^5.4.2",
+ "vite": "^5.1.5",
+ "vitest": "^1.3.1",
+ "vue-tsc": "^1.8.27"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "prettier": {
+ "printWidth": 120,
+ "tabWidth": 2,
+ "singleQuote": true,
+ "trailingComma": "all"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..972600c
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,4447 @@
+lockfileVersion: '6.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+dependencies:
+ '@chubbyts/chubbyts-throwable-to-error':
+ specifier: ^1.2.1
+ version: 1.2.1
+ '@vitejs/plugin-vue-jsx':
+ specifier: ^3.1.0
+ version: 3.1.0(vite@5.1.6)(vue@3.4.21)
+ autoprefixer:
+ specifier: ^10.4.18
+ version: 10.4.18(postcss@8.4.35)
+ cross-fetch:
+ specifier: ^4.0.0
+ version: 4.0.0
+ date-fns:
+ specifier: ^3.3.1
+ version: 3.5.0
+ postcss:
+ specifier: ^8.4.35
+ version: 8.4.35
+ qs:
+ specifier: ^6.12.0
+ version: 6.12.0
+ tailwindcss:
+ specifier: ^3.4.1
+ version: 3.4.1
+ vue:
+ specifier: ^3.4.21
+ version: 3.4.21(typescript@5.4.2)
+ vue-router:
+ specifier: ^4.3.0
+ version: 4.3.0(vue@3.4.21)
+ zod:
+ specifier: ^3.22.4
+ version: 3.22.4
+
+devDependencies:
+ '@chubbyts/chubbyts-function-mock':
+ specifier: ^1.4.1
+ version: 1.4.1
+ '@testing-library/jest-dom':
+ specifier: ^6.4.2
+ version: 6.4.2(vitest@1.4.0)
+ '@testing-library/user-event':
+ specifier: ^14.5.2
+ version: 14.5.2(@testing-library/dom@9.3.4)
+ '@testing-library/vue':
+ specifier: ^8.0.2
+ version: 8.0.2(vue@3.4.21)
+ '@types/node':
+ specifier: ^20.11.25
+ version: 20.11.28
+ '@types/prettier':
+ specifier: ^2.7.3
+ version: 2.7.3
+ '@types/qs':
+ specifier: ^6.9.12
+ version: 6.9.12
+ '@typescript-eslint/eslint-plugin':
+ specifier: ^7.1.1
+ version: 7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2)
+ '@typescript-eslint/parser':
+ specifier: ^7.1.1
+ version: 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ '@vitejs/plugin-vue':
+ specifier: ^5.0.4
+ version: 5.0.4(vite@5.1.6)(vue@3.4.21)
+ '@vitest/coverage-v8':
+ specifier: ^1.3.1
+ version: 1.4.0(vitest@1.4.0)
+ eslint:
+ specifier: ^8.57.0
+ version: 8.57.0
+ eslint-plugin-import:
+ specifier: ^2.29.1
+ version: 2.29.1(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)
+ eslint-plugin-tailwindcss:
+ specifier: ^3.14.3
+ version: 3.15.1(tailwindcss@3.4.1)
+ eslint-plugin-vue:
+ specifier: ^9.23.0
+ version: 9.23.0(eslint@8.57.0)
+ jsdom:
+ specifier: ^24.0.0
+ version: 24.0.0
+ prettier:
+ specifier: ^2.8.8
+ version: 2.8.8
+ typescript:
+ specifier: ^5.4.2
+ version: 5.4.2
+ vite:
+ specifier: ^5.1.5
+ version: 5.1.6(@types/node@20.11.28)
+ vitest:
+ specifier: ^1.3.1
+ version: 1.4.0(@types/node@20.11.28)(jsdom@24.0.0)
+ vue-tsc:
+ specifier: ^1.8.27
+ version: 1.8.27(typescript@5.4.2)
+
+packages:
+
+ /@aashutoshrathi/word-wrap@1.2.6:
+ resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /@adobe/css-tools@4.3.3:
+ resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==}
+ dev: true
+
+ /@alloc/quick-lru@5.2.0:
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
+
+ /@ampproject/remapping@2.3.0:
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+
+ /@babel/code-frame@7.23.5:
+ resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/highlight': 7.23.4
+ chalk: 2.4.2
+
+ /@babel/compat-data@7.23.5:
+ resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
+ engines: {node: '>=6.9.0'}
+ dev: false
+
+ /@babel/core@7.24.0:
+ resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.23.5
+ '@babel/generator': 7.23.6
+ '@babel/helper-compilation-targets': 7.23.6
+ '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
+ '@babel/helpers': 7.24.0
+ '@babel/parser': 7.24.0
+ '@babel/template': 7.24.0
+ '@babel/traverse': 7.24.0
+ '@babel/types': 7.24.0
+ convert-source-map: 2.0.0
+ debug: 4.3.4
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /@babel/generator@7.23.6:
+ resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 2.5.2
+ dev: false
+
+ /@babel/helper-annotate-as-pure@7.22.5:
+ resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-compilation-targets@7.23.6:
+ resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/compat-data': 7.23.5
+ '@babel/helper-validator-option': 7.23.5
+ browserslist: 4.23.0
+ lru-cache: 5.1.1
+ semver: 6.3.1
+ dev: false
+
+ /@babel/helper-create-class-features-plugin@7.24.0(@babel/core@7.24.0):
+ resolution: {integrity: sha512-QAH+vfvts51BCsNZ2PhY6HAggnlS6omLLFTsIpeqZk/MmJ6cW7tgz5yRv0fMJThcr6FmbMrENh1RgrWPTYA76g==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/helper-annotate-as-pure': 7.22.5
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-function-name': 7.23.0
+ '@babel/helper-member-expression-to-functions': 7.23.0
+ '@babel/helper-optimise-call-expression': 7.22.5
+ '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0)
+ '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.6
+ semver: 6.3.1
+ dev: false
+
+ /@babel/helper-environment-visitor@7.22.20:
+ resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
+ engines: {node: '>=6.9.0'}
+ dev: false
+
+ /@babel/helper-function-name@7.23.0:
+ resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.24.0
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-hoist-variables@7.22.5:
+ resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-member-expression-to-functions@7.23.0:
+ resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-module-imports@7.22.15:
+ resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0):
+ resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-module-imports': 7.22.15
+ '@babel/helper-simple-access': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.6
+ '@babel/helper-validator-identifier': 7.22.20
+ dev: false
+
+ /@babel/helper-optimise-call-expression@7.22.5:
+ resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-plugin-utils@7.24.0:
+ resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==}
+ engines: {node: '>=6.9.0'}
+ dev: false
+
+ /@babel/helper-replace-supers@7.22.20(@babel/core@7.24.0):
+ resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-member-expression-to-functions': 7.23.0
+ '@babel/helper-optimise-call-expression': 7.22.5
+ dev: false
+
+ /@babel/helper-simple-access@7.22.5:
+ resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-skip-transparent-expression-wrappers@7.22.5:
+ resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-split-export-declaration@7.22.6:
+ resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/helper-string-parser@7.23.4:
+ resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
+ engines: {node: '>=6.9.0'}
+
+ /@babel/helper-validator-identifier@7.22.20:
+ resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
+ engines: {node: '>=6.9.0'}
+
+ /@babel/helper-validator-option@7.23.5:
+ resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
+ engines: {node: '>=6.9.0'}
+ dev: false
+
+ /@babel/helpers@7.24.0:
+ resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.24.0
+ '@babel/traverse': 7.24.0
+ '@babel/types': 7.24.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /@babel/highlight@7.23.4:
+ resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-validator-identifier': 7.22.20
+ chalk: 2.4.2
+ js-tokens: 4.0.0
+
+ /@babel/parser@7.24.0:
+ resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ '@babel/types': 7.24.0
+
+ /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0):
+ resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/helper-plugin-utils': 7.24.0
+ dev: false
+
+ /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0):
+ resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/helper-plugin-utils': 7.24.0
+ dev: false
+
+ /@babel/plugin-transform-typescript@7.23.6(@babel/core@7.24.0):
+ resolution: {integrity: sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/helper-annotate-as-pure': 7.22.5
+ '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.24.0)
+ '@babel/helper-plugin-utils': 7.24.0
+ '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0)
+ dev: false
+
+ /@babel/runtime@7.24.0:
+ resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.14.1
+ dev: true
+
+ /@babel/template@7.24.0:
+ resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.23.5
+ '@babel/parser': 7.24.0
+ '@babel/types': 7.24.0
+ dev: false
+
+ /@babel/traverse@7.24.0:
+ resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.23.5
+ '@babel/generator': 7.23.6
+ '@babel/helper-environment-visitor': 7.22.20
+ '@babel/helper-function-name': 7.23.0
+ '@babel/helper-hoist-variables': 7.22.5
+ '@babel/helper-split-export-declaration': 7.22.6
+ '@babel/parser': 7.24.0
+ '@babel/types': 7.24.0
+ debug: 4.3.4
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /@babel/types@7.24.0:
+ resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-string-parser': 7.23.4
+ '@babel/helper-validator-identifier': 7.22.20
+ to-fast-properties: 2.0.0
+
+ /@bcoe/v8-coverage@0.2.3:
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+ dev: true
+
+ /@chubbyts/chubbyts-function-mock@1.4.1:
+ resolution: {integrity: sha512-igr6L85ytNcp5LGUXDnluOuSe+uE06Qg6+8VFYAWkdN8+7yom6SEPk+JlumfhAWDeK7xRMTMJJ7oANbueuZipw==}
+ engines: {node: '>=16'}
+ dev: true
+
+ /@chubbyts/chubbyts-throwable-to-error@1.2.1:
+ resolution: {integrity: sha512-sqmz+niGqD2gujhK01//c3kQjhL3l0S+pBVWWGUORP1kgyjuevUBaMvP1pajv7gH3UwMoop5LyjakbRv5Berow==}
+ engines: {node: '>=16'}
+ dev: false
+
+ /@esbuild/aix-ppc64@0.19.12:
+ resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/android-arm64@0.19.12:
+ resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/android-arm@0.19.12:
+ resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/android-x64@0.19.12:
+ resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/darwin-arm64@0.19.12:
+ resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/darwin-x64@0.19.12:
+ resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/freebsd-arm64@0.19.12:
+ resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/freebsd-x64@0.19.12:
+ resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-arm64@0.19.12:
+ resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-arm@0.19.12:
+ resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-ia32@0.19.12:
+ resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-loong64@0.19.12:
+ resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-mips64el@0.19.12:
+ resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-ppc64@0.19.12:
+ resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-riscv64@0.19.12:
+ resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-s390x@0.19.12:
+ resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/linux-x64@0.19.12:
+ resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/netbsd-x64@0.19.12:
+ resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/openbsd-x64@0.19.12:
+ resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/sunos-x64@0.19.12:
+ resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/win32-arm64@0.19.12:
+ resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/win32-ia32@0.19.12:
+ resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ optional: true
+
+ /@esbuild/win32-x64@0.19.12:
+ resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ optional: true
+
+ /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ dependencies:
+ eslint: 8.57.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@eslint-community/regexpp@4.10.0:
+ resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+ dev: true
+
+ /@eslint/eslintrc@2.1.4:
+ resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.4
+ espree: 9.6.1
+ globals: 13.24.0
+ ignore: 5.3.1
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@eslint/js@8.57.0:
+ resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@humanwhocodes/config-array@0.11.14:
+ resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 2.0.2
+ debug: 4.3.4
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@humanwhocodes/module-importer@1.0.1:
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+ dev: true
+
+ /@humanwhocodes/object-schema@2.0.2:
+ resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
+ dev: true
+
+ /@isaacs/cliui@8.0.2:
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: /string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: /strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: /wrap-ansi@7.0.0
+
+ /@istanbuljs/schema@0.1.3:
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /@jest/schemas@29.6.3:
+ resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ dependencies:
+ '@sinclair/typebox': 0.27.8
+ dev: true
+
+ /@jridgewell/gen-mapping@0.3.5:
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ '@jridgewell/trace-mapping': 0.3.25
+
+ /@jridgewell/resolve-uri@3.1.2:
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ /@jridgewell/set-array@1.2.1:
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ /@jridgewell/sourcemap-codec@1.4.15:
+ resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+
+ /@jridgewell/trace-mapping@0.3.25:
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.4.15
+
+ /@nodelib/fs.scandir@2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ /@nodelib/fs.stat@2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+
+ /@nodelib/fs.walk@1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.17.1
+
+ /@one-ini/wasm@0.1.1:
+ resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
+ dev: true
+
+ /@pkgjs/parseargs@0.11.0:
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-android-arm-eabi@4.13.0:
+ resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==}
+ cpu: [arm]
+ os: [android]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-android-arm64@4.13.0:
+ resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-darwin-arm64@4.13.0:
+ resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-darwin-x64@4.13.0:
+ resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-linux-arm-gnueabihf@4.13.0:
+ resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-gnu@4.13.0:
+ resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-linux-arm64-musl@4.13.0:
+ resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-linux-riscv64-gnu@4.13.0:
+ resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==}
+ cpu: [riscv64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-gnu@4.13.0:
+ resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-musl@4.13.0:
+ resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-win32-arm64-msvc@4.13.0:
+ resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-win32-ia32-msvc@4.13.0:
+ resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ optional: true
+
+ /@rollup/rollup-win32-x64-msvc@4.13.0:
+ resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ optional: true
+
+ /@sinclair/typebox@0.27.8:
+ resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
+ dev: true
+
+ /@testing-library/dom@9.3.4:
+ resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@babel/code-frame': 7.23.5
+ '@babel/runtime': 7.24.0
+ '@types/aria-query': 5.0.4
+ aria-query: 5.1.3
+ chalk: 4.1.2
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ pretty-format: 27.5.1
+ dev: true
+
+ /@testing-library/jest-dom@6.4.2(vitest@1.4.0):
+ resolution: {integrity: sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==}
+ engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
+ peerDependencies:
+ '@jest/globals': '>= 28'
+ '@types/bun': latest
+ '@types/jest': '>= 28'
+ jest: '>= 28'
+ vitest: '>= 0.32'
+ peerDependenciesMeta:
+ '@jest/globals':
+ optional: true
+ '@types/bun':
+ optional: true
+ '@types/jest':
+ optional: true
+ jest:
+ optional: true
+ vitest:
+ optional: true
+ dependencies:
+ '@adobe/css-tools': 4.3.3
+ '@babel/runtime': 7.24.0
+ aria-query: 5.3.0
+ chalk: 3.0.0
+ css.escape: 1.5.1
+ dom-accessibility-api: 0.6.3
+ lodash: 4.17.21
+ redent: 3.0.0
+ vitest: 1.4.0(@types/node@20.11.28)(jsdom@24.0.0)
+ dev: true
+
+ /@testing-library/user-event@14.5.2(@testing-library/dom@9.3.4):
+ resolution: {integrity: sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==}
+ engines: {node: '>=12', npm: '>=6'}
+ peerDependencies:
+ '@testing-library/dom': '>=7.21.4'
+ dependencies:
+ '@testing-library/dom': 9.3.4
+ dev: true
+
+ /@testing-library/vue@8.0.2(vue@3.4.21):
+ resolution: {integrity: sha512-A8wWX+qQn0o0izpQWnGCpwQt8wAdpsVP8vPP2h5Q/jcGhZ5yKXz9PPUqhQv+45LTFaWlyRf8bArTVaB/KFFd5A==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ '@vue/compiler-sfc': '>= 3'
+ vue: '>= 3'
+ peerDependenciesMeta:
+ '@vue/compiler-sfc':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.24.0
+ '@testing-library/dom': 9.3.4
+ '@vue/test-utils': 2.4.5
+ vue: 3.4.21(typescript@5.4.2)
+ dev: true
+
+ /@types/aria-query@5.0.4:
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+ dev: true
+
+ /@types/estree@1.0.5:
+ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+
+ /@types/istanbul-lib-coverage@2.0.6:
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
+ dev: true
+
+ /@types/json-schema@7.0.15:
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+ dev: true
+
+ /@types/json5@0.0.29:
+ resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+ dev: true
+
+ /@types/node@20.11.28:
+ resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==}
+ dependencies:
+ undici-types: 5.26.5
+
+ /@types/prettier@2.7.3:
+ resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==}
+ dev: true
+
+ /@types/qs@6.9.12:
+ resolution: {integrity: sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==}
+ dev: true
+
+ /@types/semver@7.5.8:
+ resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
+ dev: true
+
+ /@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2):
+ resolution: {integrity: sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^7.0.0
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@eslint-community/regexpp': 4.10.0
+ '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ '@typescript-eslint/scope-manager': 7.2.0
+ '@typescript-eslint/type-utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ '@typescript-eslint/visitor-keys': 7.2.0
+ debug: 4.3.4
+ eslint: 8.57.0
+ graphemer: 1.4.0
+ ignore: 5.3.1
+ natural-compare: 1.4.0
+ semver: 7.6.0
+ ts-api-utils: 1.3.0(typescript@5.4.2)
+ typescript: 5.4.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.2):
+ resolution: {integrity: sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/scope-manager': 7.2.0
+ '@typescript-eslint/types': 7.2.0
+ '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2)
+ '@typescript-eslint/visitor-keys': 7.2.0
+ debug: 4.3.4
+ eslint: 8.57.0
+ typescript: 5.4.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/scope-manager@7.2.0:
+ resolution: {integrity: sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dependencies:
+ '@typescript-eslint/types': 7.2.0
+ '@typescript-eslint/visitor-keys': 7.2.0
+ dev: true
+
+ /@typescript-eslint/type-utils@7.2.0(eslint@8.57.0)(typescript@5.4.2):
+ resolution: {integrity: sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2)
+ '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ debug: 4.3.4
+ eslint: 8.57.0
+ ts-api-utils: 1.3.0(typescript@5.4.2)
+ typescript: 5.4.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/types@7.2.0:
+ resolution: {integrity: sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dev: true
+
+ /@typescript-eslint/typescript-estree@7.2.0(typescript@5.4.2):
+ resolution: {integrity: sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/types': 7.2.0
+ '@typescript-eslint/visitor-keys': 7.2.0
+ debug: 4.3.4
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.3
+ semver: 7.6.0
+ ts-api-utils: 1.3.0(typescript@5.4.2)
+ typescript: 5.4.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/utils@7.2.0(eslint@8.57.0)(typescript@5.4.2):
+ resolution: {integrity: sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^8.56.0
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@types/json-schema': 7.0.15
+ '@types/semver': 7.5.8
+ '@typescript-eslint/scope-manager': 7.2.0
+ '@typescript-eslint/types': 7.2.0
+ '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2)
+ eslint: 8.57.0
+ semver: 7.6.0
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+ dev: true
+
+ /@typescript-eslint/visitor-keys@7.2.0:
+ resolution: {integrity: sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ dependencies:
+ '@typescript-eslint/types': 7.2.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /@ungap/structured-clone@1.2.0:
+ resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+ dev: true
+
+ /@vitejs/plugin-vue-jsx@3.1.0(vite@5.1.6)(vue@3.4.21):
+ resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: ^4.0.0 || ^5.0.0
+ vue: ^3.0.0
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.24.0)
+ '@vue/babel-plugin-jsx': 1.2.1(@babel/core@7.24.0)
+ vite: 5.1.6(@types/node@20.11.28)
+ vue: 3.4.21(typescript@5.4.2)
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /@vitejs/plugin-vue@5.0.4(vite@5.1.6)(vue@3.4.21):
+ resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ peerDependencies:
+ vite: ^5.0.0
+ vue: ^3.2.25
+ dependencies:
+ vite: 5.1.6(@types/node@20.11.28)
+ vue: 3.4.21(typescript@5.4.2)
+ dev: true
+
+ /@vitest/coverage-v8@1.4.0(vitest@1.4.0):
+ resolution: {integrity: sha512-4hDGyH1SvKpgZnIByr9LhGgCEuF9DKM34IBLCC/fVfy24Z3+PZ+Ii9hsVBsHvY1umM1aGPEjceRkzxCfcQ10wg==}
+ peerDependencies:
+ vitest: 1.4.0
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@bcoe/v8-coverage': 0.2.3
+ debug: 4.3.4
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 5.0.4
+ istanbul-reports: 3.1.7
+ magic-string: 0.30.8
+ magicast: 0.3.3
+ picocolors: 1.0.0
+ std-env: 3.7.0
+ strip-literal: 2.0.0
+ test-exclude: 6.0.0
+ v8-to-istanbul: 9.2.0
+ vitest: 1.4.0(@types/node@20.11.28)(jsdom@24.0.0)
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@vitest/expect@1.4.0:
+ resolution: {integrity: sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==}
+ dependencies:
+ '@vitest/spy': 1.4.0
+ '@vitest/utils': 1.4.0
+ chai: 4.4.1
+ dev: true
+
+ /@vitest/runner@1.4.0:
+ resolution: {integrity: sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==}
+ dependencies:
+ '@vitest/utils': 1.4.0
+ p-limit: 5.0.0
+ pathe: 1.1.2
+ dev: true
+
+ /@vitest/snapshot@1.4.0:
+ resolution: {integrity: sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==}
+ dependencies:
+ magic-string: 0.30.8
+ pathe: 1.1.2
+ pretty-format: 29.7.0
+ dev: true
+
+ /@vitest/spy@1.4.0:
+ resolution: {integrity: sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==}
+ dependencies:
+ tinyspy: 2.2.1
+ dev: true
+
+ /@vitest/utils@1.4.0:
+ resolution: {integrity: sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==}
+ dependencies:
+ diff-sequences: 29.6.3
+ estree-walker: 3.0.3
+ loupe: 2.3.7
+ pretty-format: 29.7.0
+ dev: true
+
+ /@volar/language-core@1.11.1:
+ resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==}
+ dependencies:
+ '@volar/source-map': 1.11.1
+ dev: true
+
+ /@volar/source-map@1.11.1:
+ resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==}
+ dependencies:
+ muggle-string: 0.3.1
+ dev: true
+
+ /@volar/typescript@1.11.1:
+ resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==}
+ dependencies:
+ '@volar/language-core': 1.11.1
+ path-browserify: 1.0.1
+ dev: true
+
+ /@vue/babel-helper-vue-transform-on@1.2.1:
+ resolution: {integrity: sha512-jtEXim+pfyHWwvheYwUwSXm43KwQo8nhOBDyjrUITV6X2tB7lJm6n/+4sqR8137UVZZul5hBzWHdZ2uStYpyRQ==}
+ dev: false
+
+ /@vue/babel-plugin-jsx@1.2.1(@babel/core@7.24.0):
+ resolution: {integrity: sha512-Yy9qGktktXhB39QE99So/BO2Uwm/ZG+gpL9vMg51ijRRbINvgbuhyJEi4WYmGRMx/MSTfK0xjgZ3/MyY+iLCEg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.24.0
+ '@babel/helper-module-imports': 7.22.15
+ '@babel/helper-plugin-utils': 7.24.0
+ '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0)
+ '@babel/template': 7.24.0
+ '@babel/traverse': 7.24.0
+ '@babel/types': 7.24.0
+ '@vue/babel-helper-vue-transform-on': 1.2.1
+ '@vue/babel-plugin-resolve-type': 1.2.1(@babel/core@7.24.0)
+ camelcase: 6.3.0
+ html-tags: 3.3.1
+ svg-tags: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /@vue/babel-plugin-resolve-type@1.2.1(@babel/core@7.24.0):
+ resolution: {integrity: sha512-IOtnI7pHunUzHS/y+EG/yPABIAp0VN8QhQ0UCS09jeMVxgAnI9qdOzO85RXdQGxq+aWCdv8/+k3W0aYO6j/8fQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/code-frame': 7.23.5
+ '@babel/core': 7.24.0
+ '@babel/helper-module-imports': 7.22.15
+ '@babel/helper-plugin-utils': 7.24.0
+ '@babel/parser': 7.24.0
+ '@vue/compiler-sfc': 3.4.21
+ dev: false
+
+ /@vue/compiler-core@3.4.21:
+ resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==}
+ dependencies:
+ '@babel/parser': 7.24.0
+ '@vue/shared': 3.4.21
+ entities: 4.5.0
+ estree-walker: 2.0.2
+ source-map-js: 1.0.2
+
+ /@vue/compiler-dom@3.4.21:
+ resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
+ dependencies:
+ '@vue/compiler-core': 3.4.21
+ '@vue/shared': 3.4.21
+
+ /@vue/compiler-sfc@3.4.21:
+ resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
+ dependencies:
+ '@babel/parser': 7.24.0
+ '@vue/compiler-core': 3.4.21
+ '@vue/compiler-dom': 3.4.21
+ '@vue/compiler-ssr': 3.4.21
+ '@vue/shared': 3.4.21
+ estree-walker: 2.0.2
+ magic-string: 0.30.8
+ postcss: 8.4.35
+ source-map-js: 1.0.2
+
+ /@vue/compiler-ssr@3.4.21:
+ resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==}
+ dependencies:
+ '@vue/compiler-dom': 3.4.21
+ '@vue/shared': 3.4.21
+
+ /@vue/devtools-api@6.6.1:
+ resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==}
+ dev: false
+
+ /@vue/language-core@1.8.27(typescript@5.4.2):
+ resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@volar/language-core': 1.11.1
+ '@volar/source-map': 1.11.1
+ '@vue/compiler-dom': 3.4.21
+ '@vue/shared': 3.4.21
+ computeds: 0.0.1
+ minimatch: 9.0.3
+ muggle-string: 0.3.1
+ path-browserify: 1.0.1
+ typescript: 5.4.2
+ vue-template-compiler: 2.7.16
+ dev: true
+
+ /@vue/reactivity@3.4.21:
+ resolution: {integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==}
+ dependencies:
+ '@vue/shared': 3.4.21
+
+ /@vue/runtime-core@3.4.21:
+ resolution: {integrity: sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==}
+ dependencies:
+ '@vue/reactivity': 3.4.21
+ '@vue/shared': 3.4.21
+
+ /@vue/runtime-dom@3.4.21:
+ resolution: {integrity: sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==}
+ dependencies:
+ '@vue/runtime-core': 3.4.21
+ '@vue/shared': 3.4.21
+ csstype: 3.1.3
+
+ /@vue/server-renderer@3.4.21(vue@3.4.21):
+ resolution: {integrity: sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==}
+ peerDependencies:
+ vue: 3.4.21
+ dependencies:
+ '@vue/compiler-ssr': 3.4.21
+ '@vue/shared': 3.4.21
+ vue: 3.4.21(typescript@5.4.2)
+
+ /@vue/shared@3.4.21:
+ resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
+
+ /@vue/test-utils@2.4.5:
+ resolution: {integrity: sha512-oo2u7vktOyKUked36R93NB7mg2B+N7Plr8lxp2JBGwr18ch6EggFjixSCdIVVLkT6Qr0z359Xvnafc9dcKyDUg==}
+ dependencies:
+ js-beautify: 1.15.1
+ vue-component-type-helpers: 2.0.6
+ dev: true
+
+ /abbrev@2.0.0:
+ resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dev: true
+
+ /acorn-jsx@5.3.2(acorn@8.11.3):
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ acorn: 8.11.3
+ dev: true
+
+ /acorn-walk@8.3.2:
+ resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /acorn@8.11.3:
+ resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /agent-base@7.1.0:
+ resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==}
+ engines: {node: '>= 14'}
+ dependencies:
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+ dev: true
+
+ /ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ /ansi-regex@6.0.1:
+ resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+ engines: {node: '>=12'}
+
+ /ansi-styles@3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+ engines: {node: '>=4'}
+ dependencies:
+ color-convert: 1.9.3
+
+ /ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+ dependencies:
+ color-convert: 2.0.1
+
+ /ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /ansi-styles@6.2.1:
+ resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ engines: {node: '>=12'}
+
+ /any-promise@1.3.0:
+ resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
+
+ /anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
+ /arg@5.0.2:
+ resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+
+ /argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ dev: true
+
+ /aria-query@5.1.3:
+ resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
+ dependencies:
+ deep-equal: 2.2.3
+ dev: true
+
+ /aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+ dependencies:
+ dequal: 2.0.3
+ dev: true
+
+ /array-buffer-byte-length@1.0.1:
+ resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ is-array-buffer: 3.0.4
+ dev: true
+
+ /array-includes@3.1.7:
+ resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ get-intrinsic: 1.2.4
+ is-string: 1.0.7
+ dev: true
+
+ /array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /array.prototype.filter@1.0.3:
+ resolution: {integrity: sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-array-method-boxes-properly: 1.0.0
+ is-string: 1.0.7
+ dev: true
+
+ /array.prototype.findlastindex@1.2.4:
+ resolution: {integrity: sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-errors: 1.3.0
+ es-shim-unscopables: 1.0.2
+ dev: true
+
+ /array.prototype.flat@1.3.2:
+ resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-shim-unscopables: 1.0.2
+ dev: true
+
+ /array.prototype.flatmap@1.3.2:
+ resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-shim-unscopables: 1.0.2
+ dev: true
+
+ /arraybuffer.prototype.slice@1.0.3:
+ resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ is-array-buffer: 3.0.4
+ is-shared-array-buffer: 1.0.3
+ dev: true
+
+ /assertion-error@1.1.0:
+ resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+ dev: true
+
+ /asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ dev: true
+
+ /autoprefixer@10.4.18(postcss@8.4.35):
+ resolution: {integrity: sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==}
+ engines: {node: ^10 || ^12 || >=14}
+ hasBin: true
+ peerDependencies:
+ postcss: ^8.1.0
+ dependencies:
+ browserslist: 4.23.0
+ caniuse-lite: 1.0.30001597
+ fraction.js: 4.3.7
+ normalize-range: 0.1.2
+ picocolors: 1.0.0
+ postcss: 8.4.35
+ postcss-value-parser: 4.2.0
+ dev: false
+
+ /available-typed-arrays@1.0.7:
+ resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ possible-typed-array-names: 1.0.0
+ dev: true
+
+ /balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ /binary-extensions@2.3.0:
+ resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+ engines: {node: '>=8'}
+
+ /boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+ dev: true
+
+ /brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+ dev: true
+
+ /brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+ dependencies:
+ balanced-match: 1.0.2
+
+ /braces@3.0.2:
+ resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+ engines: {node: '>=8'}
+ dependencies:
+ fill-range: 7.0.1
+
+ /browserslist@4.23.0:
+ resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+ dependencies:
+ caniuse-lite: 1.0.30001597
+ electron-to-chromium: 1.4.708
+ node-releases: 2.0.14
+ update-browserslist-db: 1.0.13(browserslist@4.23.0)
+ dev: false
+
+ /cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /call-bind@1.0.7:
+ resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ set-function-length: 1.2.2
+
+ /callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /camelcase-css@2.0.1:
+ resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
+ engines: {node: '>= 6'}
+
+ /camelcase@6.3.0:
+ resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+ engines: {node: '>=10'}
+ dev: false
+
+ /caniuse-lite@1.0.30001597:
+ resolution: {integrity: sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==}
+ dev: false
+
+ /chai@4.4.1:
+ resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==}
+ engines: {node: '>=4'}
+ dependencies:
+ assertion-error: 1.1.0
+ check-error: 1.0.3
+ deep-eql: 4.1.3
+ get-func-name: 2.0.2
+ loupe: 2.3.7
+ pathval: 1.1.1
+ type-detect: 4.0.8
+ dev: true
+
+ /chalk@2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ ansi-styles: 3.2.1
+ escape-string-regexp: 1.0.5
+ supports-color: 5.5.0
+
+ /chalk@3.0.0:
+ resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+ dev: true
+
+ /chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+ dev: true
+
+ /check-error@1.0.3:
+ resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
+ dependencies:
+ get-func-name: 2.0.2
+ dev: true
+
+ /chokidar@3.6.0:
+ resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.3
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ /color-convert@1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ dependencies:
+ color-name: 1.1.3
+
+ /color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+ dependencies:
+ color-name: 1.1.4
+
+ /color-name@1.1.3:
+ resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
+
+ /color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ /combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ delayed-stream: 1.0.0
+ dev: true
+
+ /commander@10.0.1:
+ resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /commander@4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+
+ /computeds@0.0.1:
+ resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==}
+ dev: true
+
+ /concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ dev: true
+
+ /config-chain@1.1.13:
+ resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+ dependencies:
+ ini: 1.3.8
+ proto-list: 1.2.4
+ dev: true
+
+ /convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ /cross-fetch@4.0.0:
+ resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
+ dependencies:
+ node-fetch: 2.7.0
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
+ /cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ /css.escape@1.5.1:
+ resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+ dev: true
+
+ /cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ /cssstyle@4.0.1:
+ resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ rrweb-cssom: 0.6.0
+ dev: true
+
+ /csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ /data-urls@5.0.0:
+ resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+ engines: {node: '>=18'}
+ dependencies:
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.0.0
+ dev: true
+
+ /date-fns@3.5.0:
+ resolution: {integrity: sha512-a+DwyXn7NOfdJireCzAA0B9p7jIXEu/Q9JKCyMYvH6+0vPUNbQceA0neXrdfJ/xzl3mhOh5vibQQ3936Tssm6A==}
+ dev: false
+
+ /de-indent@1.0.2:
+ resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
+ dev: true
+
+ /debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.3
+ dev: true
+
+ /debug@4.3.4:
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+
+ /decimal.js@10.4.3:
+ resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
+ dev: true
+
+ /deep-eql@4.1.3:
+ resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
+ engines: {node: '>=6'}
+ dependencies:
+ type-detect: 4.0.8
+ dev: true
+
+ /deep-equal@2.2.3:
+ resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ call-bind: 1.0.7
+ es-get-iterator: 1.1.3
+ get-intrinsic: 1.2.4
+ is-arguments: 1.1.1
+ is-array-buffer: 3.0.4
+ is-date-object: 1.0.5
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.3
+ isarray: 2.0.5
+ object-is: 1.1.6
+ object-keys: 1.1.1
+ object.assign: 4.1.5
+ regexp.prototype.flags: 1.5.2
+ side-channel: 1.0.6
+ which-boxed-primitive: 1.0.2
+ which-collection: 1.0.2
+ which-typed-array: 1.1.15
+ dev: true
+
+ /deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ dev: true
+
+ /define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ gopd: 1.0.1
+
+ /define-properties@1.2.1:
+ resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-data-property: 1.1.4
+ has-property-descriptors: 1.0.2
+ object-keys: 1.1.1
+ dev: true
+
+ /delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /didyoumean@1.2.2:
+ resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
+
+ /diff-sequences@29.6.3:
+ resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ dev: true
+
+ /dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+ dependencies:
+ path-type: 4.0.0
+ dev: true
+
+ /dlv@1.1.3:
+ resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+
+ /doctrine@2.1.0:
+ resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /doctrine@3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+ dev: true
+
+ /dom-accessibility-api@0.6.3:
+ resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+ dev: true
+
+ /eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+ /editorconfig@1.0.4:
+ resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==}
+ engines: {node: '>=14'}
+ hasBin: true
+ dependencies:
+ '@one-ini/wasm': 0.1.1
+ commander: 10.0.1
+ minimatch: 9.0.1
+ semver: 7.6.0
+ dev: true
+
+ /electron-to-chromium@1.4.708:
+ resolution: {integrity: sha512-iWgEEvREL4GTXXHKohhh33+6Y8XkPI5eHihDmm8zUk5Zo7HICEW+wI/j5kJ2tbuNUCXJ/sNXa03ajW635DiJXA==}
+ dev: false
+
+ /emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ /emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ /entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ /es-abstract@1.22.5:
+ resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ arraybuffer.prototype.slice: 1.0.3
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ es-set-tostringtag: 2.0.3
+ es-to-primitive: 1.2.1
+ function.prototype.name: 1.1.6
+ get-intrinsic: 1.2.4
+ get-symbol-description: 1.0.2
+ globalthis: 1.0.3
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+ has-proto: 1.0.3
+ has-symbols: 1.0.3
+ hasown: 2.0.2
+ internal-slot: 1.0.7
+ is-array-buffer: 3.0.4
+ is-callable: 1.2.7
+ is-negative-zero: 2.0.3
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.3
+ is-string: 1.0.7
+ is-typed-array: 1.1.13
+ is-weakref: 1.0.2
+ object-inspect: 1.13.1
+ object-keys: 1.1.1
+ object.assign: 4.1.5
+ regexp.prototype.flags: 1.5.2
+ safe-array-concat: 1.1.2
+ safe-regex-test: 1.0.3
+ string.prototype.trim: 1.2.8
+ string.prototype.trimend: 1.0.7
+ string.prototype.trimstart: 1.0.7
+ typed-array-buffer: 1.0.2
+ typed-array-byte-length: 1.0.1
+ typed-array-byte-offset: 1.0.2
+ typed-array-length: 1.0.5
+ unbox-primitive: 1.0.2
+ which-typed-array: 1.1.15
+ dev: true
+
+ /es-array-method-boxes-properly@1.0.0:
+ resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==}
+ dev: true
+
+ /es-define-property@1.0.0:
+ resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.4
+
+ /es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ /es-get-iterator@1.1.3:
+ resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==}
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ has-symbols: 1.0.3
+ is-arguments: 1.1.1
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-string: 1.0.7
+ isarray: 2.0.5
+ stop-iteration-iterator: 1.0.0
+ dev: true
+
+ /es-set-tostringtag@2.0.3:
+ resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.2.4
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+ dev: true
+
+ /es-shim-unscopables@1.0.2:
+ resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
+ dependencies:
+ hasown: 2.0.2
+ dev: true
+
+ /es-to-primitive@1.2.1:
+ resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ is-callable: 1.2.7
+ is-date-object: 1.0.5
+ is-symbol: 1.0.4
+ dev: true
+
+ /esbuild@0.19.12:
+ resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
+ engines: {node: '>=12'}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.19.12
+ '@esbuild/android-arm': 0.19.12
+ '@esbuild/android-arm64': 0.19.12
+ '@esbuild/android-x64': 0.19.12
+ '@esbuild/darwin-arm64': 0.19.12
+ '@esbuild/darwin-x64': 0.19.12
+ '@esbuild/freebsd-arm64': 0.19.12
+ '@esbuild/freebsd-x64': 0.19.12
+ '@esbuild/linux-arm': 0.19.12
+ '@esbuild/linux-arm64': 0.19.12
+ '@esbuild/linux-ia32': 0.19.12
+ '@esbuild/linux-loong64': 0.19.12
+ '@esbuild/linux-mips64el': 0.19.12
+ '@esbuild/linux-ppc64': 0.19.12
+ '@esbuild/linux-riscv64': 0.19.12
+ '@esbuild/linux-s390x': 0.19.12
+ '@esbuild/linux-x64': 0.19.12
+ '@esbuild/netbsd-x64': 0.19.12
+ '@esbuild/openbsd-x64': 0.19.12
+ '@esbuild/sunos-x64': 0.19.12
+ '@esbuild/win32-arm64': 0.19.12
+ '@esbuild/win32-ia32': 0.19.12
+ '@esbuild/win32-x64': 0.19.12
+
+ /escalade@3.1.2:
+ resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /escape-string-regexp@1.0.5:
+ resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+ engines: {node: '>=0.8.0'}
+
+ /escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /eslint-import-resolver-node@0.3.9:
+ resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+ dependencies:
+ debug: 3.2.7
+ is-core-module: 2.13.1
+ resolve: 1.22.8
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
+ resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: '*'
+ eslint-import-resolver-node: '*'
+ eslint-import-resolver-typescript: '*'
+ eslint-import-resolver-webpack: '*'
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+ eslint:
+ optional: true
+ eslint-import-resolver-node:
+ optional: true
+ eslint-import-resolver-typescript:
+ optional: true
+ eslint-import-resolver-webpack:
+ optional: true
+ dependencies:
+ '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ debug: 3.2.7
+ eslint: 8.57.0
+ eslint-import-resolver-node: 0.3.9
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.2.0)(eslint@8.57.0):
+ resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@typescript-eslint/parser': '*'
+ eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+ peerDependenciesMeta:
+ '@typescript-eslint/parser':
+ optional: true
+ dependencies:
+ '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.2)
+ array-includes: 3.1.7
+ array.prototype.findlastindex: 1.2.4
+ array.prototype.flat: 1.3.2
+ array.prototype.flatmap: 1.3.2
+ debug: 3.2.7
+ doctrine: 2.1.0
+ eslint: 8.57.0
+ eslint-import-resolver-node: 0.3.9
+ eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
+ hasown: 2.0.2
+ is-core-module: 2.13.1
+ is-glob: 4.0.3
+ minimatch: 3.1.2
+ object.fromentries: 2.0.7
+ object.groupby: 1.0.2
+ object.values: 1.1.7
+ semver: 6.3.1
+ tsconfig-paths: 3.15.0
+ transitivePeerDependencies:
+ - eslint-import-resolver-typescript
+ - eslint-import-resolver-webpack
+ - supports-color
+ dev: true
+
+ /eslint-plugin-tailwindcss@3.15.1(tailwindcss@3.4.1):
+ resolution: {integrity: sha512-4RXRMIaMG07C2TBEW1k0VM4+dDazz1kxcZhkK4zirvmHGZTA4jnlSO2kq5mamuSPi+Wo17dh2SlC8IyFBuCd7Q==}
+ engines: {node: '>=12.13.0'}
+ peerDependencies:
+ tailwindcss: ^3.4.0
+ dependencies:
+ fast-glob: 3.3.2
+ postcss: 8.4.35
+ tailwindcss: 3.4.1
+ dev: true
+
+ /eslint-plugin-vue@9.23.0(eslint@8.57.0):
+ resolution: {integrity: sha512-Bqd/b7hGYGrlV+wP/g77tjyFmp81lh5TMw0be9093X02SyelxRRfCI6/IsGq/J7Um0YwB9s0Ry0wlFyjPdmtUw==}
+ engines: {node: ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ eslint: 8.57.0
+ natural-compare: 1.4.0
+ nth-check: 2.1.1
+ postcss-selector-parser: 6.0.16
+ semver: 7.6.0
+ vue-eslint-parser: 9.4.2(eslint@8.57.0)
+ xml-name-validator: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /eslint-scope@7.2.2:
+ resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
+ /eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /eslint@8.57.0:
+ resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+ '@eslint-community/regexpp': 4.10.0
+ '@eslint/eslintrc': 2.1.4
+ '@eslint/js': 8.57.0
+ '@humanwhocodes/config-array': 0.11.14
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ '@ungap/structured-clone': 1.2.0
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.4
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.5.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ globals: 13.24.0
+ graphemer: 1.4.0
+ ignore: 5.3.1
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ 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
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /espree@9.6.1:
+ resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.11.3
+ acorn-jsx: 5.3.2(acorn@8.11.3)
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
+ /esquery@1.5.0:
+ resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+ /estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+ dependencies:
+ '@types/estree': 1.0.5
+ dev: true
+
+ /esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /execa@8.0.1:
+ resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
+ engines: {node: '>=16.17'}
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 8.0.1
+ human-signals: 5.0.0
+ is-stream: 3.0.0
+ merge-stream: 2.0.0
+ npm-run-path: 5.3.0
+ onetime: 6.0.0
+ signal-exit: 4.1.0
+ strip-final-newline: 3.0.0
+ dev: true
+
+ /fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+ dev: true
+
+ /fast-glob@3.3.2:
+ resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.5
+
+ /fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+ dev: true
+
+ /fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+ dev: true
+
+ /fastq@1.17.1:
+ resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+ dependencies:
+ reusify: 1.0.4
+
+ /file-entry-cache@6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flat-cache: 3.2.0
+ dev: true
+
+ /fill-range@7.0.1:
+ resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ to-regex-range: 5.0.1
+
+ /find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /flat-cache@3.2.0:
+ resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flatted: 3.3.1
+ keyv: 4.5.4
+ rimraf: 3.0.2
+ dev: true
+
+ /flatted@3.3.1:
+ resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
+ dev: true
+
+ /for-each@0.3.3:
+ resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+ dependencies:
+ is-callable: 1.2.7
+ dev: true
+
+ /foreground-child@3.1.1:
+ resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+ engines: {node: '>=14'}
+ dependencies:
+ cross-spawn: 7.0.3
+ signal-exit: 4.1.0
+
+ /form-data@4.0.0:
+ resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+ engines: {node: '>= 6'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+ dev: true
+
+ /fraction.js@4.3.7:
+ resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+ dev: false
+
+ /fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ dev: true
+
+ /fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ optional: true
+
+ /function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ /function.prototype.name@1.1.6:
+ resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ functions-have-names: 1.2.3
+ dev: true
+
+ /functions-have-names@1.2.3:
+ resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ dev: true
+
+ /gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+ dev: false
+
+ /get-func-name@2.0.2:
+ resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
+ dev: true
+
+ /get-intrinsic@1.2.4:
+ resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ has-proto: 1.0.3
+ has-symbols: 1.0.3
+ hasown: 2.0.2
+
+ /get-stream@8.0.1:
+ resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
+ engines: {node: '>=16'}
+ dev: true
+
+ /get-symbol-description@1.0.2:
+ resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ dev: true
+
+ /glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+ dependencies:
+ is-glob: 4.0.3
+
+ /glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+
+ /glob@10.3.10:
+ resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ foreground-child: 3.1.1
+ jackspeak: 2.3.6
+ minimatch: 9.0.3
+ minipass: 7.0.4
+ path-scurry: 1.10.1
+
+ /glob@7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: true
+
+ /globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+ dev: false
+
+ /globals@13.24.0:
+ resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.20.2
+ dev: true
+
+ /globalthis@1.0.3:
+ resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-properties: 1.2.1
+ dev: true
+
+ /globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.2
+ ignore: 5.3.1
+ merge2: 1.4.1
+ slash: 3.0.0
+ dev: true
+
+ /gopd@1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+ dependencies:
+ get-intrinsic: 1.2.4
+
+ /graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+ dev: true
+
+ /has-bigints@1.0.2:
+ resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
+ dev: true
+
+ /has-flag@3.0.0:
+ resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
+ engines: {node: '>=4'}
+
+ /has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+ dependencies:
+ es-define-property: 1.0.0
+
+ /has-proto@1.0.3:
+ resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+ engines: {node: '>= 0.4'}
+
+ /has-symbols@1.0.3:
+ resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+ engines: {node: '>= 0.4'}
+
+ /has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.3
+ dev: true
+
+ /hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ function-bind: 1.1.2
+
+ /he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+ dev: true
+
+ /html-encoding-sniffer@4.0.0:
+ resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ whatwg-encoding: 3.1.1
+ dev: true
+
+ /html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+ dev: true
+
+ /html-tags@3.3.1:
+ resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
+ engines: {node: '>=8'}
+ dev: false
+
+ /http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+ dependencies:
+ agent-base: 7.1.0
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /https-proxy-agent@7.0.4:
+ resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==}
+ engines: {node: '>= 14'}
+ dependencies:
+ agent-base: 7.1.0
+ debug: 4.3.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /human-signals@5.0.0:
+ resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
+ engines: {node: '>=16.17.0'}
+ dev: true
+
+ /iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: true
+
+ /ignore@5.3.1:
+ resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+ dev: true
+
+ /imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+ dev: true
+
+ /indent-string@4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+ dev: true
+
+ /inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ dev: true
+
+ /ini@1.3.8:
+ resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+ dev: true
+
+ /internal-slot@1.0.7:
+ resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ es-errors: 1.3.0
+ hasown: 2.0.2
+ side-channel: 1.0.6
+ dev: true
+
+ /is-arguments@1.1.1:
+ resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
+ dev: true
+
+ /is-array-buffer@3.0.4:
+ resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ dev: true
+
+ /is-bigint@1.0.4:
+ resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+ dependencies:
+ has-bigints: 1.0.2
+ dev: true
+
+ /is-binary-path@2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+ dependencies:
+ binary-extensions: 2.3.0
+
+ /is-boolean-object@1.1.2:
+ resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
+ dev: true
+
+ /is-callable@1.2.7:
+ resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-core-module@2.13.1:
+ resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
+ dependencies:
+ hasown: 2.0.2
+
+ /is-date-object@1.0.5:
+ resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.2
+ dev: true
+
+ /is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ /is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ /is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+
+ /is-map@2.0.3:
+ resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-negative-zero@2.0.3:
+ resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-number-object@1.0.7:
+ resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.2
+ dev: true
+
+ /is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ /is-path-inside@3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+ dev: true
+
+ /is-regex@1.1.4:
+ resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
+ dev: true
+
+ /is-set@2.0.3:
+ resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-shared-array-buffer@1.0.3:
+ resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ dev: true
+
+ /is-stream@3.0.0:
+ resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /is-string@1.0.7:
+ resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.2
+ dev: true
+
+ /is-symbol@1.0.4:
+ resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.3
+ dev: true
+
+ /is-typed-array@1.1.13:
+ resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ which-typed-array: 1.1.15
+ dev: true
+
+ /is-weakmap@2.0.2:
+ resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-weakref@1.0.2:
+ resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+ dependencies:
+ call-bind: 1.0.7
+ dev: true
+
+ /is-weakset@2.0.3:
+ resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ dev: true
+
+ /isarray@2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+ dev: true
+
+ /isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ /istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+ dev: true
+
+ /istanbul-lib-source-maps@5.0.4:
+ resolution: {integrity: sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ debug: 4.3.4
+ istanbul-lib-coverage: 3.2.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /istanbul-reports@3.1.7:
+ resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
+ engines: {node: '>=8'}
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+ dev: true
+
+ /jackspeak@2.3.6:
+ resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
+ /jiti@1.21.0:
+ resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
+ hasBin: true
+
+ /js-beautify@1.15.1:
+ resolution: {integrity: sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==}
+ engines: {node: '>=14'}
+ hasBin: true
+ dependencies:
+ config-chain: 1.1.13
+ editorconfig: 1.0.4
+ glob: 10.3.10
+ js-cookie: 3.0.5
+ nopt: 7.2.0
+ dev: true
+
+ /js-cookie@3.0.5:
+ resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
+ engines: {node: '>=14'}
+ dev: true
+
+ /js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ /js-tokens@8.0.3:
+ resolution: {integrity: sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==}
+ dev: true
+
+ /js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ dev: true
+
+ /jsdom@24.0.0:
+ resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ canvas: ^2.11.2
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+ dependencies:
+ cssstyle: 4.0.1
+ data-urls: 5.0.0
+ decimal.js: 10.4.3
+ form-data: 4.0.0
+ html-encoding-sniffer: 4.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.4
+ is-potential-custom-element-name: 1.0.1
+ nwsapi: 2.2.7
+ parse5: 7.1.2
+ rrweb-cssom: 0.6.0
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 4.1.3
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 7.0.0
+ whatwg-encoding: 3.1.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.0.0
+ ws: 8.16.0
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+ dev: true
+
+ /jsesc@2.5.2:
+ resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: false
+
+ /json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ dev: true
+
+ /json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ dev: true
+
+ /json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+ dev: true
+
+ /json5@1.0.2:
+ resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.8
+ dev: true
+
+ /json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+ dev: false
+
+ /jsonc-parser@3.2.1:
+ resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==}
+ dev: true
+
+ /keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ dependencies:
+ json-buffer: 3.0.1
+ dev: true
+
+ /levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /lilconfig@2.1.0:
+ resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+ engines: {node: '>=10'}
+
+ /lilconfig@3.1.1:
+ resolution: {integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==}
+ engines: {node: '>=14'}
+
+ /lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ /local-pkg@0.5.0:
+ resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
+ engines: {node: '>=14'}
+ dependencies:
+ mlly: 1.6.1
+ pkg-types: 1.0.3
+ dev: true
+
+ /locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-locate: 5.0.0
+ dev: true
+
+ /lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ dev: true
+
+ /lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ dev: true
+
+ /loupe@2.3.7:
+ resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
+ dependencies:
+ get-func-name: 2.0.2
+ dev: true
+
+ /lru-cache@10.2.0:
+ resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
+ engines: {node: 14 || >=16.14}
+
+ /lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ dependencies:
+ yallist: 3.1.1
+ dev: false
+
+ /lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+ dependencies:
+ yallist: 4.0.0
+ dev: true
+
+ /lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+ dev: true
+
+ /magic-string@0.30.8:
+ resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.4.15
+
+ /magicast@0.3.3:
+ resolution: {integrity: sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==}
+ dependencies:
+ '@babel/parser': 7.24.0
+ '@babel/types': 7.24.0
+ source-map-js: 1.0.2
+ dev: true
+
+ /make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+ dependencies:
+ semver: 7.6.0
+ dev: true
+
+ /merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+ dev: true
+
+ /merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ /micromatch@4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+
+ /mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.52.0
+ dev: true
+
+ /mimic-fn@4.0.0:
+ resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /min-indent@1.0.1:
+ resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ dependencies:
+ brace-expansion: 1.1.11
+ dev: true
+
+ /minimatch@9.0.1:
+ resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+ dev: true
+
+ /minimatch@9.0.3:
+ resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ brace-expansion: 2.0.1
+
+ /minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+ dev: true
+
+ /minipass@7.0.4:
+ resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ /mlly@1.6.1:
+ resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==}
+ dependencies:
+ acorn: 8.11.3
+ pathe: 1.1.2
+ pkg-types: 1.0.3
+ ufo: 1.5.1
+ dev: true
+
+ /ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+ /ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ dev: true
+
+ /muggle-string@0.3.1:
+ resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
+ dev: true
+
+ /mz@2.7.0:
+ resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
+ dependencies:
+ any-promise: 1.3.0
+ object-assign: 4.1.1
+ thenify-all: 1.6.0
+
+ /nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ /natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ dev: true
+
+ /node-fetch@2.7.0:
+ resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ dependencies:
+ whatwg-url: 5.0.0
+ dev: false
+
+ /node-releases@2.0.14:
+ resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
+ dev: false
+
+ /nopt@7.2.0:
+ resolution: {integrity: sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ hasBin: true
+ dependencies:
+ abbrev: 2.0.0
+ dev: true
+
+ /normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ /normalize-range@0.1.2:
+ resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ path-key: 4.0.0
+ dev: true
+
+ /nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+ dependencies:
+ boolbase: 1.0.0
+ dev: true
+
+ /nwsapi@2.2.7:
+ resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==}
+ dev: true
+
+ /object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ /object-hash@3.0.0:
+ resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
+ engines: {node: '>= 6'}
+
+ /object-inspect@1.13.1:
+ resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+
+ /object-is@1.1.6:
+ resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ dev: true
+
+ /object-keys@1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /object.assign@4.1.5:
+ resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ has-symbols: 1.0.3
+ object-keys: 1.1.1
+ dev: true
+
+ /object.fromentries@2.0.7:
+ resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ dev: true
+
+ /object.groupby@1.0.2:
+ resolution: {integrity: sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==}
+ dependencies:
+ array.prototype.filter: 1.0.3
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-errors: 1.3.0
+ dev: true
+
+ /object.values@1.1.7:
+ resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ dev: true
+
+ /once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ dependencies:
+ wrappy: 1.0.2
+ dev: true
+
+ /onetime@6.0.0:
+ resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ mimic-fn: 4.0.0
+ dev: true
+
+ /optionator@0.9.3:
+ resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ '@aashutoshrathi/word-wrap': 1.2.6
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ yocto-queue: 0.1.0
+ dev: true
+
+ /p-limit@5.0.0:
+ resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ yocto-queue: 1.0.0
+ dev: true
+
+ /p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-limit: 3.1.0
+ dev: true
+
+ /parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+ dependencies:
+ callsites: 3.1.0
+ dev: true
+
+ /parse5@7.1.2:
+ resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
+ dependencies:
+ entities: 4.5.0
+ dev: true
+
+ /path-browserify@1.0.1:
+ resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+ dev: true
+
+ /path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ /path-key@4.0.0:
+ resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ /path-scurry@1.10.1:
+ resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ dependencies:
+ lru-cache: 10.2.0
+ minipass: 7.0.4
+
+ /path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /pathe@1.1.2:
+ resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
+ dev: true
+
+ /pathval@1.1.1:
+ resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+ dev: true
+
+ /picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+
+ /picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ /pify@2.3.0:
+ resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
+ engines: {node: '>=0.10.0'}
+
+ /pirates@4.0.6:
+ resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
+ engines: {node: '>= 6'}
+
+ /pkg-types@1.0.3:
+ resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==}
+ dependencies:
+ jsonc-parser: 3.2.1
+ mlly: 1.6.1
+ pathe: 1.1.2
+ dev: true
+
+ /possible-typed-array-names@1.0.0:
+ resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /postcss-import@15.1.0(postcss@8.4.35):
+ resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ postcss: ^8.0.0
+ dependencies:
+ postcss: 8.4.35
+ postcss-value-parser: 4.2.0
+ read-cache: 1.0.0
+ resolve: 1.22.8
+
+ /postcss-js@4.0.1(postcss@8.4.35):
+ resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
+ engines: {node: ^12 || ^14 || >= 16}
+ peerDependencies:
+ postcss: ^8.4.21
+ dependencies:
+ camelcase-css: 2.0.1
+ postcss: 8.4.35
+
+ /postcss-load-config@4.0.2(postcss@8.4.35):
+ resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ postcss: '>=8.0.9'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ postcss:
+ optional: true
+ ts-node:
+ optional: true
+ dependencies:
+ lilconfig: 3.1.1
+ postcss: 8.4.35
+ yaml: 2.4.1
+
+ /postcss-nested@6.0.1(postcss@8.4.35):
+ resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==}
+ engines: {node: '>=12.0'}
+ peerDependencies:
+ postcss: ^8.2.14
+ dependencies:
+ postcss: 8.4.35
+ postcss-selector-parser: 6.0.16
+
+ /postcss-selector-parser@6.0.16:
+ resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
+ engines: {node: '>=4'}
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
+ /postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
+ /postcss@8.4.35:
+ resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.0
+ source-map-js: 1.0.2
+
+ /prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /prettier@2.8.8:
+ resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ dev: true
+
+ /pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+ dev: true
+
+ /pretty-format@29.7.0:
+ resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ dependencies:
+ '@jest/schemas': 29.6.3
+ ansi-styles: 5.2.0
+ react-is: 18.2.0
+ dev: true
+
+ /proto-list@1.2.4:
+ resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+ dev: true
+
+ /psl@1.9.0:
+ resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
+ dev: true
+
+ /punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /qs@6.12.0:
+ resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==}
+ engines: {node: '>=0.6'}
+ dependencies:
+ side-channel: 1.0.6
+ dev: false
+
+ /querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+ dev: true
+
+ /queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ /react-is@17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+ dev: true
+
+ /react-is@18.2.0:
+ resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
+ dev: true
+
+ /read-cache@1.0.0:
+ resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
+ dependencies:
+ pify: 2.3.0
+
+ /readdirp@3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+
+ /redent@3.0.0:
+ resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+ engines: {node: '>=8'}
+ dependencies:
+ indent-string: 4.0.0
+ strip-indent: 3.0.0
+ dev: true
+
+ /regenerator-runtime@0.14.1:
+ resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+ dev: true
+
+ /regexp.prototype.flags@1.5.2:
+ resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-errors: 1.3.0
+ set-function-name: 2.0.2
+ dev: true
+
+ /requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+ dev: true
+
+ /resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /resolve@1.22.8:
+ resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.13.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ /reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ /rimraf@3.0.2:
+ resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ hasBin: true
+ dependencies:
+ glob: 7.2.3
+ dev: true
+
+ /rollup@4.13.0:
+ resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+ dependencies:
+ '@types/estree': 1.0.5
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.13.0
+ '@rollup/rollup-android-arm64': 4.13.0
+ '@rollup/rollup-darwin-arm64': 4.13.0
+ '@rollup/rollup-darwin-x64': 4.13.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.13.0
+ '@rollup/rollup-linux-arm64-gnu': 4.13.0
+ '@rollup/rollup-linux-arm64-musl': 4.13.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.13.0
+ '@rollup/rollup-linux-x64-gnu': 4.13.0
+ '@rollup/rollup-linux-x64-musl': 4.13.0
+ '@rollup/rollup-win32-arm64-msvc': 4.13.0
+ '@rollup/rollup-win32-ia32-msvc': 4.13.0
+ '@rollup/rollup-win32-x64-msvc': 4.13.0
+ fsevents: 2.3.3
+
+ /rrweb-cssom@0.6.0:
+ resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
+ dev: true
+
+ /run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+
+ /safe-array-concat@1.1.2:
+ resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
+ engines: {node: '>=0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ has-symbols: 1.0.3
+ isarray: 2.0.5
+ dev: true
+
+ /safe-regex-test@1.0.3:
+ resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-regex: 1.1.4
+ dev: true
+
+ /safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ dev: true
+
+ /saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+ dependencies:
+ xmlchars: 2.2.0
+ dev: true
+
+ /semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ /semver@7.6.0:
+ resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+ dev: true
+
+ /set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+
+ /set-function-name@2.0.2:
+ resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ functions-have-names: 1.2.3
+ has-property-descriptors: 1.0.2
+ dev: true
+
+ /shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+ dependencies:
+ shebang-regex: 3.0.0
+
+ /shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ /side-channel@1.0.6:
+ resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ object-inspect: 1.13.1
+
+ /siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+ dev: true
+
+ /signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ /slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /source-map-js@1.0.2:
+ resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+ engines: {node: '>=0.10.0'}
+
+ /stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+ dev: true
+
+ /std-env@3.7.0:
+ resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
+ dev: true
+
+ /stop-iteration-iterator@1.0.0:
+ resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ internal-slot: 1.0.7
+ dev: true
+
+ /string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ /string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
+
+ /string.prototype.trim@1.2.8:
+ resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ dev: true
+
+ /string.prototype.trimend@1.0.7:
+ resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ dev: true
+
+ /string.prototype.trimstart@1.0.7:
+ resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ dev: true
+
+ /strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-regex: 5.0.1
+
+ /strip-ansi@7.1.0:
+ resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-regex: 6.0.1
+
+ /strip-bom@3.0.0:
+ resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /strip-final-newline@3.0.0:
+ resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /strip-indent@3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ min-indent: 1.0.1
+ dev: true
+
+ /strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /strip-literal@2.0.0:
+ resolution: {integrity: sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==}
+ dependencies:
+ js-tokens: 8.0.3
+ dev: true
+
+ /sucrase@3.35.0:
+ resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
+ engines: {node: '>=16 || 14 >=14.17'}
+ hasBin: true
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ commander: 4.1.1
+ glob: 10.3.10
+ lines-and-columns: 1.2.4
+ mz: 2.7.0
+ pirates: 4.0.6
+ ts-interface-checker: 0.1.13
+
+ /supports-color@5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: 3.0.0
+
+ /supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+ dependencies:
+ has-flag: 4.0.0
+ dev: true
+
+ /supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ /svg-tags@1.0.0:
+ resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
+ dev: false
+
+ /symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+ dev: true
+
+ /tailwindcss@3.4.1:
+ resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ arg: 5.0.2
+ chokidar: 3.6.0
+ didyoumean: 1.2.2
+ dlv: 1.1.3
+ fast-glob: 3.3.2
+ glob-parent: 6.0.2
+ is-glob: 4.0.3
+ jiti: 1.21.0
+ lilconfig: 2.1.0
+ micromatch: 4.0.5
+ normalize-path: 3.0.0
+ object-hash: 3.0.0
+ picocolors: 1.0.0
+ postcss: 8.4.35
+ postcss-import: 15.1.0(postcss@8.4.35)
+ postcss-js: 4.0.1(postcss@8.4.35)
+ postcss-load-config: 4.0.2(postcss@8.4.35)
+ postcss-nested: 6.0.1(postcss@8.4.35)
+ postcss-selector-parser: 6.0.16
+ resolve: 1.22.8
+ sucrase: 3.35.0
+ transitivePeerDependencies:
+ - ts-node
+
+ /test-exclude@6.0.0:
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 7.2.3
+ minimatch: 3.1.2
+ dev: true
+
+ /text-table@0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ dev: true
+
+ /thenify-all@1.6.0:
+ resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ thenify: 3.3.1
+
+ /thenify@3.3.1:
+ resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
+ dependencies:
+ any-promise: 1.3.0
+
+ /tinybench@2.6.0:
+ resolution: {integrity: sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==}
+ dev: true
+
+ /tinypool@0.8.2:
+ resolution: {integrity: sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==}
+ engines: {node: '>=14.0.0'}
+ dev: true
+
+ /tinyspy@2.2.1:
+ resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
+ engines: {node: '>=14.0.0'}
+ dev: true
+
+ /to-fast-properties@2.0.0:
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+ engines: {node: '>=4'}
+
+ /to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ is-number: 7.0.0
+
+ /tough-cookie@4.1.3:
+ resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==}
+ engines: {node: '>=6'}
+ dependencies:
+ psl: 1.9.0
+ punycode: 2.3.1
+ universalify: 0.2.0
+ url-parse: 1.5.10
+ dev: true
+
+ /tr46@0.0.3:
+ resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ dev: false
+
+ /tr46@5.0.0:
+ resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
+ engines: {node: '>=18'}
+ dependencies:
+ punycode: 2.3.1
+ dev: true
+
+ /ts-api-utils@1.3.0(typescript@5.4.2):
+ resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
+ engines: {node: '>=16'}
+ peerDependencies:
+ typescript: '>=4.2.0'
+ dependencies:
+ typescript: 5.4.2
+ dev: true
+
+ /ts-interface-checker@0.1.13:
+ resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
+
+ /tsconfig-paths@3.15.0:
+ resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+ dependencies:
+ '@types/json5': 0.0.29
+ json5: 1.0.2
+ minimist: 1.2.8
+ strip-bom: 3.0.0
+ dev: true
+
+ /type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ dev: true
+
+ /type-detect@4.0.8:
+ resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /type-fest@0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /typed-array-buffer@1.0.2:
+ resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-typed-array: 1.1.13
+ dev: true
+
+ /typed-array-byte-length@1.0.1:
+ resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+ dev: true
+
+ /typed-array-byte-offset@1.0.2:
+ resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+ dev: true
+
+ /typed-array-length@1.0.5:
+ resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+ possible-typed-array-names: 1.0.0
+ dev: true
+
+ /typescript@5.4.2:
+ resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ /ufo@1.5.1:
+ resolution: {integrity: sha512-HGyF79+/qZ4soRvM+nHERR2pJ3VXDZ/8sL1uLahdgEDf580NkgiWOxLk33FetExqOWp352JZRsgXbG/4MaGOSg==}
+ dev: true
+
+ /unbox-primitive@1.0.2:
+ resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+ dependencies:
+ call-bind: 1.0.7
+ has-bigints: 1.0.2
+ has-symbols: 1.0.3
+ which-boxed-primitive: 1.0.2
+ dev: true
+
+ /undici-types@5.26.5:
+ resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+
+ /universalify@0.2.0:
+ resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
+ engines: {node: '>= 4.0.0'}
+ dev: true
+
+ /update-browserslist-db@1.0.13(browserslist@4.23.0):
+ resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+ dependencies:
+ browserslist: 4.23.0
+ escalade: 3.1.2
+ picocolors: 1.0.0
+ dev: false
+
+ /uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ dependencies:
+ punycode: 2.3.1
+ dev: true
+
+ /url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+ dev: true
+
+ /util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+ /v8-to-istanbul@9.2.0:
+ resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
+ engines: {node: '>=10.12.0'}
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ '@types/istanbul-lib-coverage': 2.0.6
+ convert-source-map: 2.0.0
+ dev: true
+
+ /vite-node@1.4.0(@types/node@20.11.28):
+ resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ dependencies:
+ cac: 6.7.14
+ debug: 4.3.4
+ pathe: 1.1.2
+ picocolors: 1.0.0
+ vite: 5.1.6(@types/node@20.11.28)
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ dev: true
+
+ /vite@5.1.6(@types/node@20.11.28):
+ resolution: {integrity: sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ dependencies:
+ '@types/node': 20.11.28
+ esbuild: 0.19.12
+ postcss: 8.4.35
+ rollup: 4.13.0
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ /vitest@1.4.0(@types/node@20.11.28)(jsdom@24.0.0):
+ resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/node': ^18.0.0 || >=20.0.0
+ '@vitest/browser': 1.4.0
+ '@vitest/ui': 1.4.0
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+ dependencies:
+ '@types/node': 20.11.28
+ '@vitest/expect': 1.4.0
+ '@vitest/runner': 1.4.0
+ '@vitest/snapshot': 1.4.0
+ '@vitest/spy': 1.4.0
+ '@vitest/utils': 1.4.0
+ acorn-walk: 8.3.2
+ chai: 4.4.1
+ debug: 4.3.4
+ execa: 8.0.1
+ jsdom: 24.0.0
+ local-pkg: 0.5.0
+ magic-string: 0.30.8
+ pathe: 1.1.2
+ picocolors: 1.0.0
+ std-env: 3.7.0
+ strip-literal: 2.0.0
+ tinybench: 2.6.0
+ tinypool: 0.8.2
+ vite: 5.1.6(@types/node@20.11.28)
+ vite-node: 1.4.0(@types/node@20.11.28)
+ why-is-node-running: 2.2.2
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ dev: true
+
+ /vue-component-type-helpers@2.0.6:
+ resolution: {integrity: sha512-qdGXCtoBrwqk1BT6r2+1Wcvl583ZVkuSZ3or7Y1O2w5AvWtlvvxwjGhmz5DdPJS9xqRdDlgTJ/38ehWnEi0tFA==}
+ dev: true
+
+ /vue-eslint-parser@9.4.2(eslint@8.57.0):
+ resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==}
+ engines: {node: ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '>=6.0.0'
+ dependencies:
+ debug: 4.3.4
+ eslint: 8.57.0
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.5.0
+ lodash: 4.17.21
+ semver: 7.6.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /vue-router@4.3.0(vue@3.4.21):
+ resolution: {integrity: sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==}
+ peerDependencies:
+ vue: ^3.2.0
+ dependencies:
+ '@vue/devtools-api': 6.6.1
+ vue: 3.4.21(typescript@5.4.2)
+ dev: false
+
+ /vue-template-compiler@2.7.16:
+ resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==}
+ dependencies:
+ de-indent: 1.0.2
+ he: 1.2.0
+ dev: true
+
+ /vue-tsc@1.8.27(typescript@5.4.2):
+ resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==}
+ hasBin: true
+ peerDependencies:
+ typescript: '*'
+ dependencies:
+ '@volar/typescript': 1.11.1
+ '@vue/language-core': 1.8.27(typescript@5.4.2)
+ semver: 7.6.0
+ typescript: 5.4.2
+ dev: true
+
+ /vue@3.4.21(typescript@5.4.2):
+ resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@vue/compiler-dom': 3.4.21
+ '@vue/compiler-sfc': 3.4.21
+ '@vue/runtime-dom': 3.4.21
+ '@vue/server-renderer': 3.4.21(vue@3.4.21)
+ '@vue/shared': 3.4.21
+ typescript: 5.4.2
+
+ /w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+ dependencies:
+ xml-name-validator: 5.0.0
+ dev: true
+
+ /webidl-conversions@3.0.1:
+ resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ dev: false
+
+ /webidl-conversions@7.0.0:
+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /whatwg-encoding@3.1.1:
+ resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
+ engines: {node: '>=18'}
+ dependencies:
+ iconv-lite: 0.6.3
+ dev: true
+
+ /whatwg-mimetype@4.0.0:
+ resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /whatwg-url@14.0.0:
+ resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
+ engines: {node: '>=18'}
+ dependencies:
+ tr46: 5.0.0
+ webidl-conversions: 7.0.0
+ dev: true
+
+ /whatwg-url@5.0.0:
+ resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+ dev: false
+
+ /which-boxed-primitive@1.0.2:
+ resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+ dependencies:
+ is-bigint: 1.0.4
+ is-boolean-object: 1.1.2
+ is-number-object: 1.0.7
+ is-string: 1.0.7
+ is-symbol: 1.0.4
+ dev: true
+
+ /which-collection@1.0.2:
+ resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ is-map: 2.0.3
+ is-set: 2.0.3
+ is-weakmap: 2.0.2
+ is-weakset: 2.0.3
+ dev: true
+
+ /which-typed-array@1.1.15:
+ resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-tostringtag: 1.0.2
+ dev: true
+
+ /which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+
+ /why-is-node-running@2.2.2:
+ resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==}
+ engines: {node: '>=8'}
+ hasBin: true
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+ dev: true
+
+ /wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ /wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+
+ /wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ dev: true
+
+ /ws@8.16.0:
+ resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
+ 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
+ dev: true
+
+ /xml-name-validator@4.0.0:
+ resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+ dev: true
+
+ /xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+ dev: true
+
+ /yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+ dev: false
+
+ /yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ dev: true
+
+ /yaml@2.4.1:
+ resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==}
+ engines: {node: '>= 14'}
+ hasBin: true
+
+ /yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yocto-queue@1.0.0:
+ resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
+ engines: {node: '>=12.20'}
+ dev: true
+
+ /zod@3.22.4:
+ resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
+ dev: false
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..2562819
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,7 @@
+export default {
+ plugins: {
+ 'tailwindcss/nesting': {},
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+};
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000..fd3d759
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,10 @@
+sonar.organization=chubbyts
+sonar.projectKey=chubbyts_vue-petstore
+sonar.projectName=vue-petstore
+
+sonar.sources=src
+sonar.exclusions=tests/**
+sonar.tests=tests
+sonar.language=typescript
+sonar.sourceEncoding=UTF-8
+sonar.javascript.lcov.reportPaths=coverage/lcov.info
diff --git a/src/app.tsx b/src/app.tsx
new file mode 100644
index 0000000..2e455c1
--- /dev/null
+++ b/src/app.tsx
@@ -0,0 +1,51 @@
+import { defineComponent, ref } from 'vue';
+import { RouterLink, RouterView } from 'vue-router';
+
+const App = defineComponent(() => {
+ const displayMenu = ref(false);
+
+ const toggleMenu = () => {
+ displayMenu.value = !displayMenu.value;
+ };
+
+ return () => (
+
+
+
+
+
+
+
+ );
+});
+
+export default App;
diff --git a/src/client/client.ts b/src/client/client.ts
new file mode 100644
index 0000000..2c7e17a
--- /dev/null
+++ b/src/client/client.ts
@@ -0,0 +1,213 @@
+import { throwableToError } from '@chubbyts/chubbyts-throwable-to-error/dist/throwable-to-error';
+import type { HttpError } from './error';
+import { BadRequest, InternalServerError, NetworkError, NotFound, UnprocessableEntity } from './error';
+import qs from 'qs';
+import type { z } from 'zod';
+
+export type Fetch = (input: RequestInfo | URL, init?: RequestInit) => Promise;
+
+export type ListClient = (
+ modelListRequest: ModelListRequest,
+) => Promise;
+
+export const createListClient = (
+ fetch: Fetch,
+ url: string,
+ modelListRequestSchema: ModelListRequestSchema,
+ modelListResponseSchema: ModelListResponseSchema,
+): ListClient, z.infer> => {
+ return async (
+ modelListRequest: z.infer,
+ ): Promise | HttpError> => {
+ try {
+ const response: Response = await fetch(`${url}?${qs.stringify(modelListRequestSchema.parse(modelListRequest))}`, {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ });
+
+ const json = await response.json();
+
+ if (200 === response.status) {
+ return modelListResponseSchema.parse(json);
+ }
+
+ if (400 === response.status) {
+ return new BadRequest({ ...json });
+ }
+
+ if (500 === response.status) {
+ return new InternalServerError({ ...json });
+ }
+ } catch (error) {
+ return new NetworkError({ title: throwableToError(error).message });
+ }
+
+ throw new Error('Unknown response');
+ };
+};
+
+export type CreateClient = (
+ modelRequest: ModelRequest,
+) => Promise;
+
+export const createCreateClient = (
+ fetch: Fetch,
+ url: string,
+ modelRequestSchema: ModelRequestSchema,
+ modelResponseSchema: ModelResponseSchema,
+): CreateClient, z.infer> => {
+ return async (
+ modelRequest: z.infer,
+ ): Promise | HttpError> => {
+ try {
+ const response: Response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(modelRequestSchema.parse(modelRequest)),
+ });
+
+ const json = await response.json();
+
+ if (201 === response.status) {
+ return modelResponseSchema.parse(json);
+ }
+
+ if (400 === response.status) {
+ return new BadRequest({ ...json });
+ }
+
+ if (422 === response.status) {
+ return new UnprocessableEntity({ ...json });
+ }
+
+ if (500 === response.status) {
+ return new InternalServerError({ ...json });
+ }
+ } catch (error) {
+ return new NetworkError({ title: throwableToError(error).message });
+ }
+ };
+};
+
+export type ReadClient = (id: string) => Promise;
+
+export const createReadClient = (
+ fetch: Fetch,
+ url: string,
+ modelResponseSchema: ModelResponseSchema,
+): ReadClient> => {
+ return async (id: string): Promise | HttpError> => {
+ try {
+ const response: Response = await fetch(`${url}/${id}`, {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ });
+
+ const json = await response.json();
+
+ if (200 === response.status) {
+ return modelResponseSchema.parse(json);
+ }
+
+ if (404 === response.status) {
+ return new NotFound({ ...json });
+ }
+
+ if (500 === response.status) {
+ return new InternalServerError({ ...json });
+ }
+ } catch (error) {
+ return new NetworkError({ title: throwableToError(error).message });
+ }
+ };
+};
+
+export type UpdateClient = (
+ id: string,
+ modelRequest: ModelRequest,
+) => Promise;
+
+export const createUpdateClient = (
+ fetch: Fetch,
+ url: string,
+ modelRequestSchema: ModelRequestSchema,
+ modelResponseSchema: ModelResponseSchema,
+): UpdateClient, z.infer> => {
+ return async (
+ id: string,
+ modelRequest: z.infer,
+ ): Promise | HttpError> => {
+ try {
+ const response: Response = await fetch(`${url}/${id}`, {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(modelRequestSchema.parse(modelRequest)),
+ });
+
+ const json = await response.json();
+
+ if (200 === response.status) {
+ return modelResponseSchema.parse(json);
+ }
+
+ if (400 === response.status) {
+ return new BadRequest({ ...json });
+ }
+
+ if (404 === response.status) {
+ return new NotFound({ ...json });
+ }
+
+ if (422 === response.status) {
+ return new UnprocessableEntity({ ...json });
+ }
+
+ if (500 === response.status) {
+ return new InternalServerError({ ...json });
+ }
+ } catch (error) {
+ return new NetworkError({ title: throwableToError(error).message });
+ }
+ };
+};
+
+export type DeleteClient = (id: string) => Promise;
+
+export const createDeleteClient = (fetch: Fetch, url: string): DeleteClient => {
+ return async (id: string): Promise => {
+ try {
+ const response: Response = await fetch(`${url}/${id}`, {
+ method: 'DELETE',
+ headers: {
+ Accept: 'application/json',
+ },
+ });
+
+ if (204 === response.status) {
+ return;
+ }
+
+ const json = await response.json();
+
+ if (404 === response.status) {
+ return new NotFound({ ...json });
+ }
+
+ if (500 === response.status) {
+ return new InternalServerError({ ...json });
+ }
+ } catch (error) {
+ return new NetworkError({ title: throwableToError(error).message });
+ }
+ };
+};
diff --git a/src/client/error.ts b/src/client/error.ts
new file mode 100644
index 0000000..0117dad
--- /dev/null
+++ b/src/client/error.ts
@@ -0,0 +1,58 @@
+export class HttpError {
+ title: string;
+ detail?: string;
+ instance?: string;
+ constructor({ title, detail, instance }: { title: string; detail?: string; instance?: string }) {
+ this.title = title;
+ this.detail = detail;
+ this.instance = instance;
+ }
+}
+
+export interface InvalidParameter {
+ name: string;
+ reason: string;
+ details?: { [key: string]: unknown };
+}
+
+export class BadRequestOrUnprocessableEntity extends HttpError {
+ invalidParameters?: Array;
+ constructor({
+ title,
+ detail,
+ instance,
+ invalidParameters,
+ }: {
+ title: string;
+ detail?: string;
+ instance?: string;
+ invalidParameters?: Array;
+ }) {
+ super({ title, detail, instance });
+ this.invalidParameters = invalidParameters;
+ }
+}
+
+export class BadRequest extends BadRequestOrUnprocessableEntity {}
+
+export class InternalServerError extends HttpError {}
+
+export class NetworkError extends HttpError {}
+
+export class NotFound extends HttpError {}
+
+export class UnprocessableEntity extends BadRequestOrUnprocessableEntity {}
+
+export const createInvalidParametersByName = (
+ httpErrorOrUndefined: HttpError | undefined,
+): Map> => {
+ return (
+ httpErrorOrUndefined && httpErrorOrUndefined instanceof BadRequestOrUnprocessableEntity
+ ? httpErrorOrUndefined.invalidParameters ?? []
+ : []
+ ).reduce((map: Map>, invalidParameter: InvalidParameter) => {
+ map.set(invalidParameter.name, [...(map.get(invalidParameter.name) ?? []), invalidParameter]);
+
+ return map;
+ }, new Map>());
+};
diff --git a/src/client/pet.ts b/src/client/pet.ts
new file mode 100644
index 0000000..4a78c6d
--- /dev/null
+++ b/src/client/pet.ts
@@ -0,0 +1,17 @@
+import { petListRequestSchema, petListResponseSchema, petRequestSchema, petResponseSchema } from '../model/pet';
+import {
+ createCreateClient,
+ createDeleteClient,
+ createListClient,
+ createReadClient,
+ createUpdateClient,
+} from './client';
+import { fetch } from 'cross-fetch';
+
+const url = `${import.meta.env.VITE_PETSTORE_URL}/api/pets`;
+
+export const listPetsClient = createListClient(fetch, url, petListRequestSchema, petListResponseSchema);
+export const createPetClient = createCreateClient(fetch, url, petRequestSchema, petResponseSchema);
+export const readPetClient = createReadClient(fetch, url, petResponseSchema);
+export const updatePetClient = createUpdateClient(fetch, url, petRequestSchema, petResponseSchema);
+export const deletePetClient = createDeleteClient(fetch, url);
diff --git a/src/component/button.tsx b/src/component/button.tsx
new file mode 100644
index 0000000..b8d7def
--- /dev/null
+++ b/src/component/button.tsx
@@ -0,0 +1,65 @@
+import type {
+ AllowedComponentProps,
+ ButtonHTMLAttributes,
+ ComponentCustomProps,
+ SlotsType,
+ VNode,
+ VNodeProps,
+} from 'vue';
+import { defineComponent } from 'vue';
+import type { RouterLinkProps } from 'vue-router';
+import { _RouterLinkI, RouterLink } from 'vue-router';
+
+type ColorTheme = 'blue' | 'gray' | 'green' | 'red';
+
+const getColorThemeClasses = (colorTheme: ColorTheme) => {
+ switch (colorTheme) {
+ case 'blue':
+ return 'bg-blue-600 hover:bg-blue-700';
+ case 'gray':
+ return 'bg-gray-600 hover:bg-gray-700';
+ case 'green':
+ return 'bg-green-600 hover:bg-green-700';
+ case 'red':
+ return 'bg-red-600 hover:bg-red-700';
+ }
+};
+
+export const AnchorButton = defineComponent(
+ (
+ props: AllowedComponentProps & ComponentCustomProps & VNodeProps & RouterLinkProps & { colorTheme: ColorTheme },
+ { slots },
+ ) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'AnchorButton',
+ props: ['class', 'colorTheme'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
+
+export const Button = defineComponent(
+ (props: ButtonHTMLAttributes & { colorTheme: ColorTheme }, { slots }) => {
+ return () => (
+
+ );
+ },
+ {
+ name: 'Button',
+ props: ['class', 'colorTheme'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
diff --git a/src/component/form/form.tsx b/src/component/form/form.tsx
new file mode 100644
index 0000000..41e3880
--- /dev/null
+++ b/src/component/form/form.tsx
@@ -0,0 +1,65 @@
+import type { FieldsetHTMLAttributes, SlotsType, VNode } from 'vue';
+import { defineComponent } from 'vue';
+import type { InvalidParameter } from '../../client/error';
+
+export const FieldSet = defineComponent(
+ (props: FieldsetHTMLAttributes, { slots }) => {
+ return () => (
+
+ );
+ },
+ {
+ name: 'FieldSet',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
+
+export const TextField = defineComponent(
+ (props: {
+ dataTestId: string;
+ label: string;
+ value: string;
+ setValue: (value: string) => void;
+ invalidParameters: Array;
+ }) => {
+ console.log(props);
+
+ return () => (
+
+ );
+ },
+ {
+ name: 'TextField',
+ props: ['dataTestId', 'label', 'value', 'setValue', 'invalidParameters'],
+ },
+);
diff --git a/src/component/form/pet-filters-form.tsx b/src/component/form/pet-filters-form.tsx
new file mode 100644
index 0000000..8df6a03
--- /dev/null
+++ b/src/component/form/pet-filters-form.tsx
@@ -0,0 +1,49 @@
+import { computed, defineComponent, reactive } from 'vue';
+import type { PetFilters } from '../../model/pet';
+import type { HttpError } from '../../client/error';
+import { createInvalidParametersByName } from '../../client/error';
+import { FieldSet, TextField } from './form';
+import { Button } from '../button';
+
+export const PetFiltersForm = defineComponent(
+ (props: {
+ httpError: HttpError | undefined;
+ initialPetFilters: PetFilters;
+ submitPetFilters: (petFilters: PetFilters) => void;
+ }) => {
+ const groupInvalidParametersByName = computed(() => createInvalidParametersByName(props.httpError));
+
+ const petFilters = reactive(props.initialPetFilters);
+
+ const onSubmit = () => {
+ props.submitPetFilters({ ...petFilters });
+ };
+
+ return () => (
+
+ );
+ },
+ {
+ name: 'PetFiltersForm',
+ props: ['httpError', 'initialPetFilters', 'submitPetFilters'],
+ },
+);
diff --git a/src/component/form/pet-form.tsx b/src/component/form/pet-form.tsx
new file mode 100644
index 0000000..152c7e1
--- /dev/null
+++ b/src/component/form/pet-form.tsx
@@ -0,0 +1,104 @@
+import { computed, defineComponent, reactive } from 'vue';
+import type { PetRequest } from '../../model/pet';
+import type { HttpError } from '../../client/error';
+import { createInvalidParametersByName } from '../../client/error';
+import { FieldSet, TextField } from './form';
+import { Button } from '../button';
+
+export const PetForm = defineComponent(
+ (props: { httpError: HttpError | undefined; initialPet?: PetRequest; submitPet: (pet: PetRequest) => void }) => {
+ const groupInvalidParametersByName = computed(() => createInvalidParametersByName(props.httpError));
+
+ const pet = reactive(props.initialPet ?? { name: '', vaccinations: [] });
+
+ const onSubmit = () => {
+ props.submitPet({ ...pet });
+ };
+
+ return () => (
+
+ );
+ },
+ {
+ name: 'PetForm',
+ props: ['httpError', 'initialPet', 'submitPet'],
+ },
+);
diff --git a/src/component/heading.tsx b/src/component/heading.tsx
new file mode 100644
index 0000000..091b640
--- /dev/null
+++ b/src/component/heading.tsx
@@ -0,0 +1,17 @@
+import type { HTMLAttributes, SlotsType, VNode } from 'vue';
+import { defineComponent } from 'vue';
+
+export const H1 = defineComponent(
+ (props: HTMLAttributes, { slots }) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'H1',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
diff --git a/src/component/page/home.tsx b/src/component/page/home.tsx
new file mode 100644
index 0000000..7864c86
--- /dev/null
+++ b/src/component/page/home.tsx
@@ -0,0 +1,27 @@
+import { defineComponent, onMounted, onUnmounted } from 'vue';
+import { H1 } from '../heading';
+
+const pageTitle = 'Home';
+
+const Home = defineComponent(
+ () => {
+ onMounted(() => {
+ document.title = pageTitle;
+ });
+
+ onUnmounted(() => {
+ document.title = '';
+ });
+
+ return () => (
+
+
{pageTitle}
+
+ );
+ },
+ {
+ name: 'Home',
+ },
+);
+
+export default Home;
diff --git a/src/component/page/not-found.tsx b/src/component/page/not-found.tsx
new file mode 100644
index 0000000..c3c2742
--- /dev/null
+++ b/src/component/page/not-found.tsx
@@ -0,0 +1,27 @@
+import { defineComponent, onMounted, onUnmounted } from 'vue';
+import { H1 } from '../heading';
+
+const pageTitle = 'Not Found';
+
+const NotFound = defineComponent(
+ () => {
+ onMounted(() => {
+ document.title = pageTitle;
+ });
+
+ onUnmounted(() => {
+ document.title = '';
+ });
+
+ return () => (
+
+
{pageTitle}
+
+ );
+ },
+ {
+ name: 'NotFound',
+ },
+);
+
+export default NotFound;
diff --git a/src/component/page/pet/create.tsx b/src/component/page/pet/create.tsx
new file mode 100644
index 0000000..11884b5
--- /dev/null
+++ b/src/component/page/pet/create.tsx
@@ -0,0 +1,49 @@
+import { defineComponent, onMounted, onUnmounted } from 'vue';
+import { H1 } from '../../heading';
+import { HttpError as HttpErrorPartial } from '../../partial/http-error';
+import { useRouter } from 'vue-router';
+import { createModelResource } from '../../../hook/create-model-resource';
+import { createPetClient as createClient } from '../../../client/pet';
+import type { PetRequest } from '../../../model/pet';
+import { PetForm } from '../../form/pet-form';
+import { AnchorButton } from '../../button';
+
+const pageTitle = 'Pet Create';
+
+const PetCreate = defineComponent(
+ () => {
+ const { push } = useRouter();
+
+ const { httpError, actions } = createModelResource({ createClient });
+
+ const submitPet = async (pet: PetRequest) => {
+ if (await actions.createModel(pet)) {
+ push('/pet');
+ }
+ };
+
+ onMounted(() => {
+ document.title = pageTitle;
+ });
+
+ onUnmounted(() => {
+ document.title = '';
+ });
+
+ return () => (
+
+ {httpError.value ?
: null}
+
{pageTitle}
+
+
+ List
+
+
+ );
+ },
+ {
+ name: 'PetCreate',
+ },
+);
+
+export default PetCreate;
diff --git a/src/component/page/pet/list.tsx b/src/component/page/pet/list.tsx
new file mode 100644
index 0000000..134f799
--- /dev/null
+++ b/src/component/page/pet/list.tsx
@@ -0,0 +1,199 @@
+import { computed, defineComponent, onMounted, onUnmounted, watch } from 'vue';
+import { H1 } from '../../heading';
+import { HttpError as HttpErrorPartial } from '../../partial/http-error';
+import { format } from 'date-fns';
+import { de } from 'date-fns/locale';
+import { useRoute, useRouter } from 'vue-router';
+import { createModelResource } from '../../../hook/create-model-resource';
+import { deletePetClient as deleteClient, listPetsClient as listClient } from '../../../client/pet';
+import { z } from 'zod';
+import { numberSchema } from '../../../model/model';
+import type { PetFilters, PetSort } from '../../../model/pet';
+import { petFiltersSchema, petSortSchema } from '../../../model/pet';
+import qs from 'qs';
+import { AnchorButton, Button } from '../../button';
+import { Table, Tbody, Td, Th, Thead, Tr } from '../../table';
+import { Pagination } from '../../partial/pagination';
+import { PetFiltersForm } from '../../form/pet-filters-form';
+
+const pageTitle = 'Pet List';
+
+const limit = 10;
+
+const querySchema = z.object({
+ page: numberSchema.optional().default(1),
+ filters: petFiltersSchema.optional().default({}),
+ sort: petSortSchema.optional().default({}),
+});
+
+const PetList = defineComponent(
+ () => {
+ const { push } = useRouter();
+ const route = useRoute();
+ const query = computed(() => querySchema.parse(qs.parse(route.fullPath.substring(route.path.length + 1))));
+
+ const {
+ modelList: petList,
+ httpError,
+ actions,
+ } = createModelResource({
+ listClient,
+ deleteClient,
+ });
+
+ const petListRequest = computed(() => ({
+ offset: query.value.page * limit - limit,
+ limit,
+ filters: query.value.filters,
+ sort: query.value.sort,
+ }));
+
+ const fetchPetList = async () => {
+ actions.listModel(petListRequest.value);
+ };
+
+ const deletePet = async (id: string) => {
+ if (await actions.deleteModel(id)) {
+ fetchPetList();
+ }
+ };
+
+ const submitPage = (page: number): void => {
+ push(`/pet?${qs.stringify({ ...query.value, page })}`);
+ };
+
+ const submitPetFilters = (filters: PetFilters): void => {
+ push(`/pet?${qs.stringify({ ...query.value, page: 1, filters })}`);
+ };
+
+ const submitPetSort = (sort: PetSort): void => {
+ push(`/pet?${qs.stringify({ ...query.value, page: 1, sort })}`);
+ };
+
+ onMounted(() => {
+ document.title = pageTitle;
+
+ fetchPetList();
+ });
+
+ watch(query, () => {
+ fetchPetList();
+ });
+
+ onUnmounted(() => {
+ document.title = '';
+ });
+
+ return () => (
+ <>
+ {petList.value || httpError.value ? (
+
+ {httpError.value ?
: null}
+
{pageTitle}
+ {petList.value ? (
+
+ {petList.value._links?.create ? (
+
+ Create
+
+ ) : null}
+
+
+
+
+
+ Id |
+ CreatedAt |
+ UpdatedAt |
+
+ Name (
+
+ |
+
+ |
+
+ )
+ |
+ Tag |
+ Actions |
+
+
+
+ {petList.value.items.map((pet, i) => (
+
+ {pet.id} |
+ {format(Date.parse(pet.createdAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })} |
+
+ {pet.updatedAt &&
+ format(Date.parse(pet.updatedAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })}
+ |
+ {pet.name} |
+ {pet.tag} |
+
+ {pet._links?.read ? (
+
+ Read
+
+ ) : null}
+ {pet._links?.update ? (
+
+ Update
+
+ ) : null}
+ {pet._links?.delete ? (
+
+ ) : null}
+ |
+
+ ))}
+
+
+
+
+
+ ) : null}
+
+ ) : null}
+ >
+ );
+ },
+ {
+ name: 'PetList',
+ },
+);
+
+export default PetList;
diff --git a/src/component/page/pet/read.tsx b/src/component/page/pet/read.tsx
new file mode 100644
index 0000000..821b3c2
--- /dev/null
+++ b/src/component/page/pet/read.tsx
@@ -0,0 +1,81 @@
+import { defineComponent, onMounted, onUnmounted } from 'vue';
+import { H1 } from '../../heading';
+import { HttpError as HttpErrorPartial } from '../../partial/http-error';
+import { format } from 'date-fns';
+import { de } from 'date-fns/locale';
+import { useRoute } from 'vue-router';
+import { createModelResource } from '../../../hook/create-model-resource';
+import { readPetClient as readClient } from '../../../client/pet';
+import { AnchorButton } from '../../button';
+
+const pageTitle = 'Pet Read';
+
+const PetRead = defineComponent(
+ () => {
+ const route = useRoute();
+ const id = route.params.id as string;
+
+ const { model: pet, httpError, actions } = createModelResource({ readClient });
+
+ onMounted(() => {
+ document.title = pageTitle;
+
+ actions.readModel(id);
+ });
+
+ onUnmounted(() => {
+ document.title = '';
+ });
+
+ return () => (
+ <>
+ {pet.value || httpError.value ? (
+
+ {httpError.value ?
: null}
+
{pageTitle}
+ {pet.value ? (
+
+
+ - Id
+ - {pet.value.id}
+ - CreatedAt
+ -
+ {format(Date.parse(pet.value.createdAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })}
+
+ - UpdatedAt
+ -
+ {pet.value.updatedAt
+ ? format(Date.parse(pet.value.updatedAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })
+ : null}
+
+ - Name
+ - {pet.value.name}
+ - Tag
+ - {pet.value.tag}
+ - Vaccinations
+ -
+ {pet.value.vaccinations.length > 0 ? (
+
+ {pet.value.vaccinations.map((vaccination) => (
+ - {vaccination.name}
+ ))}
+
+ ) : null}
+
+
+
+ ) : null}
+
+ List
+
+
+ ) : null}
+ >
+ );
+ },
+ {
+ name: 'PetRead',
+ },
+);
+
+export default PetRead;
diff --git a/src/component/page/pet/update.tsx b/src/component/page/pet/update.tsx
new file mode 100644
index 0000000..cc3e522
--- /dev/null
+++ b/src/component/page/pet/update.tsx
@@ -0,0 +1,57 @@
+import { defineComponent, onMounted, onUnmounted } from 'vue';
+import { H1 } from '../../heading';
+import { HttpError as HttpErrorPartial } from '../../partial/http-error';
+import { useRoute, useRouter } from 'vue-router';
+import { createModelResource } from '../../../hook/create-model-resource';
+import { readPetClient as readClient, updatePetClient as updateClient } from '../../../client/pet';
+import type { PetRequest } from '../../../model/pet';
+import { PetForm } from '../../form/pet-form';
+import { AnchorButton } from '../../button';
+
+const pageTitle = 'Pet Update';
+
+const PetUpdate = defineComponent(
+ () => {
+ const { push } = useRouter();
+ const route = useRoute();
+ const id = route.params.id as string;
+
+ const { model: pet, httpError, actions } = createModelResource({ readClient, updateClient });
+
+ const submitPet = async (petRequest: PetRequest) => {
+ if (await actions.updateModel(id, petRequest)) {
+ push('/pet');
+ }
+ };
+
+ onMounted(() => {
+ document.title = pageTitle;
+
+ actions.readModel(id);
+ });
+
+ onUnmounted(() => {
+ document.title = '';
+ });
+
+ return () => (
+ <>
+ {pet.value || httpError.value ? (
+
+ {httpError.value ?
: null}
+
{pageTitle}
+ {pet.value ?
: null}
+
+ List
+
+
+ ) : null}
+ >
+ );
+ },
+ {
+ name: 'PetUpdate',
+ },
+);
+
+export default PetUpdate;
diff --git a/src/component/partial/http-error.tsx b/src/component/partial/http-error.tsx
new file mode 100644
index 0000000..ba85ba0
--- /dev/null
+++ b/src/component/partial/http-error.tsx
@@ -0,0 +1,28 @@
+import { defineComponent } from 'vue';
+import type { HttpError as HttpErrorType } from '../../client/error';
+import { BadRequestOrUnprocessableEntity } from '../../client/error';
+
+export const HttpError = defineComponent(
+ (props: { httpError: HttpErrorType }) => {
+ return () => (
+
+
{props.httpError.title}
+ {props.httpError.detail ?
{props.httpError.detail}
: null}
+ {props.httpError.instance ?
{props.httpError.instance}
: null}
+ {props.httpError instanceof BadRequestOrUnprocessableEntity && props.httpError.invalidParameters?.length ? (
+
+ {props.httpError.invalidParameters.map((invalidParameter, i) => (
+ -
+ {invalidParameter.name}: {invalidParameter.reason}
+
+ ))}
+
+ ) : null}
+
+ );
+ },
+ {
+ name: 'HttpError',
+ props: ['httpError'],
+ },
+);
diff --git a/src/component/partial/pagination.tsx b/src/component/partial/pagination.tsx
new file mode 100644
index 0000000..93a5231
--- /dev/null
+++ b/src/component/partial/pagination.tsx
@@ -0,0 +1,110 @@
+import { computed, defineComponent } from 'vue';
+
+const calculatePages = (currentPage: number, totalPages: number, maxPages: number) => {
+ if (totalPages <= 1 || maxPages <= 1 || currentPage > totalPages) {
+ return [];
+ }
+
+ const pages = [currentPage];
+
+ for (let i = 1; ; i++) {
+ if (currentPage - i >= 1) {
+ pages.push(currentPage - i);
+
+ if (pages.length === maxPages || pages.length === totalPages) {
+ break;
+ }
+ }
+
+ if (currentPage + i <= totalPages) {
+ pages.push(currentPage + i);
+
+ if (pages.length === maxPages || pages.length === totalPages) {
+ break;
+ }
+ }
+ }
+
+ pages.sort((a, b) => a - b);
+
+ return pages;
+};
+
+export const Pagination = defineComponent(
+ (props: { currentPage: number; totalPages: number; maxPages: number; submitPage: (page: number) => void }) => {
+ const pages = computed(() => calculatePages(props.currentPage, props.totalPages, props.maxPages));
+
+ return () => (
+ <>
+ {pages.value.length > 0 ? (
+
+ {props.currentPage > 2 ? (
+ -
+
+
+ ) : null}
+ {props.currentPage > 1 ? (
+ -
+
+
+ ) : null}
+ {pages.value.map((page: number) => (
+ -
+
+
+ ))}
+ {props.currentPage < props.totalPages ? (
+ -
+
+
+ ) : null}
+ {props.currentPage < props.totalPages - 1 ? (
+ -
+
+
+ ) : null}
+
+ ) : null}
+ >
+ );
+ },
+ {
+ name: 'Pagination',
+ props: ['currentPage', 'totalPages', 'maxPages', 'submitPage'],
+ },
+);
diff --git a/src/component/table.tsx b/src/component/table.tsx
new file mode 100644
index 0000000..87eb89d
--- /dev/null
+++ b/src/component/table.tsx
@@ -0,0 +1,102 @@
+import type { HTMLAttributes, SlotsType, TableHTMLAttributes, TdHTMLAttributes, ThHTMLAttributes, VNode } from 'vue';
+import { defineComponent } from 'vue';
+
+export const Table = defineComponent(
+ (props: TableHTMLAttributes, { slots }) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'Table',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
+
+export const Thead = defineComponent(
+ (props: HTMLAttributes, { slots }) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'Thead',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
+
+export const Tbody = defineComponent(
+ (props: HTMLAttributes, { slots }) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'Tbody',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
+
+export const Tr = defineComponent(
+ (props: HTMLAttributes, { slots }) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'Tr',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
+
+export const Th = defineComponent(
+ (props: ThHTMLAttributes, { slots }) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'Th',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
+
+export const Td = defineComponent(
+ (props: TdHTMLAttributes, { slots }) => {
+ return () => (
+
+ {slots.default()}
+
+ );
+ },
+ {
+ name: 'Td',
+ props: ['class'],
+ slots: Object as SlotsType<{ default: () => VNode[] }>,
+ },
+);
diff --git a/src/hook/create-model-resource.ts b/src/hook/create-model-resource.ts
new file mode 100644
index 0000000..46ca2e5
--- /dev/null
+++ b/src/hook/create-model-resource.ts
@@ -0,0 +1,161 @@
+import { HttpError } from '../client/error';
+import type { ModelListRequest, ModelListResponse, ModelRequest, ModelResponse } from '../model/model';
+import type { CreateClient, DeleteClient, ListClient, ReadClient, UpdateClient } from '../client/client';
+import { ref } from 'vue';
+
+export const createModelResource = <
+ MLReq extends ModelListRequest,
+ MLRes extends ModelListResponse,
+ MReq extends ModelRequest,
+ MRes extends ModelResponse,
+>({
+ listClient,
+ createClient,
+ readClient,
+ updateClient,
+ deleteClient,
+}: {
+ listClient?: ListClient;
+ createClient?: CreateClient;
+ readClient?: ReadClient;
+ updateClient?: UpdateClient;
+ deleteClient?: DeleteClient;
+}) => {
+ const loading = ref<'list' | 'create' | 'read' | 'update' | 'delete' | undefined>();
+ const modelList = ref();
+ const model = ref();
+ const httpError = ref();
+
+ const listModel = async (req: MLReq): Promise => {
+ if (!listClient) {
+ throw new Error('Missing listClient');
+ }
+
+ loading.value = 'list';
+
+ const response = await listClient(req);
+
+ let success: boolean;
+
+ if (response instanceof HttpError) {
+ httpError.value = response;
+ success = false;
+ } else {
+ httpError.value = undefined;
+ modelList.value = response;
+ success = true;
+ }
+
+ loading.value = undefined;
+
+ return success;
+ };
+
+ const createModel = async (req: MReq): Promise => {
+ if (!createClient) {
+ throw new Error('Missing createClient');
+ }
+
+ loading.value = 'create';
+
+ const response = await createClient(req);
+
+ let success: boolean;
+
+ if (response instanceof HttpError) {
+ httpError.value = response;
+ success = false;
+ } else {
+ httpError.value = undefined;
+ model.value = response;
+ success = true;
+ }
+
+ loading.value = undefined;
+
+ return success;
+ };
+
+ const readModel = async (id: string): Promise => {
+ if (!readClient) {
+ throw new Error('Missing readClient');
+ }
+
+ loading.value = 'read';
+
+ const response = await readClient(id);
+
+ let success: boolean;
+
+ if (response instanceof HttpError) {
+ httpError.value = response;
+ success = false;
+ } else {
+ httpError.value = undefined;
+ model.value = response;
+ success = true;
+ }
+
+ loading.value = undefined;
+
+ return success;
+ };
+
+ const updateModel = async (id: string, req: MReq): Promise => {
+ if (!updateClient) {
+ throw new Error('Missing updateClient');
+ }
+
+ loading.value = 'update';
+
+ const response = await updateClient(id, req);
+
+ let success: boolean;
+
+ if (response instanceof HttpError) {
+ httpError.value = response;
+ success = false;
+ } else {
+ httpError.value = undefined;
+ model.value = response;
+ success = true;
+ }
+
+ loading.value = undefined;
+
+ return success;
+ };
+
+ const deleteModel = async (id: string): Promise => {
+ if (!deleteClient) {
+ throw new Error('Missing deleteClient');
+ }
+
+ loading.value = 'delete';
+
+ const response = await deleteClient(id);
+
+ let success: boolean;
+
+ if (response instanceof HttpError) {
+ httpError.value = response;
+ success = false;
+ } else {
+ httpError.value = undefined;
+ model.value = undefined;
+ success = true;
+ }
+
+ loading.value = undefined;
+
+ return success;
+ };
+
+ return {
+ loading,
+ modelList,
+ model,
+ httpError,
+ actions: { listModel, createModel, readModel, updateModel, deleteModel },
+ };
+};
diff --git a/src/index.css b/src/index.css
new file mode 100644
index 0000000..dbfb140
--- /dev/null
+++ b/src/index.css
@@ -0,0 +1,10 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+html,
+body,
+#root {
+ @apply w-full;
+ @apply h-full;
+}
diff --git a/src/index.tsx b/src/index.tsx
new file mode 100644
index 0000000..eaf1b9d
--- /dev/null
+++ b/src/index.tsx
@@ -0,0 +1,14 @@
+import { createApp } from 'vue';
+import './index.css';
+import App from './app.tsx';
+import { routes } from './routes.ts';
+import { createWebHistory, createRouter } from 'vue-router';
+
+createApp(App)
+ .use(
+ createRouter({
+ history: createWebHistory(),
+ routes,
+ }),
+ )
+ .mount('#root');
diff --git a/src/model/model.ts b/src/model/model.ts
new file mode 100644
index 0000000..295b96c
--- /dev/null
+++ b/src/model/model.ts
@@ -0,0 +1,63 @@
+import { z } from 'zod';
+
+export const numberSchema = z.union([
+ z
+ .string()
+ .refine((number) => !Number.isNaN(parseInt(number, 10)))
+ .transform((number) => parseInt(number, 10)),
+ z.number(),
+]);
+
+export const sortSchema = z.union([z.literal('asc'), z.literal('desc')]);
+
+const linkSchema = z.object({
+ href: z.string(),
+});
+
+export const modelRequestSchema = z.object({}).strict();
+
+export type ModelRequest = z.infer;
+
+export const modelResponseSchema = z
+ .object({
+ id: z.string(),
+ createdAt: z.string(),
+ updatedAt: z.string().nullish(),
+ _links: z
+ .object({
+ read: linkSchema.nullish(),
+ update: linkSchema.nullish(),
+ delete: linkSchema.nullish(),
+ })
+ .strict(),
+ })
+ .strict();
+
+export type ModelResponse = z.infer;
+
+export const modelListRequestSchema = z
+ .object({
+ offset: numberSchema.optional(),
+ limit: numberSchema.optional(),
+ filters: z.object({}).strict().optional(),
+ sort: z.object({}).strict().optional(),
+ })
+ .strict();
+
+export type ModelListRequest = z.infer;
+
+export const modelListResponseSchema = z
+ .object({
+ offset: numberSchema,
+ limit: numberSchema,
+ filters: z.object({}).strict(),
+ sort: z.object({}).strict(),
+ count: numberSchema,
+ items: z.array(modelResponseSchema),
+ _links: z.object({
+ create: linkSchema.nullish(),
+ }),
+ })
+ .strict();
+
+export type ModelListResponse = z.infer;
diff --git a/src/model/pet.ts b/src/model/pet.ts
new file mode 100644
index 0000000..068c127
--- /dev/null
+++ b/src/model/pet.ts
@@ -0,0 +1,57 @@
+import { z } from 'zod';
+import {
+ modelRequestSchema,
+ modelResponseSchema,
+ modelListRequestSchema,
+ sortSchema,
+ modelListResponseSchema,
+} from './model';
+
+export const petRequestSchema = z.object({
+ ...modelRequestSchema.shape,
+ name: z.string(),
+ tag: z.string().nullish(),
+ vaccinations: z.array(
+ z.object({
+ name: z.string(),
+ }),
+ ),
+});
+
+export type PetRequest = z.infer;
+
+export const petResponseSchema = z.object({
+ ...modelResponseSchema.shape,
+ ...petRequestSchema.shape,
+});
+
+export type PetResponse = z.infer;
+
+export const petFiltersSchema = z.object({
+ name: z.string().nullish(),
+});
+
+export type PetFilters = z.infer;
+
+export const petSortSchema = z.object({
+ name: sortSchema.nullish(),
+});
+
+export type PetSort = z.infer;
+
+export const petListRequestSchema = z.object({
+ ...modelListRequestSchema.shape,
+ filters: petFiltersSchema.optional(),
+ sort: petSortSchema.optional(),
+});
+
+export type PetListRequest = z.infer;
+
+export const petListResponseSchema = z.object({
+ ...modelListResponseSchema.shape,
+ filters: petFiltersSchema,
+ sort: petSortSchema,
+ items: z.array(petResponseSchema),
+});
+
+export type PetListResponse = z.infer;
diff --git a/src/routes.ts b/src/routes.ts
new file mode 100644
index 0000000..6bc6358
--- /dev/null
+++ b/src/routes.ts
@@ -0,0 +1,17 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+const Home = () => import('./component/page/home');
+const PetList = () => import('./component/page/pet/list');
+const PetCreate = () => import('./component/page/pet/create');
+const PetRead = () => import('./component/page/pet/read');
+const PetUpdate = () => import('./component/page/pet/update');
+const NotFound = () => import('./component/page/not-found');
+
+export const routes: Array = [
+ { path: '/', name: 'Home', component: Home },
+ { path: '/pet', name: 'PetList', component: PetList },
+ { path: '/pet/create', name: 'PetCreate', component: PetCreate },
+ { path: '/pet/:id', name: 'PetRead', component: PetRead },
+ { path: '/pet/:id/update', name: 'PetUpdate', component: PetUpdate },
+ { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
+];
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..fc61fff
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ['./src/**/*.{jsx,tsx}'],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/tests/app.test.tsx b/tests/app.test.tsx
new file mode 100644
index 0000000..29b2578
--- /dev/null
+++ b/tests/app.test.tsx
@@ -0,0 +1,422 @@
+/** @jsxImportSource vue */
+
+import { test, expect, vi } from 'vitest';
+import { formatHtml } from './formatter';
+import { render, screen } from '@testing-library/vue';
+import App from '../src/app';
+import { routes } from '../src/routes';
+import { userEvent } from '@testing-library/user-event';
+import { createRouter, createWebHistory } from 'vue-router';
+import { defineComponent } from 'vue';
+
+vi.mock('../src/component/page/home', () => {
+ return {
+ __esModule: true,
+ default: defineComponent(() => () => ),
+ };
+});
+
+vi.mock('../src/component/page/pet/list', () => {
+ return {
+ __esModule: true,
+ default: defineComponent(() => () => ),
+ };
+});
+
+vi.mock('../src/component/page/pet/create', () => {
+ return {
+ __esModule: true,
+ default: defineComponent(() => () => ),
+ };
+});
+
+vi.mock('../src/component/page/pet/read', () => {
+ return {
+ __esModule: true,
+ default: defineComponent(() => () => ),
+ };
+});
+
+vi.mock('../src/component/page/pet/update', () => {
+ return {
+ __esModule: true,
+ default: defineComponent(() => () => ),
+ };
+});
+
+vi.mock('../src/component/page/not-found', () => {
+ return {
+ __esModule: true,
+ default: defineComponent(() => () => ),
+ };
+});
+
+test('close navigation', () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('open navigation', async () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ const navigationToggle = await screen.findByTestId('navigation-toggle');
+
+ await userEvent.click(navigationToggle);
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('not found', async () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/unknown');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('pet list', async () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('pet create', async () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/create');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('pet read', async () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('pet update', async () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9/update');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
diff --git a/tests/client/client.test.ts b/tests/client/client.test.ts
new file mode 100644
index 0000000..7b0121d
--- /dev/null
+++ b/tests/client/client.test.ts
@@ -0,0 +1,1239 @@
+import { describe, expect, test } from 'vitest';
+import type { Fetch } from '../../src/client/client';
+import {
+ createCreateClient,
+ createDeleteClient,
+ createListClient,
+ createReadClient,
+ createUpdateClient,
+} from '../../src/client/client';
+import {
+ modelRequestSchema,
+ modelResponseSchema,
+ modelListRequestSchema,
+ modelListResponseSchema,
+} from '../../src/model/model';
+import { useFunctionMock } from '@chubbyts/chubbyts-function-mock/dist/function-mock';
+import { z } from 'zod';
+
+const dummyModelRequestSchema = z.object({
+ ...modelRequestSchema.shape,
+ name: z.string(),
+});
+
+type DummyModelRequest = z.infer;
+
+const dummyModelResponseSchema = z.object({
+ ...modelResponseSchema.shape,
+ ...dummyModelRequestSchema.shape,
+});
+
+type DummyModelResponse = z.infer;
+
+const dummyModelListRequestSchema = z.object({
+ ...modelListRequestSchema.shape,
+ filters: z
+ .object({
+ name: z.string().optional(),
+ })
+ .strict()
+ .optional(),
+});
+
+type DummyModelListRequest = z.infer;
+
+const dummyModelListResponseSchema = z.object({
+ ...modelListResponseSchema.shape,
+ filters: z
+ .object({
+ name: z.string().optional(),
+ })
+ .strict()
+ .optional(),
+ items: z.array(dummyModelResponseSchema),
+});
+
+type DummyModelListResponse = z.infer;
+
+describe('createListClient', () => {
+ test('success', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const dummyModelResponse: DummyModelResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2022-06-12T20:08:24.793Z',
+ ...dummyModelRequest,
+ _links: {},
+ };
+
+ const dummyModelListRequest: DummyModelListRequest = { filters: { name: 'Dummy' } };
+
+ const dummyModelListResponse: DummyModelListResponse = {
+ offset: 0,
+ limit: 20,
+ filters: {},
+ sort: {},
+ count: 1,
+ items: [dummyModelResponse],
+ ...dummyModelListRequest,
+ _links: {},
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models?filters%5Bname%5D=Dummy',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 200,
+ json: () => Promise.resolve(dummyModelListResponse),
+ } as Response),
+ },
+ ]);
+
+ const listClient = createListClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelListRequestSchema,
+ dummyModelListResponseSchema,
+ );
+
+ expect(await listClient({ filters: { name: 'Dummy' } })).toEqual(dummyModelListResponse);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('bad request', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models?filters%5Bname%5D=Dummy',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 400,
+ json: () =>
+ Promise.resolve({
+ title: 'Bad Request',
+ detail: 'Sorting value',
+ instance: '0123456789abcdef',
+ invalidParameters: [{ name: 'name', reason: 'unknown field', details: { key: 'value1' } }],
+ }),
+ } as Response),
+ },
+ ]);
+
+ const listClient = createListClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelListRequestSchema,
+ dummyModelListResponseSchema,
+ );
+
+ expect(await listClient({ filters: { name: 'Dummy' } })).toMatchInlineSnapshot(`
+ BadRequest {
+ "detail": "Sorting value",
+ "instance": "0123456789abcdef",
+ "invalidParameters": [
+ {
+ "details": {
+ "key": "value1",
+ },
+ "name": "name",
+ "reason": "unknown field",
+ },
+ ],
+ "title": "Bad Request",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('internal server error', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models?filters%5Bname%5D=Dummy',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 500,
+ json: () =>
+ Promise.resolve({
+ title: 'Internal Server Error',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const listClient = createListClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelListRequestSchema,
+ dummyModelListResponseSchema,
+ );
+
+ expect(await listClient({ filters: { name: 'Dummy' } })).toMatchInlineSnapshot(`
+ InternalServerError {
+ "detail": undefined,
+ "instance": "0123456789abcdef",
+ "title": "Internal Server Error",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('network error', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models?filters%5Bname%5D=Dummy',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ error: new Error('Failed to fetch'),
+ },
+ ]);
+
+ const listClient = createListClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelListRequestSchema,
+ dummyModelListResponseSchema,
+ );
+
+ expect(await listClient({ filters: { name: 'Dummy' } })).toMatchInlineSnapshot(`
+ NetworkError {
+ "detail": undefined,
+ "instance": undefined,
+ "title": "Failed to fetch",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('unknown response', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models?filters%5Bname%5D=Dummy',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 418,
+ json: () => Promise.resolve({}),
+ } as Response),
+ },
+ ]);
+
+ const listClient = createListClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelListRequestSchema,
+ dummyModelListResponseSchema,
+ );
+
+ try {
+ await listClient({ filters: { name: 'Dummy' } });
+ throw new Error('expect fail');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: Unknown response]');
+ }
+
+ expect(fetchMocks.length).toBe(0);
+ });
+});
+
+describe('createCreateClient', () => {
+ test('success', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const dummyModelResponse: DummyModelResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2022-06-12T20:08:24.793Z',
+ ...dummyModelRequest,
+ _links: {},
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models',
+ {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 201,
+ json: () => Promise.resolve(dummyModelResponse),
+ } as Response),
+ },
+ ]);
+
+ const createClient = createCreateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await createClient(dummyModelRequest)).toEqual(dummyModelResponse);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('bad request', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models',
+ {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 400,
+ json: () =>
+ Promise.resolve({
+ title: 'Bad Request',
+ detail: 'name',
+ instance: '0123456789abcdef',
+ invalidParameters: [{ name: 'name', reason: 'empty', details: { key: 'value1' } }],
+ }),
+ } as Response),
+ },
+ ]);
+
+ const createClient = createCreateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await createClient(dummyModelRequest)).toMatchInlineSnapshot(`
+ BadRequest {
+ "detail": "name",
+ "instance": "0123456789abcdef",
+ "invalidParameters": [
+ {
+ "details": {
+ "key": "value1",
+ },
+ "name": "name",
+ "reason": "empty",
+ },
+ ],
+ "title": "Bad Request",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('unprocessable entity', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models',
+ {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 422,
+ json: () =>
+ Promise.resolve({
+ title: 'Unprocessable Entity',
+ detail: 'name',
+ instance: '0123456789abcdef',
+ invalidParameters: [{ name: 'name', reason: 'empty', details: { key: 'value1' } }],
+ }),
+ } as Response),
+ },
+ ]);
+
+ const createClient = createCreateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await createClient(dummyModelRequest)).toMatchInlineSnapshot(`
+ UnprocessableEntity {
+ "detail": "name",
+ "instance": "0123456789abcdef",
+ "invalidParameters": [
+ {
+ "details": {
+ "key": "value1",
+ },
+ "name": "name",
+ "reason": "empty",
+ },
+ ],
+ "title": "Unprocessable Entity",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('internal server error', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models',
+ {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 500,
+ json: () =>
+ Promise.resolve({
+ title: 'Internal Server Error',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const createClient = createCreateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await createClient(dummyModelRequest)).toMatchInlineSnapshot(`
+ InternalServerError {
+ "detail": undefined,
+ "instance": "0123456789abcdef",
+ "title": "Internal Server Error",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('network error', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models',
+ {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ error: new Error('Failed to fetch'),
+ },
+ ]);
+
+ const createClient = createCreateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await createClient(dummyModelRequest)).toMatchInlineSnapshot(`
+ NetworkError {
+ "detail": undefined,
+ "instance": undefined,
+ "title": "Failed to fetch",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('unknown response', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models',
+ {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 418,
+ json: () => Promise.resolve({}),
+ } as Response),
+ },
+ ]);
+
+ const createClient = createCreateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ try {
+ await createClient(dummyModelRequest);
+ throw new Error('expect fail');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: expect fail]');
+ }
+
+ expect(fetchMocks.length).toBe(0);
+ });
+});
+
+describe('createReadClient', () => {
+ test('success', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const dummyModelResponse: DummyModelResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2022-06-12T20:08:24.793Z',
+ ...dummyModelRequest,
+ _links: {},
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ `https://petstore.test/api/models/${dummyModelResponse.id}`,
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 200,
+ json: () => Promise.resolve(dummyModelResponse),
+ } as Response),
+ },
+ ]);
+
+ const readClient = createReadClient(fetch, 'https://petstore.test/api/models', dummyModelResponseSchema);
+
+ expect(await readClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toEqual(dummyModelResponse);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('not found', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 404,
+ json: () =>
+ Promise.resolve({
+ title: 'Not Found',
+ detail: 'There is no model with id "4d783b77-eb09-4603-b99b-f590b605eaa9"',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const readClient = createReadClient(fetch, 'https://petstore.test/api/models', dummyModelResponseSchema);
+
+ expect(await readClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toMatchInlineSnapshot(`
+ NotFound {
+ "detail": "There is no model with id "4d783b77-eb09-4603-b99b-f590b605eaa9"",
+ "instance": "0123456789abcdef",
+ "title": "Not Found",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('internal server error', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 500,
+ json: () =>
+ Promise.resolve({
+ title: 'Internal Server Error',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const readClient = createReadClient(fetch, 'https://petstore.test/api/models', dummyModelResponseSchema);
+
+ expect(await readClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toMatchInlineSnapshot(`
+ InternalServerError {
+ "detail": undefined,
+ "instance": "0123456789abcdef",
+ "title": "Internal Server Error",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('network error', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ error: new Error('Failed to fetch'),
+ },
+ ]);
+
+ const readClient = createReadClient(fetch, 'https://petstore.test/api/models', dummyModelResponseSchema);
+
+ expect(await readClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toMatchInlineSnapshot(`
+ NetworkError {
+ "detail": undefined,
+ "instance": undefined,
+ "title": "Failed to fetch",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('unknown response', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 418,
+ json: () => Promise.resolve({}),
+ } as Response),
+ },
+ ]);
+
+ const readClient = createReadClient(fetch, 'https://petstore.test/api/models', dummyModelResponseSchema);
+
+ try {
+ await readClient('4d783b77-eb09-4603-b99b-f590b605eaa9');
+ throw new Error('expect fail');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: expect fail]');
+ }
+
+ expect(fetchMocks.length).toBe(0);
+ });
+});
+
+describe('createUpdateClient', () => {
+ test('success', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const dummyModelResponse: DummyModelResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2022-06-12T20:08:24.793Z',
+ ...dummyModelRequest,
+ _links: {},
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ `https://petstore.test/api/models/${dummyModelResponse.id}`,
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 200,
+ json: () => Promise.resolve(dummyModelResponse),
+ } as Response),
+ },
+ ]);
+
+ const updateClient = createUpdateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await updateClient('4d783b77-eb09-4603-b99b-f590b605eaa9', dummyModelRequest)).toEqual(dummyModelResponse);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('bad request', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 400,
+ json: () =>
+ Promise.resolve({
+ title: 'Bad Request',
+ detail: 'name',
+ instance: '0123456789abcdef',
+ invalidParameters: [{ name: 'name', reason: 'empty', details: { key: 'value1' } }],
+ }),
+ } as Response),
+ },
+ ]);
+
+ const updateClient = createUpdateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await updateClient('4d783b77-eb09-4603-b99b-f590b605eaa9', dummyModelRequest)).toMatchInlineSnapshot(`
+ BadRequest {
+ "detail": "name",
+ "instance": "0123456789abcdef",
+ "invalidParameters": [
+ {
+ "details": {
+ "key": "value1",
+ },
+ "name": "name",
+ "reason": "empty",
+ },
+ ],
+ "title": "Bad Request",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('not found', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 404,
+ json: () =>
+ Promise.resolve({
+ title: 'Not Found',
+ detail: 'There is no model with id "4d783b77-eb09-4603-b99b-f590b605eaa9"',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const updateClient = createUpdateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await updateClient('4d783b77-eb09-4603-b99b-f590b605eaa9', dummyModelRequest)).toMatchInlineSnapshot(`
+ NotFound {
+ "detail": "There is no model with id "4d783b77-eb09-4603-b99b-f590b605eaa9"",
+ "instance": "0123456789abcdef",
+ "title": "Not Found",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('unprocessable entity', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 422,
+ json: () =>
+ Promise.resolve({
+ title: 'Unprocessable Entity',
+ detail: 'name',
+ instance: '0123456789abcdef',
+ invalidParameters: [{ name: 'name', reason: 'empty', details: { key: 'value1' } }],
+ }),
+ } as Response),
+ },
+ ]);
+
+ const updateClient = createUpdateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await updateClient('4d783b77-eb09-4603-b99b-f590b605eaa9', dummyModelRequest)).toMatchInlineSnapshot(`
+ UnprocessableEntity {
+ "detail": "name",
+ "instance": "0123456789abcdef",
+ "invalidParameters": [
+ {
+ "details": {
+ "key": "value1",
+ },
+ "name": "name",
+ "reason": "empty",
+ },
+ ],
+ "title": "Unprocessable Entity",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('internal server error', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 500,
+ json: () =>
+ Promise.resolve({
+ title: 'Internal Server Error',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const updateClient = createUpdateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await updateClient('4d783b77-eb09-4603-b99b-f590b605eaa9', dummyModelRequest)).toMatchInlineSnapshot(`
+ InternalServerError {
+ "detail": undefined,
+ "instance": "0123456789abcdef",
+ "title": "Internal Server Error",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('network error', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ error: new Error('Failed to fetch'),
+ },
+ ]);
+
+ const updateClient = createUpdateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ expect(await updateClient('4d783b77-eb09-4603-b99b-f590b605eaa9', dummyModelRequest)).toMatchInlineSnapshot(`
+ NetworkError {
+ "detail": undefined,
+ "instance": undefined,
+ "title": "Failed to fetch",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('unknown response', async () => {
+ const dummyModelRequest: DummyModelRequest = {
+ name: 'Dummy',
+ };
+
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'PUT',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dummyModelRequest),
+ },
+ ],
+ return: Promise.resolve({
+ status: 418,
+ json: () => Promise.resolve({}),
+ } as Response),
+ },
+ ]);
+
+ const updateClient = createUpdateClient(
+ fetch,
+ 'https://petstore.test/api/models',
+ dummyModelRequestSchema,
+ dummyModelResponseSchema,
+ );
+
+ try {
+ await updateClient('4d783b77-eb09-4603-b99b-f590b605eaa9', dummyModelRequest);
+ throw new Error('expect fail');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: expect fail]');
+ }
+
+ expect(fetchMocks.length).toBe(0);
+ });
+});
+
+describe('createDeleteClient', () => {
+ test('success', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'DELETE',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 204,
+ json: () => Promise.resolve(undefined),
+ } as Response),
+ },
+ ]);
+
+ const deleteClient = createDeleteClient(fetch, 'https://petstore.test/api/models');
+
+ expect(await deleteClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toBeUndefined();
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('not found', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'DELETE',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 404,
+ json: () =>
+ Promise.resolve({
+ title: 'Not Found',
+ detail: 'There is no model with id "4d783b77-eb09-4603-b99b-f590b605eaa9"',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const deleteClient = createDeleteClient(fetch, 'https://petstore.test/api/models');
+
+ expect(await deleteClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toMatchInlineSnapshot(`
+ NotFound {
+ "detail": "There is no model with id "4d783b77-eb09-4603-b99b-f590b605eaa9"",
+ "instance": "0123456789abcdef",
+ "title": "Not Found",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('internal server error', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'DELETE',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 500,
+ json: () =>
+ Promise.resolve({
+ title: 'Internal Server Error',
+ instance: '0123456789abcdef',
+ }),
+ } as Response),
+ },
+ ]);
+
+ const deleteClient = createDeleteClient(fetch, 'https://petstore.test/api/models');
+
+ expect(await deleteClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toMatchInlineSnapshot(`
+ InternalServerError {
+ "detail": undefined,
+ "instance": "0123456789abcdef",
+ "title": "Internal Server Error",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('network error', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'DELETE',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ error: new Error('Failed to fetch'),
+ },
+ ]);
+
+ const deleteClient = createDeleteClient(fetch, 'https://petstore.test/api/models');
+
+ expect(await deleteClient('4d783b77-eb09-4603-b99b-f590b605eaa9')).toMatchInlineSnapshot(`
+ NetworkError {
+ "detail": undefined,
+ "instance": undefined,
+ "title": "Failed to fetch",
+ }
+ `);
+
+ expect(fetchMocks.length).toBe(0);
+ });
+
+ test('unknown response', async () => {
+ const [fetch, fetchMocks] = useFunctionMock([
+ {
+ parameters: [
+ 'https://petstore.test/api/models/4d783b77-eb09-4603-b99b-f590b605eaa9',
+ {
+ method: 'DELETE',
+ headers: {
+ Accept: 'application/json',
+ },
+ },
+ ],
+ return: Promise.resolve({
+ status: 418,
+ json: () => Promise.resolve({}),
+ } as Response),
+ },
+ ]);
+
+ const deleteClient = createDeleteClient(fetch, 'https://petstore.test/api/models');
+
+ try {
+ await deleteClient('4d783b77-eb09-4603-b99b-f590b605eaa9');
+ throw new Error('expect fail');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: expect fail]');
+ }
+
+ expect(fetchMocks.length).toBe(0);
+ });
+});
diff --git a/tests/client/error.test.ts b/tests/client/error.test.ts
new file mode 100644
index 0000000..1c2fe96
--- /dev/null
+++ b/tests/client/error.test.ts
@@ -0,0 +1,79 @@
+import { describe, expect, test } from 'vitest';
+import type { InvalidParameter } from '../../src/client/error';
+import { BadRequest, NetworkError, UnprocessableEntity, createInvalidParametersByName } from '../../src/client/error';
+
+describe('createInvalidParametersByName', () => {
+ test('with network error', () => {
+ const invalidParametersByName = createInvalidParametersByName(new NetworkError({ title: 'network error' }));
+
+ expect(invalidParametersByName.size).toBe(0);
+ });
+
+ test('with bad request and without invalid parameters', () => {
+ const invalidParametersByName = createInvalidParametersByName(new BadRequest({ title: 'bad request' }));
+
+ expect(invalidParametersByName.size).toBe(0);
+ });
+
+ test('with bad request and with invalid parameters', () => {
+ const invalidParameters: Array = [
+ { name: 'name', reason: 'wrong type', details: { key: 'value1' } },
+ { name: 'name', reason: 'not empty', details: { key: 'value2' } },
+ { name: 'description', reason: 'to long', details: { key: 'value3' } },
+ ];
+
+ const invalidParametersByName = createInvalidParametersByName(
+ new BadRequest({ title: 'bad request', invalidParameters }),
+ );
+
+ expect(invalidParametersByName.has('name')).toBeTruthy();
+
+ const InvalidParametersOfName = invalidParametersByName.get('name');
+
+ expect(InvalidParametersOfName).toBeInstanceOf(Array);
+ expect(InvalidParametersOfName).toHaveLength(2);
+
+ expect(InvalidParametersOfName instanceof Array ? InvalidParametersOfName[0] : null).toBe(invalidParameters[0]);
+ expect(InvalidParametersOfName instanceof Array ? InvalidParametersOfName[1] : null).toBe(invalidParameters[1]);
+
+ const InvalidParametersOfDescription = invalidParametersByName.get('description');
+
+ expect(InvalidParametersOfDescription).toBeInstanceOf(Array);
+ expect(InvalidParametersOfDescription).toHaveLength(1);
+
+ expect(InvalidParametersOfDescription instanceof Array ? InvalidParametersOfDescription[0] : null).toBe(
+ invalidParameters[2],
+ );
+ });
+
+ test('with unprocessable entity and with invalid parameters', () => {
+ const invalidParameters: Array = [
+ { name: 'name', reason: 'wrong type', details: { key: 'value1' } },
+ { name: 'name', reason: 'not empty', details: { key: 'value2' } },
+ { name: 'description', reason: 'to long', details: { key: 'value3' } },
+ ];
+
+ const invalidParametersByName = createInvalidParametersByName(
+ new UnprocessableEntity({ title: 'unprocessable entity', invalidParameters }),
+ );
+
+ expect(invalidParametersByName.has('name')).toBeTruthy();
+
+ const InvalidParametersOfName = invalidParametersByName.get('name');
+
+ expect(InvalidParametersOfName).toBeInstanceOf(Array);
+ expect(InvalidParametersOfName).toHaveLength(2);
+
+ expect(InvalidParametersOfName instanceof Array ? InvalidParametersOfName[0] : null).toBe(invalidParameters[0]);
+ expect(InvalidParametersOfName instanceof Array ? InvalidParametersOfName[1] : null).toBe(invalidParameters[1]);
+
+ const InvalidParametersOfDescription = invalidParametersByName.get('description');
+
+ expect(InvalidParametersOfDescription).toBeInstanceOf(Array);
+ expect(InvalidParametersOfDescription).toHaveLength(1);
+
+ expect(InvalidParametersOfDescription instanceof Array ? InvalidParametersOfDescription[0] : null).toBe(
+ invalidParameters[2],
+ );
+ });
+});
diff --git a/tests/client/pet.test.ts b/tests/client/pet.test.ts
new file mode 100644
index 0000000..82d934b
--- /dev/null
+++ b/tests/client/pet.test.ts
@@ -0,0 +1,10 @@
+import { test, expect } from 'vitest';
+import { listPetsClient, createPetClient, readPetClient, updatePetClient, deletePetClient } from '../../src/client/pet';
+
+test('functions', () => {
+ expect(typeof listPetsClient).toBe('function');
+ expect(typeof createPetClient).toBe('function');
+ expect(typeof readPetClient).toBe('function');
+ expect(typeof updatePetClient).toBe('function');
+ expect(typeof deletePetClient).toBe('function');
+});
diff --git a/tests/component/form/pet-filters-form.test.tsx b/tests/component/form/pet-filters-form.test.tsx
new file mode 100644
index 0000000..b02f2d8
--- /dev/null
+++ b/tests/component/form/pet-filters-form.test.tsx
@@ -0,0 +1,143 @@
+/** @jsxImportSource vue */
+
+import { test, expect, vi } from 'vitest';
+import { formatHtml } from '../../formatter';
+import { PetFiltersForm } from '../../../src/component/form/pet-filters-form';
+import { BadRequest, NetworkError } from '../../../src/client/error';
+import { userEvent } from '@testing-library/user-event';
+import { render, screen } from '@testing-library/vue';
+import type { PetFilters } from '../../../src/model/pet';
+
+test('default', () => {
+ const httpError = undefined;
+ const initialPetFilters = {};
+ const submitPetFilters = () => { };
+
+ const { container } = render(
+ ,
+ );
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+ "
+ `);
+});
+
+test('network error', () => {
+ const httpError = new NetworkError({ title: 'network error' });
+ const initialPetFilters = {};
+ const submitPetFilters = () => { };
+
+ render(
+ ,
+ );
+});
+
+test('bad request', () => {
+ const httpError = new BadRequest({
+ title: 'bad request',
+ });
+ const initialPetFilters = {};
+ const submitPetFilters = () => { };
+
+ render(
+ ,
+ );
+});
+
+test('bad request - with query string name', () => {
+ const httpError = new BadRequest({
+ title: 'bad request',
+ invalidParameters: [{ name: 'filters[name]', reason: 'reason' }],
+ });
+ const initialPetFilters = {};
+ const submitPetFilters = () => { };
+
+ const { container } = render(
+ ,
+ );
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('submit with name', async () => {
+ const httpError = undefined;
+ const initialPetFilters = { name: 'Brown' };
+ const submitPetFilters = vi.fn((petFilters: PetFilters) => {
+ expect(petFilters).toEqual({ name: 'Brownie' });
+ });
+
+ render(
+ ,
+ );
+
+ const nameField = await screen.findByTestId('pet-filters-form-name');
+
+ await userEvent.type(nameField, 'ie');
+
+ const submitButton = await screen.findByTestId('pet-filters-form-submit');
+
+ await userEvent.click(submitButton);
+
+ expect(submitPetFilters).toHaveBeenCalledTimes(1);
+});
+
+test('submit without name', async () => {
+ const httpError = undefined;
+ const initialPetFilters = { name: '' };
+ const submitPetFilters = vi.fn((petFilters: PetFilters) => {
+ expect(petFilters).toEqual({ name: undefined });
+ });
+
+ render(
+ ,
+ );
+
+ const nameField = await screen.findByTestId('pet-filters-form-name');
+
+ await userEvent.type(nameField, '{enter}');
+
+ expect(submitPetFilters).toHaveBeenCalledTimes(1);
+});
diff --git a/tests/component/form/pet-form.test.tsx b/tests/component/form/pet-form.test.tsx
new file mode 100644
index 0000000..14290af
--- /dev/null
+++ b/tests/component/form/pet-form.test.tsx
@@ -0,0 +1,252 @@
+/** @jsxImportSource vue */
+
+import { test, expect, vi } from 'vitest';
+import { formatHtml } from '../../formatter';
+import { PetForm } from '../../../src/component/form/pet-form';
+import { BadRequest, NetworkError } from '../../../src/client/error';
+import type { PetRequest } from '../../../src/model/pet';
+import { userEvent } from '@testing-library/user-event';
+import { render, screen } from '@testing-library/vue';
+
+test('without initial pet', () => {
+ const httpError = undefined;
+ const initialPet = undefined;
+ const submitPet = () => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('with initial pet', () => {
+ const httpError = undefined;
+ const initialPet = { name: 'Brownie', tag: '0001-000', vaccinations: [{ name: 'rabies' }] };
+ const submitPet = () => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('network error', () => {
+ const httpError = new NetworkError({ title: 'network error' });
+ const initialPet = { name: 'Brownie', tag: '0001-000', vaccinations: [{ name: 'rabies' }] };
+ const submitPet = () => { };
+
+ render();
+});
+
+test('bad request', () => {
+ const httpError = new BadRequest({
+ title: 'bad request',
+ });
+ const initialPet = { name: 'Brownie', tag: '0001-000', vaccinations: [{ name: 'rabies' }] };
+ const submitPet = () => { };
+
+ render();
+});
+
+test('bad request - with query string name', () => {
+ const httpError = new BadRequest({
+ title: 'bad request',
+ invalidParameters: [
+ { name: 'name', reason: 'reason1' },
+ { name: 'vaccinations[0][name]', reason: 'reason2' },
+ ],
+ });
+ const initialPet = { name: 'Brownie', tag: '0001-000', vaccinations: [{ name: 'rabies' }] };
+ const submitPet = () => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('submit with name', async () => {
+ const httpError = undefined;
+ const initialPet = { name: 'Brown', vaccinations: [{ name: 'rabie' }, { name: 'cat cold' }] };
+ const submitPet = vi.fn((pet: PetRequest) => {
+ expect(pet).toEqual({ name: 'Brownie', vaccinations: [{ name: 'rabies' }, { name: 'cat cold' }, { name: '' }] });
+ });
+
+ render();
+
+ const nameField = await screen.findByTestId('pet-form-name');
+
+ await userEvent.type(nameField, 'ie');
+
+ const vaccinationNameField = await screen.findByTestId('pet-form-vaccinations-0-name');
+
+ await userEvent.type(vaccinationNameField, 's');
+
+ const addVaccination = await screen.findByTestId('pet-form-add-vaccination');
+
+ await userEvent.click(addVaccination);
+ await userEvent.click(addVaccination);
+
+ const removeVaccination = await screen.findByTestId('pet-form-remove-vaccination-3');
+
+ await userEvent.click(removeVaccination);
+
+ const submitButton = await screen.findByTestId('pet-form-submit');
+
+ await userEvent.click(submitButton);
+
+ expect(submitPet).toHaveBeenCalledTimes(1);
+});
diff --git a/tests/component/page/home.test.tsx b/tests/component/page/home.test.tsx
new file mode 100644
index 0000000..f1a3883
--- /dev/null
+++ b/tests/component/page/home.test.tsx
@@ -0,0 +1,17 @@
+/** @jsxImportSource vue */
+
+import { render } from '@testing-library/vue';
+import Home from '../../../src/component/page/home';
+import { test, expect } from 'vitest';
+import { formatHtml } from '../../formatter';
+
+test('default', () => {
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
diff --git a/tests/component/page/not-found.test.tsx b/tests/component/page/not-found.test.tsx
new file mode 100644
index 0000000..dc2fd3b
--- /dev/null
+++ b/tests/component/page/not-found.test.tsx
@@ -0,0 +1,17 @@
+/** @jsxImportSource vue */
+
+import { render } from '@testing-library/vue';
+import NotFound from '../../../src/component/page/not-found';
+import { test, expect } from 'vitest';
+import { formatHtml } from '../../formatter';
+
+test('default', () => {
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
diff --git a/tests/component/page/pet/create.test.tsx b/tests/component/page/pet/create.test.tsx
new file mode 100644
index 0000000..c2a8f17
--- /dev/null
+++ b/tests/component/page/pet/create.test.tsx
@@ -0,0 +1,178 @@
+/** @jsxImportSource vue */
+
+import { vi, test, expect } from 'vitest';
+import type { PetRequest, PetResponse } from '../../../../src/model/pet';
+import { formatHtml } from '../../../formatter';
+import { UnprocessableEntity } from '../../../../src/client/error';
+import type { HttpError } from '../../../../src/client/error';
+import { render, screen } from '@testing-library/vue';
+import type { createPetClient } from '../../../../src/client/pet';
+import { defineComponent } from 'vue';
+import { createRouter, createWebHistory, RouterView } from 'vue-router';
+import { userEvent } from '@testing-library/user-event';
+
+let mockCreatePetClient: typeof createPetClient;
+
+vi.mock('../../../../src/client/pet', () => {
+ return {
+ createPetClient: (pet: PetRequest) => {
+ return mockCreatePetClient(pet);
+ },
+ };
+});
+
+vi.mock('../../../../src/component/form/pet-form', () => {
+ return {
+ __esModule: true,
+ PetForm: defineComponent((props: { httpError: HttpError | undefined; initialPet?: PetRequest; submitPet: (pet: PetRequest) => void; }) => {
+ const onSubmit = () => {
+ props.submitPet({ name: 'Brownie', vaccinations: [] });
+ };
+
+ return () => (
+
+ );
+ }, { props: ['httpError', 'initialPet', 'submitPet'] }),
+ };
+});
+
+test('default', async () => {
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/create', name: 'PetCreate', component: () => import('../../../../src/component/page/pet/create') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/create');
+
+ await screen.findByTestId('page-pet-create');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('unprocessable entity', async () => {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ mockCreatePetClient = async (_: PetRequest) => {
+ return new Promise((resolve) =>
+ resolve(new UnprocessableEntity({ title: 'unprocessable entity' })),
+ );
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/create', name: 'PetCreate', component: () => import('../../../../src/component/page/pet/create') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/create');
+
+ const testButton = await screen.findByTestId('pet-form-submit');
+
+ await userEvent.click(testButton);
+
+ await screen.findByTestId('http-error');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+
unprocessable entity
+
+
+
Pet Create
+
List
+
+
+ "
+ `);
+});
+
+test('successful', async () => {
+ mockCreatePetClient = async (petRequest: PetRequest) => {
+ const petResponse: PetResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ ...petRequest,
+ _links: {},
+ };
+ return new Promise((resolve) => resolve(petResponse));
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: defineComponent(() => () => ) },
+ { path: '/pet/create', name: 'PetCreate', component: () => import('../../../../src/component/page/pet/create') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/create');
+
+ const testButton = await screen.findByTestId('pet-form-submit');
+
+ await userEvent.click(testButton);
+
+ await screen.findByTestId('page-pet-list-mock');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
diff --git a/tests/component/page/pet/list.test.tsx b/tests/component/page/pet/list.test.tsx
new file mode 100644
index 0000000..110d8c6
--- /dev/null
+++ b/tests/component/page/pet/list.test.tsx
@@ -0,0 +1,806 @@
+/** @jsxImportSource vue */
+
+import { vi, test, expect } from 'vitest';
+import type { PetFilters, PetListRequest, PetListResponse } from '../../../../src/model/pet';
+import { formatHtml } from '../../../formatter';
+import type { deletePetClient, listPetsClient } from '../../../../src/client/pet';
+import type { HttpError } from '../../../../src/client/error';
+import { BadRequest, NetworkError } from '../../../../src/client/error';
+import { userEvent } from '@testing-library/user-event';
+import { render, screen } from '@testing-library/vue';
+import { createRouter, createWebHistory, RouterView } from 'vue-router';
+import { defineComponent } from 'vue';
+
+let mockDeletePetClient: typeof deletePetClient;
+let mockListPetsClient: typeof listPetsClient;
+
+vi.mock('../../../../src/client/pet', () => {
+ return {
+ deletePetClient: (id: string) => {
+ return mockDeletePetClient(id);
+ },
+ listPetsClient: (petListRequest: PetListRequest) => {
+ return mockListPetsClient(petListRequest);
+ },
+ };
+});
+
+vi.mock('../../../../src/component/form/pet-filters-form', () => {
+ return {
+ __esModule: true,
+ PetFiltersForm: defineComponent((props: { httpError: HttpError | undefined; initialPetFilters: PetFilters; submitPetFilters: (petFilters: PetFilters) => void; }) => {
+ const onClick = () => {
+ props.submitPetFilters({ name: 'Brownie' });
+ };
+
+ return () => (
+
+ );
+ }, { props: ['httpError', 'initialPetFilters', 'submitPetFilters'] }),
+ };
+});
+
+vi.mock('../../../../src/component/partial/pagination', () => {
+ return {
+ __esModule: true,
+ Pagination: defineComponent((props: { currentPage: number; totalPages: number; maxPages: number; submitPage: (page: number) => void; }) => {
+ const onClick = () => {
+ props.submitPage(2);
+ };
+
+ return () => (
+
+ );
+ }, { props: ['currentPage', 'totalPages', 'maxPages', 'submitPage'] }),
+ };
+});
+
+test('default minimal', async () => {
+ mockListPetsClient = async (petListRequest: PetListRequest) => {
+ expect(petListRequest).toEqual({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ });
+
+ return {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ count: 1,
+ items: [
+ {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ vaccinations: [],
+ _links: {},
+ },
+ ],
+ _links: {},
+ };
+ };
+
+ mockDeletePetClient = async () => undefined;
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: () => import('../../../../src/component/page/pet/list') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet');
+
+ await screen.findByTestId('page-pet-list');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+
Pet List
+
+
+
+
+
+
+
+
+ 4d783b77-eb09-4603-b99b-f590b605eaa9
+
+
+ 15.08.2005 - 17:52:01
+
+
+ 15.08.2005 - 17:55:01
+
+
+ Brownie
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "
+ `);
+});
+
+test('bad request', async () => {
+ mockListPetsClient = async (petListRequest: PetListRequest) => {
+ expect(petListRequest).toEqual({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ });
+
+ return new Promise((resolve) => resolve(new BadRequest({ title: 'bad request' })));
+ };
+
+ mockDeletePetClient = async () => undefined;
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: () => import('../../../../src/component/page/pet/list') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet');
+
+ await screen.findByTestId('page-pet-list');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('default maximal', async () => {
+ mockListPetsClient = async (petListRequest: PetListRequest) => {
+ expect(petListRequest).toEqual({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ });
+
+ return {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ count: 1,
+ items: [
+ {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {
+ read: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ update: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ delete: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ },
+ },
+ ],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ };
+ };
+
+ mockDeletePetClient = async () => undefined;
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: () => import('../../../../src/component/page/pet/list') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet');
+
+ await screen.findByTestId('page-pet-list');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+
Pet List
+
+
Create
+
+
+
+
+
+
+ 4d783b77-eb09-4603-b99b-f590b605eaa9
+
+
+ 15.08.2005 - 17:52:01
+
+
+ 15.08.2005 - 17:55:01
+
+
+ Brownie
+
+
+ 0001-000
+
+
+
+
+
+
+
+
+
+
+
+
+ "
+ `);
+});
+
+test('delete error', async () => {
+ mockListPetsClient = async (petListRequest: PetListRequest) => {
+ expect(petListRequest).toEqual({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ });
+
+ return {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ count: 1,
+ items: [
+ {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {
+ read: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ update: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ delete: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ },
+ },
+ ],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ };
+ };
+
+ mockDeletePetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new NetworkError({ title: 'network error' });
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: () => import('../../../../src/component/page/pet/list') },
+ ]
+ });
+
+ render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet');
+
+ await screen.findByTestId('page-pet-list');
+
+ const removeButton = await screen.findByTestId('remove-pet-0');
+
+ await userEvent.click(removeButton);
+
+ await screen.findByTestId('http-error');
+
+ expect(formatHtml((await screen.findByTestId('http-error')).outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('delete success', async () => {
+ const petListCalls: Array<{ parameters: [PetListRequest]; return: Promise; }> = [
+ {
+ parameters: [
+ {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ },
+ ],
+ return: Promise.resolve({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ count: 1,
+ items: [
+ {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {
+ read: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ update: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ delete: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ },
+ },
+ ],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ }),
+ },
+ {
+ parameters: [
+ {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ },
+ ],
+ return: Promise.resolve({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ count: 1,
+ items: [
+ {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {
+ read: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ update: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ delete: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ },
+ },
+ ],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ }),
+ },
+ ];
+
+ mockListPetsClient = async (petListRequest: PetListRequest) => {
+ const petListCall = petListCalls.shift();
+ if (!petListCall) {
+ throw new Error('Missing call');
+ }
+
+ expect(petListRequest).toEqual(petListCall.parameters[0]);
+
+ return petListCall.return;
+ };
+
+ mockDeletePetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return undefined;
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: () => import('../../../../src/component/page/pet/list') },
+ ]
+ });
+
+ render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet');
+
+ await screen.findByTestId('page-pet-list');
+
+ const removeButton = await screen.findByTestId('remove-pet-0');
+
+ await userEvent.click(removeButton);
+});
+
+test('submit', async () => {
+ const petListCalls: Array<{ parameters: [PetListRequest]; return: Promise; }> = [
+ {
+ parameters: [
+ {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ },
+ ],
+ return: Promise.resolve({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ count: 1,
+ items: [
+ {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {
+ read: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ update: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ delete: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ },
+ },
+ ],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ }),
+ },
+ {
+ parameters: [
+ {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: { name: 'desc' },
+ },
+ ],
+ return: Promise.resolve({
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: { name: 'desc' },
+ count: 1,
+ items: [
+ {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Blacky',
+ tag: '0002-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {
+ read: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ update: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ delete: { href: '/api/pets/4d783b77-eb09-4603-b99b-f590b605eaa9' },
+ },
+ },
+ ],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ }),
+ },
+ {
+ parameters: [
+ {
+ offset: 0,
+ limit: 10,
+ filters: { name: 'Brownie' },
+ sort: { name: 'desc' },
+ },
+ ],
+ return: Promise.resolve({
+ offset: 0,
+ limit: 10,
+ filters: { name: 'Brownie' },
+ sort: { name: 'desc' },
+ count: 0,
+ items: [],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ }),
+ },
+ {
+ parameters: [
+ {
+ offset: 10,
+ limit: 10,
+ filters: { name: 'Brownie' },
+ sort: { name: 'desc' },
+ },
+ ],
+ return: Promise.resolve({
+ offset: 10,
+ limit: 10,
+ filters: { name: 'Brownie' },
+ sort: { name: 'desc' },
+ count: 0,
+ items: [],
+ _links: {
+ create: { href: '/api/pets' },
+ },
+ }),
+ },
+ ];
+
+ mockListPetsClient = async (petListRequest: PetListRequest) => {
+ const petListCall = petListCalls.shift();
+ if (!petListCall) {
+ throw new Error('Missing call');
+ }
+
+ expect(petListRequest).toEqual(petListCall.parameters[0]);
+
+ return petListCall.return;
+ };
+
+ mockDeletePetClient = async () => undefined;
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: () => import('../../../../src/component/page/pet/list') },
+ ]
+ });
+
+ render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet');
+ await screen.findByTestId('page-pet-list');
+
+ const petSortNameSubmitButton = await screen.findByTestId('pet-sort-name-desc');
+
+ await userEvent.click(petSortNameSubmitButton);
+
+ await screen.findByTestId('page-pet-list');
+
+ const petFiltersFormSubmitButton = await screen.findByTestId('pet-filters-form-submit');
+
+ await userEvent.click(petFiltersFormSubmitButton);
+
+ await screen.findByTestId('page-pet-list');
+
+ const paginationNextButton = await screen.findByTestId('pagination-next');
+
+ await userEvent.click(paginationNextButton);
+});
diff --git a/tests/component/page/pet/read.test.tsx b/tests/component/page/pet/read.test.tsx
new file mode 100644
index 0000000..c0a0ca2
--- /dev/null
+++ b/tests/component/page/pet/read.test.tsx
@@ -0,0 +1,205 @@
+/** @jsxImportSource vue */
+
+import { vi, test, expect } from 'vitest';
+import { formatHtml } from '../../../formatter';
+import { NotFound } from '../../../../src/client/error';
+import { render, screen } from '@testing-library/vue';
+import type { readPetClient } from '../../../../src/client/pet';
+import { createRouter, createWebHistory, RouterView } from 'vue-router';
+import { defineComponent } from 'vue';
+import type { PetResponse } from '../../../../src/model/pet';
+
+let mockReadPetClient: typeof readPetClient;
+
+vi.mock('../../../../src/client/pet', () => {
+ return {
+ readPetClient: (id: string) => {
+ return mockReadPetClient(id);
+ },
+ };
+});
+
+test('not found', async () => {
+ mockReadPetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) => resolve(new NotFound({ title: 'title' })));
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/:id', name: 'PetRead', component: () => import('../../../../src/component/page/pet/read') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ await screen.findByTestId('page-pet-read');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('success without vaccinations', async () => {
+ const petResponse: PetResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [],
+ _links: {},
+ };
+
+ mockReadPetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) => resolve(petResponse));
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/:id', name: 'PetRead', component: () => import('../../../../src/component/page/pet/read') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ await screen.findByTestId('page-pet-read');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+
Pet Read
+
+
+ - Id
+ - 4d783b77-eb09-4603-b99b-f590b605eaa9
+ - CreatedAt
+ - 15.08.2005 - 17:52:01
+ - UpdatedAt
+ - 15.08.2005 - 17:55:01
+ - Name
+ - Brownie
+ - Tag
+ - 0001-000
+ - Vaccinations
+
+
+
+
List
+
+
+ "
+ `);
+});
+
+test('success with vaccinations', async () => {
+ const petResponse: PetResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {},
+ };
+
+ mockReadPetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) => resolve(petResponse));
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/:id', name: 'PetRead', component: () => import('../../../../src/component/page/pet/read') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ await screen.findByTestId('page-pet-read');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+
Pet Read
+
+
+ - Id
+ - 4d783b77-eb09-4603-b99b-f590b605eaa9
+ - CreatedAt
+ - 15.08.2005 - 17:52:01
+ - UpdatedAt
+ - 15.08.2005 - 17:55:01
+ - Name
+ - Brownie
+ - Tag
+ - 0001-000
+ - Vaccinations
+ -
+
+
+
+
+
List
+
+
+ "
+ `);
+});
diff --git a/tests/component/page/pet/update.test.tsx b/tests/component/page/pet/update.test.tsx
new file mode 100644
index 0000000..cad71a8
--- /dev/null
+++ b/tests/component/page/pet/update.test.tsx
@@ -0,0 +1,278 @@
+/** @jsxImportSource vue */
+
+import { vi, test, expect } from 'vitest';
+import type { PetRequest, PetResponse } from '../../../../src/model/pet';
+import { formatHtml } from '../../../formatter';
+import type { HttpError } from '../../../../src/client/error';
+import { NotFound, UnprocessableEntity } from '../../../../src/client/error';
+import type { readPetClient, updatePetClient } from '../../../../src/client/pet';
+import { render, screen } from '@testing-library/vue';
+import { userEvent } from '@testing-library/user-event';
+import { defineComponent } from 'vue';
+import { createRouter, createWebHistory, RouterView } from 'vue-router';
+
+let mockReadPetClient: typeof readPetClient;
+let mockUpdatePetClient: typeof updatePetClient;
+
+vi.mock('../../../../src/client/pet', () => {
+ return {
+ readPetClient: (id: string) => {
+ return mockReadPetClient(id);
+ },
+ updatePetClient: (id: string, pet: PetRequest) => {
+ return mockUpdatePetClient(id, pet);
+ },
+ };
+});
+
+vi.mock('../../../../src/component/form/pet-form', () => {
+ return {
+ __esModule: true,
+ PetForm: defineComponent((props: { httpError: HttpError | undefined; initialPet?: PetRequest; submitPet: (pet: PetRequest) => void; }) => {
+ const onSubmit = () => {
+ props.submitPet({ name: 'Brownie', vaccinations: [] });
+ };
+
+ return () => (
+
+ );
+ }, { props: ['httpError', 'initialPet', 'submitPet'] }),
+ };
+});
+
+test('not found', async () => {
+ mockReadPetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) => resolve(new NotFound({ title: 'title' })));
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/:id/update', name: 'PetUpdate', component: () => import('../../../../src/component/page/pet/update') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9/update');
+
+ await screen.findByTestId('page-pet-update');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('default', async () => {
+ const petResponse: PetResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {},
+ };
+
+ mockReadPetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) => resolve(petResponse));
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/:id/update', name: 'PetUpdate', component: () => import('../../../../src/component/page/pet/update') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9/update');
+
+ await screen.findByTestId('page-pet-update');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('unprocessable entity', async () => {
+ const petResponse: PetResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ _links: {},
+ };
+
+ mockReadPetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) => resolve(petResponse));
+ };
+
+ mockUpdatePetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) =>
+ resolve(new UnprocessableEntity({ title: 'unprocessable entity' })),
+ );
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet/:id/update', name: 'PetUpdate', component: () => import('../../../../src/component/page/pet/update') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9/update');
+
+ const testButton = await screen.findByTestId('pet-form-submit');
+
+ await userEvent.click(testButton);
+
+ await screen.findByTestId('http-error');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+
unprocessable entity
+
+
+
Pet Update
+
List
+
+
+ "
+ `);
+});
+
+test('successful', async () => {
+ const petRequest: PetRequest = {
+ name: 'Brownie',
+ tag: '0001-000',
+ vaccinations: [{ name: 'Rabies' }],
+ };
+
+ const petResponse: PetResponse = {
+ id: '4d783b77-eb09-4603-b99b-f590b605eaa9',
+ createdAt: '2005-08-15T15:52:01+00:00',
+ updatedAt: '2005-08-15T15:55:01+00:00',
+ ...petRequest,
+ _links: {},
+ };
+
+ mockReadPetClient = async (id: string) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ return new Promise((resolve) => resolve(petResponse));
+ };
+
+ mockUpdatePetClient = async (id: string, petRequest: PetRequest) => {
+ expect(id).toBe('4d783b77-eb09-4603-b99b-f590b605eaa9');
+
+ expect(petRequest).toEqual(petRequest);
+
+ return new Promise((resolve) => resolve(petResponse));
+ };
+
+ const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', name: 'Home', component: defineComponent(() => () => ) },
+ { path: '/pet', name: 'PetList', component: defineComponent(() => () => ) },
+ { path: '/pet/:id/update', name: 'PetUpdate', component: () => import('../../../../src/component/page/pet/update') },
+ ]
+ });
+
+ const { container } = render(, {
+ global: {
+ plugins: [router],
+ },
+ });
+
+ await router.push('/pet/4d783b77-eb09-4603-b99b-f590b605eaa9/update');
+
+ const testButton = await screen.findByTestId('pet-form-submit');
+
+ await userEvent.click(testButton);
+
+ await screen.findByTestId('page-pet-list-mock');
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
diff --git a/tests/component/partial/http-error.test.tsx b/tests/component/partial/http-error.test.tsx
new file mode 100644
index 0000000..f960e37
--- /dev/null
+++ b/tests/component/partial/http-error.test.tsx
@@ -0,0 +1,50 @@
+/** @jsxImportSource vue */
+
+import { render } from '@testing-library/vue';
+import { HttpError as HttpErrorPartial } from '../../../src/component/partial/http-error';
+import { test, expect } from 'vitest';
+import { formatHtml } from '../../formatter';
+import { BadRequestOrUnprocessableEntity, HttpError } from '../../../src/client/error';
+
+test('minimal', () => {
+ const httpError = new HttpError({
+ title: 'This is the title',
+ });
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('maximal', () => {
+ const httpError = new BadRequestOrUnprocessableEntity({
+ title: 'This is the title',
+ detail: 'This is the detail',
+ instance: 'This is the instance',
+ invalidParameters: [{ name: 'Invalid Parameter Name', reason: 'Invalid Parameter Reason' }],
+ });
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
This is the title
+
This is the detail
+
This is the instance
+
+ - Invalid Parameter Name: Invalid Parameter Reason
+
+
+
+ "
+ `);
+});
diff --git a/tests/component/partial/pagination.test.tsx b/tests/component/partial/pagination.test.tsx
new file mode 100644
index 0000000..969290f
--- /dev/null
+++ b/tests/component/partial/pagination.test.tsx
@@ -0,0 +1,223 @@
+/** @jsxImportSource vue */
+
+import { render, screen } from '@testing-library/vue';
+import { userEvent } from '@testing-library/user-event';
+import { test, expect } from 'vitest';
+import { formatHtml } from '../../formatter';
+import { Pagination } from '../../../src/component/partial/pagination';
+
+test('max pages 1', () => {
+ const submitPage = (): void => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('total pages 1', () => {
+ const submitPage = (): void => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+ "
+ `);
+});
+
+test('current 1', () => {
+ const submitPage = (): void => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ "
+ `);
+});
+
+test('current 4', () => {
+ const submitPage = (): void => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ "
+ `);
+});
+
+test('current 7', () => {
+ const submitPage = (): void => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ "
+ `);
+});
+
+test('current 10', () => {
+ const submitPage = (): void => { };
+
+ const { container } = render();
+
+ expect(formatHtml(container.outerHTML)).toMatchInlineSnapshot(`
+ "
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ "
+ `);
+});
+
+test('buttons', async () => {
+ const pages: number[] = [];
+
+ const submitPage = (page: number): void => {
+ pages.push(page);
+ };
+
+ render();
+
+ for await (const element of screen.getAllByRole('button')) {
+ await userEvent.click(element);
+ }
+
+ expect(pages).toEqual([1, 6, 4, 5, 6, 7, 8, 9, 10, 8, 10]);
+});
diff --git a/tests/formatter.ts b/tests/formatter.ts
new file mode 100644
index 0000000..4d57bb9
--- /dev/null
+++ b/tests/formatter.ts
@@ -0,0 +1,5 @@
+import { format } from 'prettier';
+
+export const formatHtml = (html: string) => {
+ return format(html, { parser: 'html' });
+};
diff --git a/tests/hook/create-model-resource.test.ts b/tests/hook/create-model-resource.test.ts
new file mode 100644
index 0000000..5970728
--- /dev/null
+++ b/tests/hook/create-model-resource.test.ts
@@ -0,0 +1,291 @@
+import { describe, expect, test } from 'vitest';
+import { createModelResource } from '../../src/hook/create-model-resource';
+import { useFunctionMock } from '@chubbyts/chubbyts-function-mock/dist/function-mock';
+import type { CreateClient, ReadClient, DeleteClient, ListClient, UpdateClient } from '../../src/client/client';
+import type { ModelListRequest, ModelListResponse, ModelRequest, ModelResponse } from '../../src/model/model';
+import { BadRequest } from '../../src/client/error';
+
+describe('createModelResource', () => {
+ describe('list', () => {
+ test('missing client', async () => {
+ const { actions } = createModelResource({});
+
+ try {
+ await actions.listModel({});
+ throw new Error('expect failed');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: Missing listClient]');
+ }
+ });
+
+ test('error', async () => {
+ const badRequest = new BadRequest({ title: 'bad request' });
+
+ const [listClient, listClientMocks] = useFunctionMock>([
+ { parameters: [{}], return: Promise.resolve(badRequest) },
+ ]);
+
+ const { modelList, httpError, actions } = createModelResource({ listClient });
+
+ expect(modelList.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.listModel({})).toBe(false);
+
+ expect(modelList.value).toBeUndefined();
+ expect(httpError.value).toEqual(badRequest);
+
+ expect(listClientMocks.length).toBe(0);
+ });
+
+ test('success', async () => {
+ const modelListResponse: ModelListResponse = {
+ offset: 0,
+ limit: 10,
+ filters: {},
+ sort: {},
+ count: 0,
+ items: [],
+ _links: {},
+ };
+
+ const [listClient, listClientMocks] = useFunctionMock>([
+ { parameters: [{}], return: Promise.resolve(modelListResponse) },
+ ]);
+
+ const { modelList, httpError, actions } = createModelResource({ listClient });
+
+ expect(modelList.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.listModel({})).toBe(true);
+
+ expect(modelList.value).toEqual(modelListResponse);
+ expect(httpError.value).toBeUndefined();
+
+ expect(listClientMocks.length).toBe(0);
+ });
+ });
+
+ describe('create', () => {
+ test('missing client', async () => {
+ const { actions } = createModelResource({});
+
+ try {
+ await actions.createModel({});
+ throw new Error('expect failed');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: Missing createClient]');
+ }
+ });
+
+ test('error', async () => {
+ const badRequest = new BadRequest({ title: 'bad request' });
+
+ const [createClient, createClientMocks] = useFunctionMock>([
+ { parameters: [{}], return: Promise.resolve(badRequest) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ createClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.createModel({})).toBe(false);
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toEqual(badRequest);
+
+ expect(createClientMocks.length).toBe(0);
+ });
+
+ test('success', async () => {
+ const modelResponse: ModelResponse = {
+ id: 'ddbb7edb-8c53-4586-9844-769e1c830719',
+ createdAt: '2022-06-12T20:08:24.793Z',
+ _links: {},
+ };
+
+ const [createClient, createClientMocks] = useFunctionMock>([
+ { parameters: [{}], return: Promise.resolve(modelResponse) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ createClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.createModel({})).toBe(true);
+
+ expect(model.value).toEqual(modelResponse);
+ expect(httpError.value).toBeUndefined();
+
+ expect(createClientMocks.length).toBe(0);
+ });
+ });
+
+ describe('read', () => {
+ test('missing client', async () => {
+ const { actions } = createModelResource({});
+
+ try {
+ await actions.readModel('ddbb7edb-8c53-4586-9844-769e1c830719');
+ throw new Error('expect failed');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: Missing readClient]');
+ }
+ });
+
+ test('error', async () => {
+ const badRequest = new BadRequest({ title: 'bad request' });
+
+ const [readClient, readClientMocks] = useFunctionMock>([
+ { parameters: ['ddbb7edb-8c53-4586-9844-769e1c830719'], return: Promise.resolve(badRequest) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ readClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.readModel('ddbb7edb-8c53-4586-9844-769e1c830719')).toBe(false);
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toEqual(badRequest);
+
+ expect(readClientMocks.length).toBe(0);
+ });
+
+ test('success', async () => {
+ const modelResponse: ModelResponse = {
+ id: 'ddbb7edb-8c53-4586-9844-769e1c830719',
+ createdAt: '2022-06-12T20:08:24.793Z',
+ _links: {},
+ };
+
+ const [readClient, readClientMocks] = useFunctionMock>([
+ { parameters: ['ddbb7edb-8c53-4586-9844-769e1c830719'], return: Promise.resolve(modelResponse) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ readClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.readModel('ddbb7edb-8c53-4586-9844-769e1c830719')).toBe(true);
+
+ expect(model.value).toEqual(modelResponse);
+ expect(httpError.value).toBeUndefined();
+
+ expect(readClientMocks.length).toBe(0);
+ });
+ });
+
+ describe('update', () => {
+ test('missing client', async () => {
+ const { actions } = createModelResource({});
+
+ try {
+ await actions.updateModel('ddbb7edb-8c53-4586-9844-769e1c830719', {});
+ throw new Error('expect failed');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: Missing updateClient]');
+ }
+ });
+
+ test('error', async () => {
+ const badRequest = new BadRequest({ title: 'bad request' });
+
+ const [updateClient, updateClientMocks] = useFunctionMock>([
+ { parameters: ['ddbb7edb-8c53-4586-9844-769e1c830719', {}], return: Promise.resolve(badRequest) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ updateClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.updateModel('ddbb7edb-8c53-4586-9844-769e1c830719', {})).toBe(false);
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toEqual(badRequest);
+
+ expect(updateClientMocks.length).toBe(0);
+ });
+
+ test('success', async () => {
+ const modelResponse: ModelResponse = {
+ id: 'ddbb7edb-8c53-4586-9844-769e1c830719',
+ createdAt: '2022-06-12T20:08:24.793Z',
+ _links: {},
+ };
+
+ const [updateClient, updateClientMocks] = useFunctionMock>([
+ { parameters: ['ddbb7edb-8c53-4586-9844-769e1c830719', {}], return: Promise.resolve(modelResponse) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ updateClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.updateModel('ddbb7edb-8c53-4586-9844-769e1c830719', {})).toBe(true);
+
+ expect(model.value).toEqual(modelResponse);
+ expect(httpError.value).toBeUndefined();
+
+ expect(updateClientMocks.length).toBe(0);
+ });
+ });
+
+ describe('delete', () => {
+ test('missing client', async () => {
+ const { actions } = createModelResource({});
+
+ try {
+ await actions.deleteModel('ddbb7edb-8c53-4586-9844-769e1c830719');
+ throw new Error('expect failed');
+ } catch (e) {
+ expect(e).toMatchInlineSnapshot('[Error: Missing deleteClient]');
+ }
+ });
+
+ test('error', async () => {
+ const badRequest = new BadRequest({ title: 'bad request' });
+
+ const [deleteClient, deleteClientMocks] = useFunctionMock([
+ { parameters: ['ddbb7edb-8c53-4586-9844-769e1c830719'], return: Promise.resolve(badRequest) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ deleteClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.deleteModel('ddbb7edb-8c53-4586-9844-769e1c830719')).toBe(false);
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toEqual(badRequest);
+
+ expect(deleteClientMocks.length).toBe(0);
+ });
+
+ test('success', async () => {
+ const [deleteClient, deleteClientMocks] = useFunctionMock([
+ { parameters: ['ddbb7edb-8c53-4586-9844-769e1c830719'], return: Promise.resolve(undefined) },
+ ]);
+
+ const { model, httpError, actions } = createModelResource({ deleteClient });
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(await actions.deleteModel('ddbb7edb-8c53-4586-9844-769e1c830719')).toBe(true);
+
+ expect(model.value).toBeUndefined();
+ expect(httpError.value).toBeUndefined();
+
+ expect(deleteClientMocks.length).toBe(0);
+ });
+ });
+});
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..ca4c892
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,36 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": [
+ "ES2020",
+ "DOM",
+ "DOM.Iterable"
+ ],
+ "skipLibCheck": true,
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.tsx",
+ "src/**/*.vue"
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.node.json"
+ }
+ ]
+}
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 0000000..97ede7e
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..80bacec
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,24 @@
+///
+///
+
+import { defineConfig } from 'vite';
+import vueJsx from '@vitejs/plugin-vue-jsx';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [vueJsx()],
+ test: {
+ globals: true,
+ environment: 'jsdom',
+ setupFiles: './vitest.setup.ts',
+ include: ['tests/**/*.test.*'],
+ coverage: {
+ all: true,
+ clean: true,
+ reporter: ['text', 'html', 'lcov'],
+ provider: 'v8',
+ include: ['src'],
+ exclude: ['src/index.tsx', 'src/vite-env.d.ts'],
+ },
+ },
+});
diff --git a/vitest.setup.ts b/vitest.setup.ts
new file mode 100644
index 0000000..7b0828b
--- /dev/null
+++ b/vitest.setup.ts
@@ -0,0 +1 @@
+import '@testing-library/jest-dom';