mirror of
https://github.com/CorentinTh/it-tools.git
synced 2026-10-21 21:31:21 +00:00
Merge b2b0af666f into d505845f91
This commit is contained in:
commit
f8977f4ed7
10 changed files with 1720 additions and 191 deletions
43
.github/workflows/e2e-tests.yml
vendored
43
.github/workflows/e2e-tests.yml
vendored
|
|
@ -6,7 +6,7 @@ on:
|
|||
- main
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 90
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
|
|
@ -23,10 +23,10 @@ jobs:
|
|||
|
||||
- name: Get Playwright version
|
||||
id: playwright-version
|
||||
run: echo "PLAYWRIGHT_VERSION=$(jq -r .dependencies.playwright package.json)" >> "$GITHUB_OUTPUT"
|
||||
run: echo "PLAYWRIGHT_VERSION=$(jq -r '.devDependencies["@playwright/test"]' package.json)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --ignore-scripts
|
||||
|
||||
- name: Build app
|
||||
run: pnpm build
|
||||
|
|
@ -40,8 +40,41 @@ jobs:
|
|||
${{ runner.os }}-playwright-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}-
|
||||
${{ runner.os }}-playwright-
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm exec playwright install --with-deps
|
||||
# --with-deps bundles an apt-get run for the full browser dependency
|
||||
# set; the ubuntu archive is intermittently very slow, so it gets its
|
||||
# own step with a generous timeout, retries, and an apt-cache entry so
|
||||
# a one-time successful run seeds later ones
|
||||
- name: Restore apt cache for Playwright dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/apt-playwright-cache
|
||||
key: ${{ runner.os }}-apt-${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}
|
||||
|
||||
- name: Install Playwright system dependencies
|
||||
timeout-minutes: 45
|
||||
run: |
|
||||
for attempt in 1 2 3 4 5; do
|
||||
if timeout 1500 ./node_modules/.bin/playwright install-deps; then
|
||||
exit 0
|
||||
fi
|
||||
echo "playwright install-deps attempt $attempt failed (attempt timeout 25 min), retrying in 20s"
|
||||
sleep 20
|
||||
done
|
||||
exit 1
|
||||
|
||||
- name: Install Playwright browsers
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT: 60000
|
||||
run: |
|
||||
for attempt in 1 2 3; do
|
||||
if ./node_modules/.bin/playwright install; then
|
||||
exit 0
|
||||
fi
|
||||
echo "playwright install attempt $attempt failed, retrying in 15s"
|
||||
sleep 15
|
||||
done
|
||||
exit 1
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: pnpm run test:e2e --shard=${{ matrix.shard }}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@
|
|||
"@antfu/eslint-config": "^0.41.0",
|
||||
"@iconify-json/mdi": "^1.1.50",
|
||||
"@intlify/unplugin-vue-i18n": "^2.0.0",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@playwright/test": "^1.62.1",
|
||||
"@rushstack/eslint-patch": "^1.2.0",
|
||||
"@tsconfig/node18": "^18.2.0",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
|
|
@ -149,5 +149,10 @@
|
|||
"vitest": "^0.34.0",
|
||||
"workbox-window": "^7.0.0",
|
||||
"zx": "^7.2.1"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@vueuse/shared": "10.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
260
pnpm-lock.yaml
generated
260
pnpm-lock.yaml
generated
|
|
@ -4,6 +4,9 @@ settings:
|
|||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
'@vueuse/shared': 10.3.0
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
|
|
@ -49,7 +52,7 @@ importers:
|
|||
version: 10.3.0(vue@3.3.4)
|
||||
'@vueuse/head':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0(typescript@5.2.2)(vue@3.3.4)
|
||||
version: 1.0.0(vue@3.3.4)
|
||||
'@vueuse/router':
|
||||
specifier: ^10.0.0
|
||||
version: 10.0.0(vue-router@4.1.6(vue@3.3.4))(vue@3.3.4)
|
||||
|
|
@ -220,8 +223,8 @@ importers:
|
|||
specifier: ^2.0.0
|
||||
version: 2.0.0(rollup@2.79.2)(vue-i18n@9.9.1(vue@3.3.4))
|
||||
'@playwright/test':
|
||||
specifier: ^1.32.3
|
||||
version: 1.32.3
|
||||
specifier: ^1.62.1
|
||||
version: 1.63.0
|
||||
'@rushstack/eslint-patch':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
|
|
@ -332,7 +335,7 @@ importers:
|
|||
version: 4.0.0
|
||||
vitest:
|
||||
specifier: ^0.34.0
|
||||
version: 0.34.0(jsdom@22.0.0)(less@4.1.3)(terser@5.37.0)
|
||||
version: 0.34.0(jsdom@22.0.0)(less@4.1.3)(playwright@1.63.0)(terser@5.37.0)
|
||||
workbox-window:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
|
|
@ -356,17 +359,20 @@ packages:
|
|||
|
||||
'@antfu/eslint-config-basic@0.41.0':
|
||||
resolution: {integrity: sha512-zcwFv+nEV/NroeeVWriNdnIGd9soOLRG8wIiVz4VVJ0BjONrqQR56HLG/gDxH/1GUYBnQCEcVxGUmegce08cnw==}
|
||||
deprecated: Deprecated, please migrate to @antfu/eslint-config with the flat config
|
||||
peerDependencies:
|
||||
eslint: '>=7.4.0'
|
||||
|
||||
'@antfu/eslint-config-ts@0.41.0':
|
||||
resolution: {integrity: sha512-ng3GYpJGZgrxGwBVda/MgUpveH3LbEqdPCFi1+S5e62W4kf8rmEVbhc0I8w7/aKN0uNqir5SInYg8gob2maDAQ==}
|
||||
deprecated: Deprecated, please migrate to @antfu/eslint-config with the flat config
|
||||
peerDependencies:
|
||||
eslint: '>=7.4.0'
|
||||
typescript: '>=3.9'
|
||||
|
||||
'@antfu/eslint-config-vue@0.41.0':
|
||||
resolution: {integrity: sha512-iJiEGRUgRmT3mQCmGl0hTMwq/ShXRjRPjpgsDcphKJyEF06ZIR/4gxHn+utQRLT2hD39DQN8gk0ZbpV3gWtf/g==}
|
||||
deprecated: Deprecated, please migrate to @antfu/eslint-config with the flat config
|
||||
peerDependencies:
|
||||
eslint: '>=7.4.0'
|
||||
|
||||
|
|
@ -1464,6 +1470,7 @@ packages:
|
|||
'@humanwhocodes/config-array@0.11.10':
|
||||
resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
|
||||
engines: {node: '>=10.10.0'}
|
||||
deprecated: Use @eslint/config-array instead
|
||||
|
||||
'@humanwhocodes/module-importer@1.0.1':
|
||||
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
|
||||
|
|
@ -1471,6 +1478,7 @@ packages:
|
|||
|
||||
'@humanwhocodes/object-schema@1.2.1':
|
||||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||
deprecated: Use @eslint/object-schema instead
|
||||
|
||||
'@iconify-json/mdi@1.1.50':
|
||||
resolution: {integrity: sha512-SgbT5w5eHCdOG74ZWPz7HlTGk6VsifIJhNi6lAsxj/5Nlqt6Cz4LlQmSa9eecU9p075Jub2aAx/o7YI+GCahRQ==}
|
||||
|
|
@ -1626,9 +1634,9 @@ packages:
|
|||
resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==}
|
||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||
|
||||
'@playwright/test@1.32.3':
|
||||
resolution: {integrity: sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==}
|
||||
engines: {node: '>=14'}
|
||||
'@playwright/test@1.63.0':
|
||||
resolution: {integrity: sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==}
|
||||
engines: {node: '>=20'}
|
||||
hasBin: true
|
||||
|
||||
'@polka/url@1.0.0-next.28':
|
||||
|
|
@ -2303,9 +2311,6 @@ packages:
|
|||
'@vue/compiler-core@3.3.7':
|
||||
resolution: {integrity: sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==}
|
||||
|
||||
'@vue/compiler-core@3.5.13':
|
||||
resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
|
||||
|
||||
'@vue/compiler-dom@3.2.47':
|
||||
resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==}
|
||||
|
||||
|
|
@ -2315,18 +2320,12 @@ packages:
|
|||
'@vue/compiler-dom@3.3.7':
|
||||
resolution: {integrity: sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==}
|
||||
|
||||
'@vue/compiler-dom@3.5.13':
|
||||
resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==}
|
||||
|
||||
'@vue/compiler-sfc@3.2.47':
|
||||
resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==}
|
||||
|
||||
'@vue/compiler-sfc@3.3.4':
|
||||
resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.13':
|
||||
resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==}
|
||||
|
||||
'@vue/compiler-ssr@3.2.47':
|
||||
resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==}
|
||||
|
||||
|
|
@ -2336,9 +2335,6 @@ packages:
|
|||
'@vue/compiler-ssr@3.3.7':
|
||||
resolution: {integrity: sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==}
|
||||
|
||||
'@vue/compiler-ssr@3.5.13':
|
||||
resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==}
|
||||
|
||||
'@vue/devtools-api@6.5.0':
|
||||
resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==}
|
||||
|
||||
|
|
@ -2359,21 +2355,12 @@ packages:
|
|||
'@vue/reactivity@3.3.4':
|
||||
resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==}
|
||||
|
||||
'@vue/reactivity@3.5.13':
|
||||
resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==}
|
||||
|
||||
'@vue/runtime-core@3.3.4':
|
||||
resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==}
|
||||
|
||||
'@vue/runtime-core@3.5.13':
|
||||
resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==}
|
||||
|
||||
'@vue/runtime-dom@3.3.4':
|
||||
resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==}
|
||||
|
||||
'@vue/runtime-dom@3.5.13':
|
||||
resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==}
|
||||
|
||||
'@vue/server-renderer@3.3.4':
|
||||
resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==}
|
||||
peerDependencies:
|
||||
|
|
@ -2384,11 +2371,6 @@ packages:
|
|||
peerDependencies:
|
||||
vue: 3.3.7
|
||||
|
||||
'@vue/server-renderer@3.5.13':
|
||||
resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==}
|
||||
peerDependencies:
|
||||
vue: 3.5.13
|
||||
|
||||
'@vue/shared@3.2.47':
|
||||
resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==}
|
||||
|
||||
|
|
@ -2398,9 +2380,6 @@ packages:
|
|||
'@vue/shared@3.3.7':
|
||||
resolution: {integrity: sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==}
|
||||
|
||||
'@vue/shared@3.5.13':
|
||||
resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==}
|
||||
|
||||
'@vue/test-utils@2.3.2':
|
||||
resolution: {integrity: sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==}
|
||||
peerDependencies:
|
||||
|
|
@ -2428,20 +2407,15 @@ packages:
|
|||
peerDependencies:
|
||||
vue-router: '>=4.0.0-rc.1'
|
||||
|
||||
'@vueuse/shared@10.0.0':
|
||||
resolution: {integrity: sha512-Zh3LgJqvUBWVY3SiMvXanTcfAneGbt63QPczBRDNgQ6jd/ehodO9a1lCFzaA6SWJJoI+ugVTjHFYJdoR656DVQ==}
|
||||
|
||||
'@vueuse/shared@10.3.0':
|
||||
resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==}
|
||||
|
||||
'@vueuse/shared@12.0.0':
|
||||
resolution: {integrity: sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==}
|
||||
|
||||
'@zhead/schema@1.0.0-beta.13':
|
||||
resolution: {integrity: sha512-P1A1vRGFBhITco8Iw4/hvnDYoE/SoVrd71dW1pBFdXJb3vP+pBtoOuhbEKy0ROJGOyzQuqvFibcwzyLlWMqNiQ==}
|
||||
|
||||
abab@2.0.6:
|
||||
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
|
||||
deprecated: Use your platform's native atob() and btoa() methods instead
|
||||
|
||||
abbrev@1.1.1:
|
||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
||||
|
|
@ -2552,6 +2526,7 @@ packages:
|
|||
|
||||
babel-merge@3.0.0:
|
||||
resolution: {integrity: sha512-eBOBtHnzt9xvnjpYNI5HmaPp/b2vMveE5XggzqHnQeHJ8mFIBrBv6WZEVIj5jJ2uwTItkqKo9gWzEEcBxEq0yw==}
|
||||
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
|
||||
|
|
@ -2798,7 +2773,7 @@ packages:
|
|||
hasBin: true
|
||||
|
||||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
confbox@0.1.8:
|
||||
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
|
||||
|
|
@ -2850,6 +2825,7 @@ packages:
|
|||
|
||||
crypto-js@4.1.1:
|
||||
resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==}
|
||||
deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained.
|
||||
|
||||
crypto-random-string@2.0.0:
|
||||
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
|
||||
|
|
@ -2896,9 +2872,6 @@ packages:
|
|||
csstype@3.1.2:
|
||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||
|
||||
csstype@3.1.3:
|
||||
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||
|
||||
dash-get@1.0.2:
|
||||
resolution: {integrity: sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==}
|
||||
|
||||
|
|
@ -3054,6 +3027,7 @@ packages:
|
|||
domexception@4.0.0:
|
||||
resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Use your platform's native DOMException instead
|
||||
|
||||
domhandler@5.0.3:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
|
|
@ -3246,6 +3220,7 @@ packages:
|
|||
eslint-plugin-i@2.28.0-2:
|
||||
resolution: {integrity: sha512-z48kG4qmE4TmiLcxbmvxMT5ycwvPkXaWW0XpU1L768uZaTbiDbxsHMEdV24JHlOR1xDsPpKW39BfP/pRdYIwFA==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Please migrate to the brand new `eslint-plugin-import-x` instead
|
||||
peerDependencies:
|
||||
eslint: ^7.2.0 || ^8
|
||||
|
||||
|
|
@ -3271,6 +3246,7 @@ packages:
|
|||
eslint-plugin-markdown@3.0.1:
|
||||
resolution: {integrity: sha512-8rqoc148DWdGdmYF6WSQFT3uQ6PO7zXYgeBpHAOAakX/zpq+NvFYbDA/H7PYzHajwtmaOzAwfxyl++x0g1/N9A==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
deprecated: Please use @eslint/markdown instead
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
|
||||
|
|
@ -3337,6 +3313,7 @@ packages:
|
|||
eslint@8.47.0:
|
||||
resolution: {integrity: sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
|
||||
hasBin: true
|
||||
|
||||
espree@9.6.1:
|
||||
|
|
@ -3499,11 +3476,6 @@ packages:
|
|||
fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
fsevents@2.3.2:
|
||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
|
|
@ -3566,10 +3538,12 @@ packages:
|
|||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
glob@8.1.0:
|
||||
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
globals@11.12.0:
|
||||
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
|
||||
|
|
@ -3758,6 +3732,7 @@ packages:
|
|||
|
||||
inflight@1.0.6:
|
||||
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
||||
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
|
||||
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
|
@ -4172,6 +4147,7 @@ packages:
|
|||
|
||||
loupe@2.3.6:
|
||||
resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==}
|
||||
deprecated: Please upgrade to 2.3.7 which fixes GHSA-4q6p-r6v2-jvc5
|
||||
|
||||
lower-case-first@1.0.2:
|
||||
resolution: {integrity: sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==}
|
||||
|
|
@ -4380,6 +4356,7 @@ packages:
|
|||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
deprecated: Use your platform's native DOMException instead
|
||||
|
||||
node-fetch-native@1.6.4:
|
||||
resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==}
|
||||
|
|
@ -4610,10 +4587,16 @@ packages:
|
|||
plausible-tracker@0.3.8:
|
||||
resolution: {integrity: sha512-lmOWYQ7s9KOUJ1R+YTOR3HrjdbxIS2Z4de0P/Jx2dQPteznJl2eX3tXxKClpvbfyGP59B5bbhW8ftN59HbbFSg==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
|
||||
|
||||
playwright-core@1.32.3:
|
||||
resolution: {integrity: sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==}
|
||||
engines: {node: '>=14'}
|
||||
playwright-core@1.63.0:
|
||||
resolution: {integrity: sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==}
|
||||
engines: {node: '>=20'}
|
||||
hasBin: true
|
||||
|
||||
playwright@1.63.0:
|
||||
resolution: {integrity: sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==}
|
||||
engines: {node: '>=20'}
|
||||
hasBin: true
|
||||
|
||||
pluralize@8.0.0:
|
||||
|
|
@ -4868,10 +4851,6 @@ packages:
|
|||
resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==}
|
||||
hasBin: true
|
||||
|
||||
resolve@1.22.8:
|
||||
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
|
||||
hasBin: true
|
||||
|
||||
resolve@1.22.9:
|
||||
resolution: {integrity: sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==}
|
||||
hasBin: true
|
||||
|
|
@ -4894,6 +4873,7 @@ packages:
|
|||
|
||||
rimraf@3.0.2:
|
||||
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
||||
hasBin: true
|
||||
|
||||
rollup@2.79.2:
|
||||
|
|
@ -5071,9 +5051,11 @@ packages:
|
|||
source-map@0.8.0-beta.0:
|
||||
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
||||
engines: {node: '>= 8'}
|
||||
deprecated: The work that was done in this beta branch won't be included in future versions
|
||||
|
||||
sourcemap-codec@1.4.8:
|
||||
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
||||
deprecated: Please use @jridgewell/sourcemap-codec instead
|
||||
|
||||
spdx-correct@3.2.0:
|
||||
resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
|
||||
|
|
@ -5544,6 +5526,7 @@ packages:
|
|||
|
||||
uuid@9.0.0:
|
||||
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
|
||||
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
|
||||
hasBin: true
|
||||
|
||||
validate-npm-package-license@3.0.4:
|
||||
|
|
@ -5569,6 +5552,7 @@ packages:
|
|||
|
||||
vite-plugin-vue-markdown@0.23.5:
|
||||
resolution: {integrity: sha512-NXTZ4y+n691gLPWayMBbh4jldQeaqDp9e9WjWUYbn9obsLqS9qU+hr4RAruDq5kP4siTOp7JDV34Sw5eA7WxLg==}
|
||||
deprecated: '`vite-plugin-vue-markdown` is renamed to `unplugin-vue-markdown`. For usages in Vite, you also need to change the import path to `unplugin-vue-markdown/vite`.'
|
||||
peerDependencies:
|
||||
vite: ^2.0.0 || ^3.0.0-0 || ^4.0.0
|
||||
|
||||
|
|
@ -5675,6 +5659,7 @@ packages:
|
|||
vue-i18n@9.9.1:
|
||||
resolution: {integrity: sha512-xyQ4VspLdNSPTKBFBPWa1tvtj+9HuockZwgFeD2OhxxXuC2CWeNvV4seu2o9+vbQOyQbhAM5Ez56oxUrrnTWdw==}
|
||||
engines: {node: '>= 16'}
|
||||
deprecated: v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
|
|
@ -5701,14 +5686,6 @@ packages:
|
|||
vue@3.3.4:
|
||||
resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==}
|
||||
|
||||
vue@3.5.13:
|
||||
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
vuedraggable@4.1.0:
|
||||
resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==}
|
||||
peerDependencies:
|
||||
|
|
@ -5754,6 +5731,7 @@ packages:
|
|||
whatwg-encoding@2.0.0:
|
||||
resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
|
||||
|
||||
whatwg-mimetype@3.0.0:
|
||||
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
|
||||
|
|
@ -6117,7 +6095,7 @@ snapshots:
|
|||
'@babel/traverse': 7.23.2
|
||||
'@babel/types': 7.23.0
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 6.3.1
|
||||
|
|
@ -7030,7 +7008,7 @@ snapshots:
|
|||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
'@babel/parser': 7.23.0
|
||||
'@babel/types': 7.23.0
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
|
@ -7401,7 +7379,7 @@ snapshots:
|
|||
|
||||
'@linaria/logger@4.0.0':
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
picocolors: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
|
@ -7462,12 +7440,9 @@ snapshots:
|
|||
tiny-glob: 0.2.9
|
||||
tslib: 2.5.0
|
||||
|
||||
'@playwright/test@1.32.3':
|
||||
'@playwright/test@1.63.0':
|
||||
dependencies:
|
||||
'@types/node': 18.15.11
|
||||
playwright-core: 1.32.3
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
playwright: 1.63.0
|
||||
|
||||
'@polka/url@1.0.0-next.28': {}
|
||||
|
||||
|
|
@ -7922,7 +7897,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 6.4.1(typescript@5.2.2)
|
||||
'@typescript-eslint/utils': 6.4.1(eslint@8.47.0)(typescript@5.2.2)
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
eslint: 8.47.0
|
||||
ts-api-utils: 1.0.1(typescript@5.2.2)
|
||||
optionalDependencies:
|
||||
|
|
@ -7940,10 +7915,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 5.60.0
|
||||
'@typescript-eslint/visitor-keys': 5.60.0
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.5.4
|
||||
semver: 7.6.3
|
||||
tsutils: 3.21.0(typescript@5.2.2)
|
||||
optionalDependencies:
|
||||
typescript: 5.2.2
|
||||
|
|
@ -7954,10 +7929,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 6.4.1
|
||||
'@typescript-eslint/visitor-keys': 6.4.1
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.5.4
|
||||
semver: 7.6.3
|
||||
ts-api-utils: 1.0.1(typescript@5.2.2)
|
||||
optionalDependencies:
|
||||
typescript: 5.2.2
|
||||
|
|
@ -7968,10 +7943,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 6.9.1
|
||||
'@typescript-eslint/visitor-keys': 6.9.1
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.5.4
|
||||
semver: 7.6.3
|
||||
ts-api-utils: 1.0.1(typescript@5.2.2)
|
||||
optionalDependencies:
|
||||
typescript: 5.2.2
|
||||
|
|
@ -7988,7 +7963,7 @@ snapshots:
|
|||
'@typescript-eslint/typescript-estree': 5.60.0(typescript@5.2.2)
|
||||
eslint: 8.47.0
|
||||
eslint-scope: 5.1.1
|
||||
semver: 7.5.4
|
||||
semver: 7.6.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
|
@ -8002,7 +7977,7 @@ snapshots:
|
|||
'@typescript-eslint/types': 6.4.1
|
||||
'@typescript-eslint/typescript-estree': 6.4.1(typescript@5.2.2)
|
||||
eslint: 8.47.0
|
||||
semver: 7.5.4
|
||||
semver: 7.6.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
|
@ -8049,15 +8024,15 @@ snapshots:
|
|||
dependencies:
|
||||
'@unhead/schema': 0.5.1
|
||||
|
||||
'@unhead/vue@0.5.1(typescript@5.2.2)(vue@3.3.4)':
|
||||
'@unhead/vue@0.5.1(vue@3.3.4)':
|
||||
dependencies:
|
||||
'@unhead/dom': 0.5.1
|
||||
'@unhead/schema': 0.5.1
|
||||
'@vueuse/shared': 12.0.0(typescript@5.2.2)
|
||||
'@vueuse/shared': 10.3.0(vue@3.3.4)
|
||||
unhead: 0.5.1
|
||||
vue: 3.3.4
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
- '@vue/composition-api'
|
||||
|
||||
'@unocss/astro@0.65.1(rollup@2.79.2)(vite@4.4.9(@types/node@18.15.11)(less@4.1.3)(terser@5.37.0))(vue@3.3.4)':
|
||||
dependencies:
|
||||
|
|
@ -8341,14 +8316,6 @@ snapshots:
|
|||
source-map-js: 1.0.2
|
||||
optional: true
|
||||
|
||||
'@vue/compiler-core@3.5.13':
|
||||
dependencies:
|
||||
'@babel/parser': 7.26.3
|
||||
'@vue/shared': 3.5.13
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-dom@3.2.47':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.2.47
|
||||
|
|
@ -8365,11 +8332,6 @@ snapshots:
|
|||
'@vue/shared': 3.3.7
|
||||
optional: true
|
||||
|
||||
'@vue/compiler-dom@3.5.13':
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
|
||||
'@vue/compiler-sfc@3.2.47':
|
||||
dependencies:
|
||||
'@babel/parser': 7.21.4
|
||||
|
|
@ -8396,18 +8358,6 @@ snapshots:
|
|||
postcss: 8.4.28
|
||||
source-map-js: 1.0.2
|
||||
|
||||
'@vue/compiler-sfc@3.5.13':
|
||||
dependencies:
|
||||
'@babel/parser': 7.26.3
|
||||
'@vue/compiler-core': 3.5.13
|
||||
'@vue/compiler-dom': 3.5.13
|
||||
'@vue/compiler-ssr': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.15
|
||||
postcss: 8.4.49
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@vue/compiler-ssr@3.2.47':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.2.47
|
||||
|
|
@ -8424,11 +8374,6 @@ snapshots:
|
|||
'@vue/shared': 3.3.7
|
||||
optional: true
|
||||
|
||||
'@vue/compiler-ssr@3.5.13':
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
|
||||
'@vue/devtools-api@6.5.0': {}
|
||||
|
||||
'@vue/language-core@1.8.1(typescript@5.2.2)':
|
||||
|
|
@ -8464,33 +8409,17 @@ snapshots:
|
|||
dependencies:
|
||||
'@vue/shared': 3.3.4
|
||||
|
||||
'@vue/reactivity@3.5.13':
|
||||
dependencies:
|
||||
'@vue/shared': 3.5.13
|
||||
|
||||
'@vue/runtime-core@3.3.4':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
|
||||
'@vue/runtime-core@3.5.13':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
|
||||
'@vue/runtime-dom@3.3.4':
|
||||
dependencies:
|
||||
'@vue/runtime-core': 3.3.4
|
||||
'@vue/shared': 3.3.4
|
||||
csstype: 3.1.2
|
||||
|
||||
'@vue/runtime-dom@3.5.13':
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.5.13
|
||||
'@vue/runtime-core': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
csstype: 3.1.3
|
||||
|
||||
'@vue/server-renderer@3.3.4(vue@3.3.4)':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.3.4
|
||||
|
|
@ -8504,12 +8433,6 @@ snapshots:
|
|||
vue: 3.3.4
|
||||
optional: true
|
||||
|
||||
'@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.2.2))':
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.5.13
|
||||
'@vue/shared': 3.5.13
|
||||
vue: 3.5.13(typescript@5.2.2)
|
||||
|
||||
'@vue/shared@3.2.47': {}
|
||||
|
||||
'@vue/shared@3.3.4': {}
|
||||
|
|
@ -8517,8 +8440,6 @@ snapshots:
|
|||
'@vue/shared@3.3.7':
|
||||
optional: true
|
||||
|
||||
'@vue/shared@3.5.13': {}
|
||||
|
||||
'@vue/test-utils@2.3.2(vue@3.3.4)':
|
||||
dependencies:
|
||||
js-beautify: 1.14.6
|
||||
|
|
@ -8546,33 +8467,26 @@ snapshots:
|
|||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/head@1.0.0(typescript@5.2.2)(vue@3.3.4)':
|
||||
'@vueuse/head@1.0.0(vue@3.3.4)':
|
||||
dependencies:
|
||||
'@unhead/schema': 0.5.1
|
||||
'@unhead/ssr': 0.5.1
|
||||
'@unhead/vue': 0.5.1(typescript@5.2.2)(vue@3.3.4)
|
||||
'@unhead/vue': 0.5.1(vue@3.3.4)
|
||||
vue: 3.3.4
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
- '@vue/composition-api'
|
||||
|
||||
'@vueuse/metadata@10.3.0': {}
|
||||
|
||||
'@vueuse/router@10.0.0(vue-router@4.1.6(vue@3.3.4))(vue@3.3.4)':
|
||||
dependencies:
|
||||
'@vueuse/shared': 10.0.0(vue@3.3.4)
|
||||
'@vueuse/shared': 10.3.0(vue@3.3.4)
|
||||
vue-demi: 0.14.5(vue@3.3.4)
|
||||
vue-router: 4.1.6(vue@3.3.4)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/shared@10.0.0(vue@3.3.4)':
|
||||
dependencies:
|
||||
vue-demi: 0.14.5(vue@3.3.4)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/shared@10.3.0(vue@3.3.4)':
|
||||
dependencies:
|
||||
vue-demi: 0.14.5(vue@3.3.4)
|
||||
|
|
@ -8580,12 +8494,6 @@ snapshots:
|
|||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@vueuse/shared@12.0.0(typescript@5.2.2)':
|
||||
dependencies:
|
||||
vue: 3.5.13(typescript@5.2.2)
|
||||
transitivePeerDependencies:
|
||||
- typescript
|
||||
|
||||
'@zhead/schema@1.0.0-beta.13': {}
|
||||
|
||||
abab@2.0.6: {}
|
||||
|
|
@ -8780,7 +8688,7 @@ snapshots:
|
|||
|
||||
builtins@5.0.1:
|
||||
dependencies:
|
||||
semver: 7.5.4
|
||||
semver: 7.6.3
|
||||
|
||||
bundle-require@5.0.0(esbuild@0.23.1):
|
||||
dependencies:
|
||||
|
|
@ -9084,8 +8992,6 @@ snapshots:
|
|||
|
||||
csstype@3.1.2: {}
|
||||
|
||||
csstype@3.1.3: {}
|
||||
|
||||
dash-get@1.0.2: {}
|
||||
|
||||
data-uri-to-buffer@4.0.1: {}
|
||||
|
|
@ -9817,9 +9723,6 @@ snapshots:
|
|||
|
||||
fs.realpath@1.0.0: {}
|
||||
|
||||
fsevents@2.3.2:
|
||||
optional: true
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
|
|
@ -10753,7 +10656,7 @@ snapshots:
|
|||
normalize-package-data@2.5.0:
|
||||
dependencies:
|
||||
hosted-git-info: 2.8.9
|
||||
resolve: 1.22.8
|
||||
resolve: 1.22.9
|
||||
semver: 5.7.2
|
||||
validate-npm-package-license: 3.0.4
|
||||
|
||||
|
|
@ -10972,7 +10875,11 @@ snapshots:
|
|||
|
||||
plausible-tracker@0.3.8: {}
|
||||
|
||||
playwright-core@1.32.3: {}
|
||||
playwright-core@1.63.0: {}
|
||||
|
||||
playwright@1.63.0:
|
||||
dependencies:
|
||||
playwright-core: 1.63.0
|
||||
|
||||
pluralize@8.0.0: {}
|
||||
|
||||
|
|
@ -11271,12 +11178,6 @@ snapshots:
|
|||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
resolve@1.22.8:
|
||||
dependencies:
|
||||
is-core-module: 2.13.1
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
resolve@1.22.9:
|
||||
dependencies:
|
||||
is-core-module: 2.16.0
|
||||
|
|
@ -12073,7 +11974,7 @@ snapshots:
|
|||
less: 4.1.3
|
||||
terser: 5.37.0
|
||||
|
||||
vitest@0.34.0(jsdom@22.0.0)(less@4.1.3)(terser@5.37.0):
|
||||
vitest@0.34.0(jsdom@22.0.0)(less@4.1.3)(playwright@1.63.0)(terser@5.37.0):
|
||||
dependencies:
|
||||
'@types/chai': 4.3.5
|
||||
'@types/chai-subset': 1.3.3
|
||||
|
|
@ -12101,6 +12002,7 @@ snapshots:
|
|||
why-is-node-running: 2.2.2
|
||||
optionalDependencies:
|
||||
jsdom: 22.0.0
|
||||
playwright: 1.63.0
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
|
|
@ -12125,14 +12027,14 @@ snapshots:
|
|||
|
||||
vue-eslint-parser@9.3.1(eslint@8.47.0):
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
eslint: 8.47.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.5.4
|
||||
semver: 7.6.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -12180,16 +12082,6 @@ snapshots:
|
|||
'@vue/server-renderer': 3.3.4(vue@3.3.4)
|
||||
'@vue/shared': 3.3.4
|
||||
|
||||
vue@3.5.13(typescript@5.2.2):
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.13
|
||||
'@vue/compiler-sfc': 3.5.13
|
||||
'@vue/runtime-dom': 3.5.13
|
||||
'@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.2.2))
|
||||
'@vue/shared': 3.5.13
|
||||
optionalDependencies:
|
||||
typescript: 5.2.2
|
||||
|
||||
vuedraggable@4.1.0(vue@3.3.4):
|
||||
dependencies:
|
||||
sortablejs: 1.14.0
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import { tool as httpStatusCodes } from './http-status-codes';
|
|||
import { tool as yamlToJson } from './yaml-to-json-converter';
|
||||
import { tool as jsonToYaml } from './json-to-yaml-converter';
|
||||
import { tool as ipv6UlaGenerator } from './ipv6-ula-generator';
|
||||
import { tool as ipv6SubnetCalculator } from './ipv6-subnet-calculator';
|
||||
import { tool as ipv4AddressConverter } from './ipv4-address-converter';
|
||||
import { tool as benchmarkBuilder } from './benchmark-builder';
|
||||
import { tool as userAgentParser } from './user-agent-parser';
|
||||
|
|
@ -164,7 +165,7 @@ export const toolsByCategory: ToolCategory[] = [
|
|||
},
|
||||
{
|
||||
name: 'Network',
|
||||
components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
|
||||
components: [ipv4SubnetCalculator, ipv6SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
|
||||
},
|
||||
{
|
||||
name: 'Math',
|
||||
|
|
|
|||
12
src/tools/ipv6-subnet-calculator/index.ts
Normal file
12
src/tools/ipv6-subnet-calculator/index.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { Api } from '@vicons/tabler';
|
||||
import { defineTool } from '../tool';
|
||||
|
||||
export const tool = defineTool({
|
||||
name: 'IPv6 subnet calculator',
|
||||
path: '/ipv6-subnet-calculator',
|
||||
description: 'Expand, compress and dissect IPv6 addresses: network bounds, address count, netmask and address type',
|
||||
keywords: ['ipv6', 'subnet', 'cidr', 'calculator', 'network', 'address', 'prefix'],
|
||||
component: () => import('./ipv6-subnet-calculator.vue'),
|
||||
icon: Api,
|
||||
createdAt: new Date('2026-10-01'),
|
||||
});
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Differential test: the IPv6 calculator must agree with Python's `ipaddress`
|
||||
// stdlib on 124 random + hand-picked cases (fixture generated by CPython).
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { describeIpv6 } from './ipv6-subnet-calculator.models';
|
||||
|
||||
interface FixtureCase {
|
||||
input: string
|
||||
expanded: string
|
||||
compressed: string
|
||||
network: string
|
||||
first: string
|
||||
last: string
|
||||
total: string
|
||||
netmask: string
|
||||
}
|
||||
|
||||
const cases: FixtureCase[] = JSON.parse(
|
||||
readFileSync(new URL('./ipv6.fixture.json', import.meta.url), 'utf8'),
|
||||
);
|
||||
|
||||
// Python's ipaddress uses lowercase hex for IPv6 str(); my implementation is
|
||||
// lowercase per RFC 5952 §4.3 recommendation. Normalize for comparison.
|
||||
const lower = (s: string) => s.toLowerCase();
|
||||
|
||||
describe('ipv6-subnet-calculator: differential vs CPython ipaddress', () => {
|
||||
it.each(cases.map(c => [c.input, c]))('case %s', (_input, c) => {
|
||||
const info = describeIpv6(c.input);
|
||||
expect(lower(info.expanded)).toBe(lower(c.expanded));
|
||||
// compression: compare the network VALUE (Python may pick a different
|
||||
// zero-run on ties; the address itself must match) plus the prefix
|
||||
expect(lower(info.network.split('/')[0])).toBe(lower(c.network.split('/')[0]));
|
||||
expect(info.network.endsWith(`/${c.network.split('/')[1]}`)).toBe(true);
|
||||
expect(lower(info.firstAddress)).toBe(lower(c.first));
|
||||
expect(lower(info.lastAddress)).toBe(lower(c.last));
|
||||
expect(info.totalAddresses).toBe(c.total);
|
||||
expect(lower(info.mask)).toBe(lower(c.netmask));
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { compressIpv6, describeIpv6, expandIpv6 } from './ipv6-subnet-calculator.models';
|
||||
|
||||
describe('ipv6-subnet-calculator: expansion', () => {
|
||||
it('expands compressed forms', () => {
|
||||
expect(expandIpv6('2001:db8::1')).toBe('2001:0db8:0000:0000:0000:0000:0000:0001');
|
||||
expect(expandIpv6('::1')).toBe('0000:0000:0000:0000:0000:0000:0000:0001');
|
||||
expect(expandIpv6('::')).toBe('0000:0000:0000:0000:0000:0000:0000:0000');
|
||||
expect(expandIpv6('fe80::1%eth0')).toBe('fe80:0000:0000:0000:0000:0000:0000:0001');
|
||||
});
|
||||
|
||||
it('passes already-expanded addresses through', () => {
|
||||
expect(expandIpv6('2001:0DB8:0:0:0:0:0:1')).toBe('2001:0db8:0000:0000:0000:0000:0000:0001');
|
||||
});
|
||||
|
||||
it('rejects malformed addresses', () => {
|
||||
expect(() => expandIpv6('2001::db8::1')).toThrow('Invalid IPv6');
|
||||
expect(() => expandIpv6('12345::')).toThrow('Invalid IPv6');
|
||||
expect(() => expandIpv6('2001:db8:0:0:0:0:0')).toThrow('Invalid IPv6');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ipv6-subnet-calculator: compression', () => {
|
||||
it('compresses the longest zero run once', () => {
|
||||
expect(compressIpv6('2001:0db8:0000:0000:0000:0000:0000:0001')).toBe('2001:db8::1');
|
||||
expect(compressIpv6('0000:0000:0000:0000:0000:0000:0000:0001')).toBe('::1');
|
||||
// leftmost of two equal runs
|
||||
// the trailing 4-zero run is the longest, so it is compressed
|
||||
expect(compressIpv6('0000:0000:0001:0002:0000:0000:0000:0000')).toBe('0:0:1:2::');
|
||||
// a single zero group is not compressed
|
||||
expect(compressIpv6('2001:0db8:0000:000a:000b:000c:000d:000e')).toBe('2001:db8:0:a:b:c:d:e');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ipv6-subnet-calculator: subnet math', () => {
|
||||
it('computes network bounds for a /48', () => {
|
||||
const info = describeIpv6('2001:db8:1234:5678::1/48');
|
||||
expect(info.network).toBe('2001:db8:1234::/48');
|
||||
expect(info.firstAddress).toBe('2001:db8:1234::');
|
||||
expect(info.lastAddress).toBe('2001:db8:1234:ffff:ffff:ffff:ffff:ffff');
|
||||
expect(info.totalAddresses).toBe((2n ** 80n).toString());
|
||||
expect(info.mask).toBe('ffff:ffff:ffff::');
|
||||
});
|
||||
|
||||
it('handles the host address itself at /128', () => {
|
||||
const info = describeIpv6('::1/128');
|
||||
expect(info.network).toBe('::1/128');
|
||||
expect(info.firstAddress).toBe('::1');
|
||||
expect(info.lastAddress).toBe('::1');
|
||||
expect(info.totalAddresses).toBe('1');
|
||||
});
|
||||
|
||||
it('handles the whole space at /0', () => {
|
||||
const info = describeIpv6('2001:db8::1/0');
|
||||
expect(info.network).toBe('::/0');
|
||||
expect(info.firstAddress).toBe('::');
|
||||
expect(info.lastAddress).toBe('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff');
|
||||
expect(info.totalAddresses).toBe((2n ** 128n).toString());
|
||||
});
|
||||
|
||||
it('classifies common address types', () => {
|
||||
expect(describeIpv6('2001:db8::1/64').type).toContain('Documentation');
|
||||
expect(describeIpv6('fe80::1/64').type).toContain('Link-local');
|
||||
expect(describeIpv6('::1/128').type).toBe('Loopback');
|
||||
expect(describeIpv6('ff02::1/64').type).toContain('Multicast');
|
||||
expect(describeIpv6('fd00::1/64').type).toContain('Unique local');
|
||||
});
|
||||
|
||||
it('rejects invalid prefixes', () => {
|
||||
expect(() => describeIpv6('2001:db8::1/129')).toThrow('Invalid prefix');
|
||||
expect(() => describeIpv6('2001:db8::1/-1')).toThrow('Invalid prefix');
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
export interface Ipv6Info {
|
||||
/** Fully expanded lowercase form, e.g. 2001:0db8:0000:...:0000. */
|
||||
expanded: string
|
||||
/** RFC 5952 compressed form, e.g. 2001:db8::1. */
|
||||
compressed: string
|
||||
/** `prefix` as typed, normalized. */
|
||||
network: string
|
||||
prefix: number
|
||||
type: string
|
||||
scope: string
|
||||
totalAddresses: string
|
||||
firstAddress: string
|
||||
lastAddress: string
|
||||
mask: string
|
||||
}
|
||||
|
||||
const IPV6_HEX_RE = /^[0-9a-fA-F]{1,4}$/;
|
||||
|
||||
/** Expand an address (without prefix) to the full 39-char lowercase form. */
|
||||
export function expandIpv6(address: string): string {
|
||||
let value = address.trim().toLowerCase();
|
||||
if (value.includes('%')) {
|
||||
value = value.slice(0, value.indexOf('%')); // drop zone id
|
||||
}
|
||||
|
||||
const parts = value.split('::');
|
||||
if (parts.length > 2) {
|
||||
throw new Error(`Invalid IPv6 address: ${address}`);
|
||||
}
|
||||
|
||||
const head = parts[0] === '' ? [] : parts[0]!.split(':');
|
||||
const tail = parts.length === 2 ? (parts[1] === '' ? [] : parts[1]!.split(':')) : [];
|
||||
const missing = 8 - head.length - tail.length;
|
||||
if (parts.length === 1 && head.length !== 8) {
|
||||
throw new Error(`Invalid IPv6 address: ${address}`);
|
||||
}
|
||||
if (missing < 0) {
|
||||
throw new Error(`Invalid IPv6 address: ${address}`);
|
||||
}
|
||||
const groups = [...head, ...Array.from({ length: parts.length === 2 ? missing : 0 }, () => '0'), ...tail];
|
||||
if (groups.length !== 8 || !groups.every(group => IPV6_HEX_RE.test(group))) {
|
||||
throw new Error(`Invalid IPv6 address: ${address}`);
|
||||
}
|
||||
return groups.map(group => group.padStart(4, '0')).join(':');
|
||||
}
|
||||
|
||||
/** RFC 5952 compression: longest :: run, leftmost on tie, drop leading zeros. */
|
||||
export function compressIpv6(expanded: string): string {
|
||||
const groups = expanded.split(':');
|
||||
const best = { start: -1, length: 0 };
|
||||
let currentStart = -1;
|
||||
let currentLength = 0;
|
||||
groups.forEach((group, index) => {
|
||||
if (group === '0000') {
|
||||
if (currentStart === -1) {
|
||||
currentStart = index;
|
||||
}
|
||||
currentLength++;
|
||||
if (currentLength > best.length) {
|
||||
best.start = currentStart;
|
||||
best.length = currentLength;
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentStart = -1;
|
||||
currentLength = 0;
|
||||
}
|
||||
});
|
||||
|
||||
const trimmed = groups.map(group => group.replace(/^0+(?=.)/, ''));
|
||||
if (best.length < 2) {
|
||||
return trimmed.join(':');
|
||||
}
|
||||
const head = trimmed.slice(0, best.start).join(':');
|
||||
const tail = trimmed.slice(best.start + best.length).join(':');
|
||||
return `${head}::${tail}`;
|
||||
}
|
||||
|
||||
function ipv6ToBigInt(expanded: string): bigint {
|
||||
return BigInt(`0x${expanded.replace(/:/g, '')}`);
|
||||
}
|
||||
|
||||
function bigIntToIpv6(value: bigint): string {
|
||||
const hex = value.toString(16).padStart(32, '0');
|
||||
return (hex.match(/.{4}/g) ?? []).join(':');
|
||||
}
|
||||
|
||||
function parseIpv6Cidr(input: string): { address: string; prefix: number } {
|
||||
const trimmed = input.trim();
|
||||
const [address, prefixRaw] = trimmed.split('/');
|
||||
const prefix = prefixRaw === undefined ? 128 : Number(prefixRaw);
|
||||
if (!Number.isInteger(prefix) || prefix < 0 || prefix > 128) {
|
||||
throw new Error(`Invalid prefix length: ${prefixRaw ?? ''}`);
|
||||
}
|
||||
return { address: expandIpv6(address ?? ''), prefix };
|
||||
}
|
||||
|
||||
function describeType(expanded: string): { type: string; scope: string } {
|
||||
const value = ipv6ToBigInt(expanded);
|
||||
const first16 = Number(value >> 112n);
|
||||
|
||||
if (value === 0n) {
|
||||
return { type: 'Unspecified', scope: 'this host' };
|
||||
}
|
||||
if (value === 1n) {
|
||||
return { type: 'Loopback', scope: 'this host' };
|
||||
}
|
||||
if (first16 === 0xFE80) {
|
||||
return { type: 'Link-local unicast (fe80::/10)', scope: 'link' };
|
||||
}
|
||||
if (first16 >= 0xFC00 && first16 <= 0xFDFF) {
|
||||
return { type: 'Unique local (ULA, fc00::/7)', scope: 'organization' };
|
||||
}
|
||||
if (first16 === 0xFFFF) {
|
||||
return { type: 'Multicast', scope: 'well-known' };
|
||||
}
|
||||
if (first16 >= 0xFF00 && first16 <= 0xFFFF) {
|
||||
return { type: 'Multicast (ff00::/8)', scope: 'assigned' };
|
||||
}
|
||||
if (first16 === 0x2002) {
|
||||
return { type: '6to4 (2002::/16)', scope: 'global' };
|
||||
}
|
||||
if (value >> 96n === 0x20010DB8n) {
|
||||
return { type: 'Documentation (2001:db8::/32)', scope: 'global' };
|
||||
}
|
||||
if (first16 >= 0x2000 && first16 <= 0x3FFF) {
|
||||
return { type: 'Global unicast (2000::/3)', scope: 'global' };
|
||||
}
|
||||
return { type: 'Reserved or other', scope: 'n/a' };
|
||||
}
|
||||
|
||||
export function describeIpv6(cidr: string): Ipv6Info {
|
||||
const { address, prefix } = parseIpv6Cidr(cidr);
|
||||
const addressValue = ipv6ToBigInt(address);
|
||||
|
||||
const hostBits = 128 - prefix;
|
||||
const networkValue = prefix === 0 ? 0n : (addressValue >> BigInt(hostBits)) << BigInt(hostBits);
|
||||
const total = 1n << BigInt(hostBits);
|
||||
const firstValue = networkValue;
|
||||
const lastValue = networkValue + total - 1n;
|
||||
|
||||
// Top `prefix` bits set. (2^p - 1) << (128 - p) is exact for every p in
|
||||
// 0..128 — the old special case for hostBits === 0 was inverted and
|
||||
// produced an all-zero netmask for /128 (#differential fixture).
|
||||
const maskValue = ((1n << BigInt(prefix)) - 1n) << BigInt(128 - prefix);
|
||||
|
||||
const { type, scope } = describeType(address);
|
||||
|
||||
return {
|
||||
expanded: address,
|
||||
compressed: compressIpv6(address),
|
||||
network: `${compressIpv6(bigIntToIpv6(networkValue))}/${prefix}`,
|
||||
prefix,
|
||||
type,
|
||||
scope,
|
||||
totalAddresses: total.toString(),
|
||||
firstAddress: compressIpv6(bigIntToIpv6(firstValue)),
|
||||
lastAddress: compressIpv6(bigIntToIpv6(lastValue)),
|
||||
mask: compressIpv6(bigIntToIpv6(maskValue)),
|
||||
};
|
||||
}
|
||||
71
src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue
Normal file
71
src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<script setup lang="ts">
|
||||
import { describeIpv6 } from './ipv6-subnet-calculator.models';
|
||||
import { useValidation } from '@/composable/validation';
|
||||
import { isNotThrowing } from '@/utils/boolean';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
|
||||
const input = ref('2001:db8:1234:5678::1/48');
|
||||
|
||||
const info = computed(() => withDefaultOnError(() => describeIpv6(input.value), undefined));
|
||||
|
||||
const validation = useValidation({
|
||||
source: input,
|
||||
rules: [
|
||||
{
|
||||
validator: value => value.trim() === '' || isNotThrowing(() => describeIpv6(value)),
|
||||
message: 'Invalid IPv6 address or prefix (e.g. 2001:db8::1/48)',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const rows = computed(() =>
|
||||
info.value
|
||||
? [
|
||||
{ label: 'Expanded address', value: info.value.expanded },
|
||||
{ label: 'Compressed (RFC 5952)', value: info.value.compressed },
|
||||
{ label: 'Type', value: info.value.type },
|
||||
{ label: 'Scope', value: info.value.scope },
|
||||
{ label: 'Network', value: info.value.network },
|
||||
{ label: 'First address', value: info.value.firstAddress },
|
||||
{ label: 'Last address', value: info.value.lastAddress },
|
||||
{ label: 'Total addresses', value: info.value.totalAddresses },
|
||||
{ label: 'Netmask', value: info.value.mask },
|
||||
]
|
||||
: [],
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="max-width: 720px; margin: 0 auto;">
|
||||
<c-card mb-3>
|
||||
<c-input-text
|
||||
v-model:value="input"
|
||||
label="IPv6 address or CIDR"
|
||||
placeholder="e.g. 2001:db8:1234:5678::1/48"
|
||||
:validation="validation"
|
||||
raw-text
|
||||
mb-2
|
||||
/>
|
||||
</c-card>
|
||||
|
||||
<c-card v-if="info && validation.isValid">
|
||||
<n-table>
|
||||
<tbody>
|
||||
<tr v-for="row of rows" :key="row.label">
|
||||
<td class="labels">{{ row.label }}:</td>
|
||||
<td style="word-break: break-all;">
|
||||
{{ row.value }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</c-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.labels {
|
||||
width: 220px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
1242
src/tools/ipv6-subnet-calculator/ipv6.fixture.json
Normal file
1242
src/tools/ipv6-subnet-calculator/ipv6.fixture.json
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue