diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 6831b01..96d9433 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,23 +1,27 @@ -module.exports = { +require('@rushstack/eslint-patch/modern-module-resolution'); +const { defineConfig } = require('eslint-define-config'); + +module.exports = defineConfig({ root: true, - extends: [ - 'airbnb-base', - 'plugin:vue/vue3-recommended', - 'plugin:prettier/recommended', - 'eslint-config-vitest-globals', - ], env: { browser: true, node: true, - 'vue/setup-compiler-macros': true, - }, - globals: { - __DEV__: 'readonly', + 'vitest-globals/env': true, }, - ignorePatterns: ['node_modules', 'dist'], + ignorePatterns: ['node_modules', 'dist', 'temp'], + extends: [ + 'plugin:vue/vue3-recommended', + '@vue/eslint-config-airbnb-with-typescript', + 'plugin:vitest-globals/recommended', + 'prettier', + ], rules: { - 'prettier/prettier': 'error', - 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], 'no-param-reassign': ['error', { props: false }], + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: true, + }, + ], }, -}; +}); diff --git a/.gitignore b/.gitignore index d1fd3b9..a73b4b0 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ coverage yarn.lock package-lock.json .pnpm-store/ +temp /cypress/videos/ /cypress/screenshots/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 6595032..1303e4e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,8 @@ { "recommendations": [ - "johnsoncodehk.volar", + "vue.volar", + "Vue.vscode-typescript-vue-plugin", "esbenp.prettier-vscode", - "ZixuanChen.vitest-explorer" + "zixuanchen.vitest-explorer" ] } diff --git a/api-extractor.json b/api-extractor.json new file mode 100644 index 0000000..ed66be9 --- /dev/null +++ b/api-extractor.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "mainEntryPointFilePath": "/temp/index.d.ts", + "bundledPackages": [], + "compiler": { + "tsconfigFilePath": "/tsconfig.types.json" + }, + "apiReport": { + "enabled": false + }, + "docModel": { + "enabled": false + }, + "dtsRollup": { + "enabled": true, + "publicTrimmedFilePath": "/dist/.d.ts" + }, + "tsdocMetadata": { + "enabled": false + }, + "messages": { + "compilerMessageReporting": { + "default": { + "logLevel": "warning" + } + }, + "extractorMessageReporting": { + "default": { + "logLevel": "warning" + } + }, + "tsdocMessageReporting": { + "default": { + "logLevel": "warning" + } + } + } +} diff --git a/commitlint.config.js b/commitlint.config.cjs similarity index 100% rename from commitlint.config.js rename to commitlint.config.cjs diff --git a/demo/App.vue b/demo/App.vue index 005021b..6efbda6 100644 --- a/demo/App.vue +++ b/demo/App.vue @@ -6,7 +6,7 @@ - + diff --git a/package.json b/package.json index c53f17b..a1f167f 100644 --- a/package.json +++ b/package.json @@ -22,14 +22,20 @@ "files": [ "dist" ], - "main": "./dist/vue3LazyHydration.cjs.js", - "module": "./dist/esm/index.js", + "type": "module", + "main": "./dist/vue3-lazy-hydration.cjs", + "module": "./dist/esm/vue3-lazy-hydration.mjs", "exports": { ".": { - "import": "./dist/esm/index.js", - "require": "./dist/vue3LazyHydration.cjs.js" + "types": "./dist/vue3-lazy-hydration.d.ts", + "import": "./dist/esm/vue3-lazy-hydration.mjs", + "require": "./dist/vue3-lazy-hydration.cjs" } }, + "types": "./dist/vue3-lazy-hydration.d.ts", + "engines": { + "node": ">=14.6" + }, "sideEffects": false, "config": { "commitizen": { @@ -39,8 +45,9 @@ "scripts": { "preinstall": "npx only-allow pnpm", "postinstall": "simple-git-hooks", - "dev": "vite", - "build": "vite build", + "build": "rimraf dist && vite build && pnpm build-temp-types ", + "build-temp-types": "tsc --emitDeclarationOnly -p ./tsconfig.types.json && api-extractor run && rimraf temp", + "dev": "rimraf dist && vite", "test:unit": "vitest", "coverage": "vitest run --coverage", "format": "prettier --write --cache .", @@ -52,26 +59,32 @@ "devDependencies": { "@commitlint/cli": "17.1.2", "@commitlint/config-conventional": "17.1.0", + "@microsoft/api-extractor": "7.31.2", + "@rushstack/eslint-patch": "1.2.0", + "@types/node": "18.7.18", "@vitejs/plugin-vue": "3.0.2", "@vitest/ui": "0.21.1", + "@vue/eslint-config-airbnb-with-typescript": "7.0.0", "@vue/server-renderer": "3.2.37", "@vue/test-utils": "2.0.2", + "@vue/tsconfig": "0.1.3", "c8": "7.12.0", "commitizen": "4.2.5", "cz-conventional-changelog": "3.3.0", "eslint": "8.21.0", - "eslint-config-airbnb-base": "15.0.0", "eslint-config-prettier": "8.5.0", - "eslint-config-vitest-globals": "0.0.3", + "eslint-define-config": "1.7.0", "eslint-plugin-import": "2.26.0", - "eslint-plugin-prettier": "4.2.1", + "eslint-plugin-vitest-globals": "1.2.0", "eslint-plugin-vue": "9.3.0", "happy-dom": "6.0.4", "lint-staged": "13.0.3", "pnpm": "7.12.1", "prettier": "2.7.1", + "rimraf": "3.0.2", "sass": "1.54.4", "simple-git-hooks": "2.8.0", + "typescript": "4.8.3", "vite": "3.0.6", "vitest": "0.21.1", "vue": "3.2.37", @@ -86,7 +99,7 @@ "*": [ "prettier --write --cache --ignore-unknown" ], - "src/**/*.js": [ + "src/**/*.ts": [ "eslint --cache --fix" ] }, diff --git a/plugin-dev-server.js b/plugin-dev-server.js deleted file mode 100644 index eb95f00..0000000 --- a/plugin-dev-server.js +++ /dev/null @@ -1,43 +0,0 @@ -import fs from 'node:fs'; - -const devSSRPlugin = () => ({ - name: 'dev-ssr', - configureServer(vite) { - const { logger } = vite.config; - - return () => - vite.middlewares.use(async (req, res, next) => { - try { - const template = await vite.transformIndexHtml( - req.url, - fs.readFileSync(`${__dirname}/index.html`, 'utf8'), - req.originalUrl - ); - - const { default: render } = await vite.ssrLoadModule( - '/demo/entry-server.js' - ); - - const { appHtml, css } = await render(req.originalUrl, vite); - - res.statusCode = 200; - - res.setHeader('content-type', 'text/html'); - - res.end( - template - .replace('', css) - .replace('', appHtml) - ); - } catch (e) { - vite.ssrFixStacktrace(e); - - logger.error(e.stack || e.message); - - next(e); - } - }); - }, -}); - -export default devSSRPlugin; diff --git a/plugin-dev-server.ts b/plugin-dev-server.ts new file mode 100644 index 0000000..28e2131 --- /dev/null +++ b/plugin-dev-server.ts @@ -0,0 +1,51 @@ +import fs from 'node:fs'; +import type { IncomingMessage, ServerResponse } from 'node:http'; +import type { Connect, Plugin, ViteDevServer } from 'vite'; +import type TRender from './demo/entry-server'; + +async function ssrMiddleware( + vite: ViteDevServer, + req: Connect.IncomingMessage, + res: ServerResponse +) { + const template = await vite.transformIndexHtml( + req.url as string, + fs.readFileSync(`${__dirname}/index.html`, 'utf8'), + req.originalUrl + ); + + const render = (await vite.ssrLoadModule('/demo/entry-server.ts')) + .default as typeof TRender; + + const { appHtml, css } = await render(req.originalUrl as string, vite); + + res.statusCode = 200; + + res.setHeader('content-type', 'text/html'); + + res.end( + template + .replace('', css) + .replace('', appHtml) + ); +} + +export default function devSSRPlugin(): Plugin { + return { + name: 'dev-ssr', + configureServer(vite) { + const { logger } = vite.config; + + return () => + vite.middlewares.use((req, res, next) => { + ssrMiddleware(vite, req, res).catch((e: Error) => { + vite.ssrFixStacktrace(e); + + logger.error(e.stack || e.message); + + next(e); + }); + }); + }, + }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ccdeda4..b526ab4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,26 +3,32 @@ lockfileVersion: 5.4 specifiers: '@commitlint/cli': 17.1.2 '@commitlint/config-conventional': 17.1.0 + '@microsoft/api-extractor': 7.31.2 + '@rushstack/eslint-patch': 1.2.0 + '@types/node': 18.7.18 '@vitejs/plugin-vue': 3.0.1 '@vitest/ui': 0.21.1 + '@vue/eslint-config-airbnb-with-typescript': 7.0.0 '@vue/server-renderer': 3.2.37 '@vue/test-utils': 2.0.2 + '@vue/tsconfig': 0.1.3 c8: 7.12.0 commitizen: 4.2.5 cz-conventional-changelog: 3.3.0 eslint: 8.21.0 - eslint-config-airbnb-base: 15.0.0 eslint-config-prettier: 8.5.0 - eslint-config-vitest-globals: 0.0.3 + eslint-define-config: 1.7.0 eslint-plugin-import: 2.26.0 - eslint-plugin-prettier: 4.2.1 + eslint-plugin-vitest-globals: 1.2.0 eslint-plugin-vue: 9.3.0 happy-dom: 6.0.4 lint-staged: 13.0.3 pnpm: 7.12.1 prettier: 2.7.1 + rimraf: 3.0.2 sass: 1.54.3 simple-git-hooks: 2.8.0 + typescript: 4.8.3 vite: 3.0.5 vitest: 0.21.1 vue: 3.2.37 @@ -31,26 +37,32 @@ specifiers: devDependencies: '@commitlint/cli': registry.npmjs.org/@commitlint/cli/17.1.2 '@commitlint/config-conventional': registry.npmjs.org/@commitlint/config-conventional/17.1.0 + '@microsoft/api-extractor': registry.npmjs.org/@microsoft/api-extractor/7.31.2 + '@rushstack/eslint-patch': registry.npmjs.org/@rushstack/eslint-patch/1.2.0 + '@types/node': registry.npmjs.org/@types/node/18.7.18 '@vitejs/plugin-vue': registry.npmjs.org/@vitejs/plugin-vue/3.0.1_vite@3.0.5+vue@3.2.37 '@vitest/ui': registry.npmjs.org/@vitest/ui/0.21.1 + '@vue/eslint-config-airbnb-with-typescript': registry.npmjs.org/@vue/eslint-config-airbnb-with-typescript/7.0.0_hnwv6fk2hbwu22jnybyjsu6teu '@vue/server-renderer': registry.npmjs.org/@vue/server-renderer/3.2.37_vue@3.2.37 '@vue/test-utils': registry.npmjs.org/@vue/test-utils/2.0.2_vue@3.2.37 + '@vue/tsconfig': registry.npmjs.org/@vue/tsconfig/0.1.3_@types+node@18.7.18 c8: registry.npmjs.org/c8/7.12.0 commitizen: registry.npmjs.org/commitizen/4.2.5 cz-conventional-changelog: registry.npmjs.org/cz-conventional-changelog/3.3.0 eslint: registry.npmjs.org/eslint/8.21.0 - eslint-config-airbnb-base: registry.npmjs.org/eslint-config-airbnb-base/15.0.0_jatgrcxl4x7ywe7ak6cnjca2ae eslint-config-prettier: registry.npmjs.org/eslint-config-prettier/8.5.0_eslint@8.21.0 - eslint-config-vitest-globals: registry.npmjs.org/eslint-config-vitest-globals/0.0.3 + eslint-define-config: registry.npmjs.org/eslint-define-config/1.7.0 eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_eslint@8.21.0 - eslint-plugin-prettier: registry.npmjs.org/eslint-plugin-prettier/4.2.1_h62lvancfh4b7r6zn2dgodrh5e + eslint-plugin-vitest-globals: registry.npmjs.org/eslint-plugin-vitest-globals/1.2.0 eslint-plugin-vue: registry.npmjs.org/eslint-plugin-vue/9.3.0_eslint@8.21.0 happy-dom: registry.npmjs.org/happy-dom/6.0.4 lint-staged: registry.npmjs.org/lint-staged/13.0.3 pnpm: registry.npmjs.org/pnpm/7.12.1 prettier: registry.npmjs.org/prettier/2.7.1 + rimraf: registry.npmjs.org/rimraf/3.0.2 sass: registry.npmjs.org/sass/1.54.3 simple-git-hooks: registry.npmjs.org/simple-git-hooks/2.8.0 + typescript: registry.npmjs.org/typescript/4.8.3 vite: registry.npmjs.org/vite/3.0.5_sass@1.54.3 vitest: registry.npmjs.org/vitest/0.21.1_xbluqrolgufxqung7cewqvl2b4 vue: registry.npmjs.org/vue/3.2.37 @@ -102,6 +114,25 @@ packages: '@babel/types': registry.npmjs.org/@babel/types/7.19.0 dev: true + registry.npmjs.org/@babel/runtime-corejs3/7.19.1: + resolution: {integrity: sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz} + name: '@babel/runtime-corejs3' + version: 7.19.1 + engines: {node: '>=6.9.0'} + dependencies: + core-js-pure: registry.npmjs.org/core-js-pure/3.25.2 + regenerator-runtime: registry.npmjs.org/regenerator-runtime/0.13.9 + dev: true + + registry.npmjs.org/@babel/runtime/7.19.0: + resolution: {integrity: sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz} + name: '@babel/runtime' + version: 7.19.0 + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: registry.npmjs.org/regenerator-runtime/0.13.9 + dev: true + registry.npmjs.org/@babel/types/7.19.0: resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz} name: '@babel/types' @@ -354,10 +385,10 @@ packages: - supports-color dev: true - registry.npmjs.org/@humanwhocodes/config-array/0.10.4: - resolution: {integrity: sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz} + registry.npmjs.org/@humanwhocodes/config-array/0.10.5: + resolution: {integrity: sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz} name: '@humanwhocodes/config-array' - version: 0.10.4 + version: 0.10.5 engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': registry.npmjs.org/@humanwhocodes/object-schema/1.2.1 @@ -417,6 +448,59 @@ packages: '@jridgewell/sourcemap-codec': registry.npmjs.org/@jridgewell/sourcemap-codec/1.4.14 dev: true + registry.npmjs.org/@microsoft/api-extractor-model/7.24.2: + resolution: {integrity: sha512-uUvjqTCY7hYERWGks+joTioN1QYHIucCDy7I/JqLxFxLbFXE5dpc1X7L+FG4PN/s8QYL24DKt0fqJkgcrFKLTw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.24.2.tgz} + name: '@microsoft/api-extractor-model' + version: 7.24.2 + dependencies: + '@microsoft/tsdoc': registry.npmjs.org/@microsoft/tsdoc/0.14.1 + '@microsoft/tsdoc-config': registry.npmjs.org/@microsoft/tsdoc-config/0.16.2 + '@rushstack/node-core-library': registry.npmjs.org/@rushstack/node-core-library/3.52.0 + dev: true + + registry.npmjs.org/@microsoft/api-extractor/7.31.2: + resolution: {integrity: sha512-ZODCU9ckTS9brXiZpUW2iDrnAg7jLxeLBM1AkPpSZFcbG/8HGLvfKOKrd71VIJHjc52x2lB8xj7ZWksnP7AOBA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.31.2.tgz} + name: '@microsoft/api-extractor' + version: 7.31.2 + hasBin: true + dependencies: + '@microsoft/api-extractor-model': registry.npmjs.org/@microsoft/api-extractor-model/7.24.2 + '@microsoft/tsdoc': registry.npmjs.org/@microsoft/tsdoc/0.14.1 + '@microsoft/tsdoc-config': registry.npmjs.org/@microsoft/tsdoc-config/0.16.2 + '@rushstack/node-core-library': registry.npmjs.org/@rushstack/node-core-library/3.52.0 + '@rushstack/rig-package': registry.npmjs.org/@rushstack/rig-package/0.3.15 + '@rushstack/ts-command-line': registry.npmjs.org/@rushstack/ts-command-line/4.12.3 + colors: registry.npmjs.org/colors/1.2.5 + lodash: registry.npmjs.org/lodash/4.17.21 + resolve: registry.npmjs.org/resolve/1.17.0 + semver: registry.npmjs.org/semver/7.3.7 + source-map: registry.npmjs.org/source-map/0.6.1 + typescript: registry.npmjs.org/typescript/4.7.4 + dev: true + + registry.npmjs.org/@microsoft/tsdoc-config/0.16.2: + resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz} + name: '@microsoft/tsdoc-config' + version: 0.16.2 + dependencies: + '@microsoft/tsdoc': registry.npmjs.org/@microsoft/tsdoc/0.14.2 + ajv: registry.npmjs.org/ajv/6.12.6 + jju: registry.npmjs.org/jju/1.4.0 + resolve: registry.npmjs.org/resolve/1.19.0 + dev: true + + registry.npmjs.org/@microsoft/tsdoc/0.14.1: + resolution: {integrity: sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz} + name: '@microsoft/tsdoc' + version: 0.14.1 + dev: true + + registry.npmjs.org/@microsoft/tsdoc/0.14.2: + resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz} + name: '@microsoft/tsdoc' + version: 0.14.2 + dev: true + registry.npmjs.org/@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz} name: '@nodelib/fs.scandir' @@ -444,12 +528,67 @@ packages: fastq: registry.npmjs.org/fastq/1.13.0 dev: true + registry.npmjs.org/@pkgr/utils/2.3.1: + resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz} + name: '@pkgr/utils' + version: 2.3.1 + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dependencies: + cross-spawn: registry.npmjs.org/cross-spawn/7.0.3 + is-glob: registry.npmjs.org/is-glob/4.0.3 + open: registry.npmjs.org/open/8.4.0 + picocolors: registry.npmjs.org/picocolors/1.0.0 + tiny-glob: registry.npmjs.org/tiny-glob/0.2.9 + tslib: registry.npmjs.org/tslib/2.4.0 + dev: true + registry.npmjs.org/@polka/url/1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz} name: '@polka/url' version: 1.0.0-next.21 dev: true + registry.npmjs.org/@rushstack/eslint-patch/1.2.0: + resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz} + name: '@rushstack/eslint-patch' + version: 1.2.0 + dev: true + + registry.npmjs.org/@rushstack/node-core-library/3.52.0: + resolution: {integrity: sha512-Z+MAP//G3rEGZd3JxJcBGcPYJlh8pvPoLMTLa5Sy6FTE6hRPzN+5J8DT7BbTmlqZaL6SZpXF30heRUbnYOvujw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.52.0.tgz} + name: '@rushstack/node-core-library' + version: 3.52.0 + dependencies: + '@types/node': registry.npmjs.org/@types/node/12.20.24 + colors: registry.npmjs.org/colors/1.2.5 + fs-extra: registry.npmjs.org/fs-extra/7.0.1 + import-lazy: registry.npmjs.org/import-lazy/4.0.0 + jju: registry.npmjs.org/jju/1.4.0 + resolve: registry.npmjs.org/resolve/1.17.0 + semver: registry.npmjs.org/semver/7.3.7 + z-schema: registry.npmjs.org/z-schema/5.0.4 + dev: true + + registry.npmjs.org/@rushstack/rig-package/0.3.15: + resolution: {integrity: sha512-jxVfvO5OnkRlYRhcVDZWvwiI2l4pv37HDJRtyg5HbD8Z/I8Xj32RICgrxS5xMeGGytobrg5S6OfPOHskg7Nw+A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.15.tgz} + name: '@rushstack/rig-package' + version: 0.3.15 + dependencies: + resolve: registry.npmjs.org/resolve/1.17.0 + strip-json-comments: registry.npmjs.org/strip-json-comments/3.1.1 + dev: true + + registry.npmjs.org/@rushstack/ts-command-line/4.12.3: + resolution: {integrity: sha512-Pdij22RotMXzI+HWHyYCvw0RMZhiP5a6Za/96XamZ1+mxmpSm4ujf8TROKxGAHySmR5A8iNVSlzhNMnUlFQE6g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.12.3.tgz} + name: '@rushstack/ts-command-line' + version: 4.12.3 + dependencies: + '@types/argparse': registry.npmjs.org/@types/argparse/1.0.38 + argparse: registry.npmjs.org/argparse/1.0.10 + colors: registry.npmjs.org/colors/1.2.5 + string-argv: registry.npmjs.org/string-argv/0.3.1 + dev: true + registry.npmjs.org/@tsconfig/node10/1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz} name: '@tsconfig/node10' @@ -474,6 +613,12 @@ packages: version: 1.0.3 dev: true + registry.npmjs.org/@types/argparse/1.0.38: + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz} + name: '@types/argparse' + version: 1.0.38 + dev: true + registry.npmjs.org/@types/chai-subset/1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz} name: '@types/chai-subset' @@ -493,7 +638,7 @@ packages: name: '@types/concat-stream' version: 1.6.1 dependencies: - '@types/node': registry.npmjs.org/@types/node/8.10.66 + '@types/node': registry.npmjs.org/@types/node/18.7.18 dev: true registry.npmjs.org/@types/form-data/0.0.33: @@ -501,7 +646,7 @@ packages: name: '@types/form-data' version: 0.0.33 dependencies: - '@types/node': registry.npmjs.org/@types/node/8.10.66 + '@types/node': registry.npmjs.org/@types/node/18.7.18 dev: true registry.npmjs.org/@types/istanbul-lib-coverage/2.0.4: @@ -510,6 +655,12 @@ packages: version: 2.0.4 dev: true + registry.npmjs.org/@types/json-schema/7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz} + name: '@types/json-schema' + version: 7.0.11 + dev: true + registry.npmjs.org/@types/json5/0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz} name: '@types/json5' @@ -528,6 +679,12 @@ packages: version: 10.17.60 dev: true + registry.npmjs.org/@types/node/12.20.24: + resolution: {integrity: sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz} + name: '@types/node' + version: 12.20.24 + dev: true + registry.npmjs.org/@types/node/14.18.29: resolution: {integrity: sha512-LhF+9fbIX4iPzhsRLpK5H7iPdvW8L4IwGciXQIOEcuF62+9nw/VQVsOViAOOGxY3OlOKGLFv0sWwJXdwQeTn6A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@types/node/-/node-14.18.29.tgz} name: '@types/node' @@ -564,6 +721,153 @@ packages: version: 6.9.7 dev: true + registry.npmjs.org/@typescript-eslint/eslint-plugin/5.38.0_pt53jaadousbhf4ji77i2waxdu: + resolution: {integrity: sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.0.tgz} + id: registry.npmjs.org/@typescript-eslint/eslint-plugin/5.38.0 + name: '@typescript-eslint/eslint-plugin' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.38.0 + '@typescript-eslint/type-utils': registry.npmjs.org/@typescript-eslint/type-utils/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + debug: registry.npmjs.org/debug/4.3.4 + eslint: registry.npmjs.org/eslint/8.21.0 + ignore: registry.npmjs.org/ignore/5.2.0 + regexpp: registry.npmjs.org/regexpp/3.2.0 + semver: registry.npmjs.org/semver/7.3.7 + tsutils: registry.npmjs.org/tsutils/3.21.0_typescript@4.8.3 + typescript: registry.npmjs.org/typescript/4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmjs.org/@typescript-eslint/parser/5.38.0_iopuwovpd3qd4ttrbpmiexfkga: + resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.38.0.tgz} + id: registry.npmjs.org/@typescript-eslint/parser/5.38.0 + name: '@typescript-eslint/parser' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.38.0 + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.38.0 + '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.38.0_typescript@4.8.3 + debug: registry.npmjs.org/debug/4.3.4 + eslint: registry.npmjs.org/eslint/8.21.0 + typescript: registry.npmjs.org/typescript/4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmjs.org/@typescript-eslint/scope-manager/5.38.0: + resolution: {integrity: sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz} + name: '@typescript-eslint/scope-manager' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.38.0 + '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.38.0 + dev: true + + registry.npmjs.org/@typescript-eslint/type-utils/5.38.0_iopuwovpd3qd4ttrbpmiexfkga: + resolution: {integrity: sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.38.0.tgz} + id: registry.npmjs.org/@typescript-eslint/type-utils/5.38.0 + name: '@typescript-eslint/type-utils' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.38.0_typescript@4.8.3 + '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + debug: registry.npmjs.org/debug/4.3.4 + eslint: registry.npmjs.org/eslint/8.21.0 + tsutils: registry.npmjs.org/tsutils/3.21.0_typescript@4.8.3 + typescript: registry.npmjs.org/typescript/4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmjs.org/@typescript-eslint/types/5.38.0: + resolution: {integrity: sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/types/-/types-5.38.0.tgz} + name: '@typescript-eslint/types' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + registry.npmjs.org/@typescript-eslint/typescript-estree/5.38.0_typescript@4.8.3: + resolution: {integrity: sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz} + id: registry.npmjs.org/@typescript-eslint/typescript-estree/5.38.0 + name: '@typescript-eslint/typescript-estree' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.38.0 + '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.38.0 + debug: registry.npmjs.org/debug/4.3.4 + globby: registry.npmjs.org/globby/11.1.0 + is-glob: registry.npmjs.org/is-glob/4.0.3 + semver: registry.npmjs.org/semver/7.3.7 + tsutils: registry.npmjs.org/tsutils/3.21.0_typescript@4.8.3 + typescript: registry.npmjs.org/typescript/4.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmjs.org/@typescript-eslint/utils/5.38.0_iopuwovpd3qd4ttrbpmiexfkga: + resolution: {integrity: sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.38.0.tgz} + id: registry.npmjs.org/@typescript-eslint/utils/5.38.0 + name: '@typescript-eslint/utils' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': registry.npmjs.org/@types/json-schema/7.0.11 + '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.38.0 + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.38.0 + '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.38.0_typescript@4.8.3 + eslint: registry.npmjs.org/eslint/8.21.0 + eslint-scope: registry.npmjs.org/eslint-scope/5.1.1 + eslint-utils: registry.npmjs.org/eslint-utils/3.0.0_eslint@8.21.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + registry.npmjs.org/@typescript-eslint/visitor-keys/5.38.0: + resolution: {integrity: sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz} + name: '@typescript-eslint/visitor-keys' + version: 5.38.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.38.0 + eslint-visitor-keys: registry.npmjs.org/eslint-visitor-keys/3.3.0 + dev: true + registry.npmjs.org/@vitejs/plugin-vue/3.0.1_vite@3.0.5+vue@3.2.37: resolution: {integrity: sha512-Ll9JgxG7ONIz/XZv3dssfoMUDu9qAnlJ+km+pBA0teYSXzwPCIzS/e1bmwNYl5dcQGs677D21amgfYAnzMl17A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-3.0.1.tgz} id: registry.npmjs.org/@vitejs/plugin-vue/3.0.1 @@ -638,6 +942,59 @@ packages: version: 6.2.1 dev: true + registry.npmjs.org/@vue/eslint-config-airbnb-with-typescript/7.0.0_hnwv6fk2hbwu22jnybyjsu6teu: + resolution: {integrity: sha512-y0VxZrvgGYwaEukejN9a9/zrUg1sabGMaSAxpymKLmIVImRr7dONUnTCwY1zkxxXtn+nlCA1PgYLZMAPZ2SxWw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@vue/eslint-config-airbnb-with-typescript/-/eslint-config-airbnb-with-typescript-7.0.0.tgz} + id: registry.npmjs.org/@vue/eslint-config-airbnb-with-typescript/7.0.0 + name: '@vue/eslint-config-airbnb-with-typescript' + version: 7.0.0 + peerDependencies: + eslint: ^8.2.0 + eslint-plugin-vue: ^9.2.0 + typescript: '*' + dependencies: + '@typescript-eslint/eslint-plugin': registry.npmjs.org/@typescript-eslint/eslint-plugin/5.38.0_pt53jaadousbhf4ji77i2waxdu + '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + '@vue/eslint-config-airbnb': registry.npmjs.org/@vue/eslint-config-airbnb/7.0.0_7dfsdrhvuvxt2txuu6jxh7qmx4 + eslint: registry.npmjs.org/eslint/8.21.0 + eslint-config-airbnb-typescript: registry.npmjs.org/eslint-config-airbnb-typescript/17.0.0_sphhbn67vok74w6b43lskmqmma + eslint-define-config: registry.npmjs.org/eslint-define-config/1.7.0 + eslint-import-resolver-node: registry.npmjs.org/eslint-import-resolver-node/0.3.6 + eslint-import-resolver-typescript: registry.npmjs.org/eslint-import-resolver-typescript/3.5.1_jatgrcxl4x7ywe7ak6cnjca2ae + eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_qspdds2d277rjvvrg4o6ugrmri + eslint-plugin-vue: registry.npmjs.org/eslint-plugin-vue/9.3.0_eslint@8.21.0 + typescript: registry.npmjs.org/typescript/4.8.3 + vue-eslint-parser: registry.npmjs.org/vue-eslint-parser/9.1.0_eslint@8.21.0 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - supports-color + dev: true + + registry.npmjs.org/@vue/eslint-config-airbnb/7.0.0_7dfsdrhvuvxt2txuu6jxh7qmx4: + resolution: {integrity: sha512-qC3HRnvaDWRocDKPVKUnjWLXo1NDfDSPKwizc49llN/mRZF2Q9D/7wcAMwzCVzPM/D80ZUz0sy1cq9u/6jFnqw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@vue/eslint-config-airbnb/-/eslint-config-airbnb-7.0.0.tgz} + id: registry.npmjs.org/@vue/eslint-config-airbnb/7.0.0 + name: '@vue/eslint-config-airbnb' + version: 7.0.0 + peerDependencies: + eslint: ^8.2.0 + eslint-plugin-vue: ^9.2.0 + dependencies: + eslint: registry.npmjs.org/eslint/8.21.0 + eslint-config-airbnb-base: registry.npmjs.org/eslint-config-airbnb-base/15.0.0_jatgrcxl4x7ywe7ak6cnjca2ae + eslint-import-resolver-custom-alias: registry.npmjs.org/eslint-import-resolver-custom-alias/1.3.0_fkfqfehjtk7sk2efaqbgxsuasa + eslint-import-resolver-node: registry.npmjs.org/eslint-import-resolver-node/0.3.6 + eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_qspdds2d277rjvvrg4o6ugrmri + eslint-plugin-jsx-a11y: registry.npmjs.org/eslint-plugin-jsx-a11y/6.6.1_eslint@8.21.0 + eslint-plugin-react: registry.npmjs.org/eslint-plugin-react/7.31.8_eslint@8.21.0 + eslint-plugin-vue: registry.npmjs.org/eslint-plugin-vue/9.3.0_eslint@8.21.0 + eslint-plugin-vuejs-accessibility: registry.npmjs.org/eslint-plugin-vuejs-accessibility/1.2.0_eslint@8.21.0 + vue-eslint-parser: registry.npmjs.org/vue-eslint-parser/9.1.0_eslint@8.21.0 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + registry.npmjs.org/@vue/reactivity-transform/3.2.37: resolution: {integrity: sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz} name: '@vue/reactivity-transform' @@ -707,6 +1064,20 @@ packages: vue: registry.npmjs.org/vue/3.2.37 dev: true + registry.npmjs.org/@vue/tsconfig/0.1.3_@types+node@18.7.18: + resolution: {integrity: sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.1.3.tgz} + id: registry.npmjs.org/@vue/tsconfig/0.1.3 + name: '@vue/tsconfig' + version: 0.1.3 + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@types/node': registry.npmjs.org/@types/node/18.7.18 + dev: true + registry.npmjs.org/JSONStream/1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz} name: JSONStream @@ -839,12 +1210,37 @@ packages: version: 4.1.3 dev: true + registry.npmjs.org/argparse/1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz} + name: argparse + version: 1.0.10 + dependencies: + sprintf-js: registry.npmjs.org/sprintf-js/1.0.3 + dev: true + registry.npmjs.org/argparse/2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz} name: argparse version: 2.0.1 dev: true + registry.npmjs.org/aria-query/4.2.2: + resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz} + name: aria-query + version: 4.2.2 + engines: {node: '>=6.0'} + dependencies: + '@babel/runtime': registry.npmjs.org/@babel/runtime/7.19.0 + '@babel/runtime-corejs3': registry.npmjs.org/@babel/runtime-corejs3/7.19.1 + dev: true + + registry.npmjs.org/aria-query/5.0.2: + resolution: {integrity: sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/aria-query/-/aria-query-5.0.2.tgz} + name: aria-query + version: 5.0.2 + engines: {node: '>=6.0'} + dev: true + registry.npmjs.org/array-ify/1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz} name: array-ify @@ -859,7 +1255,7 @@ packages: dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 define-properties: registry.npmjs.org/define-properties/1.1.4 - es-abstract: registry.npmjs.org/es-abstract/1.20.2 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 get-intrinsic: registry.npmjs.org/get-intrinsic/1.1.3 is-string: registry.npmjs.org/is-string/1.0.7 dev: true @@ -879,7 +1275,19 @@ packages: dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 define-properties: registry.npmjs.org/define-properties/1.1.4 - es-abstract: registry.npmjs.org/es-abstract/1.20.2 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 + es-shim-unscopables: registry.npmjs.org/es-shim-unscopables/1.0.0 + dev: true + + registry.npmjs.org/array.prototype.flatmap/1.3.0: + resolution: {integrity: sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz} + name: array.prototype.flatmap + version: 1.3.0 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmjs.org/call-bind/1.0.2 + define-properties: registry.npmjs.org/define-properties/1.1.4 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 es-shim-unscopables: registry.npmjs.org/es-shim-unscopables/1.0.0 dev: true @@ -902,6 +1310,12 @@ packages: version: 1.1.0 dev: true + registry.npmjs.org/ast-types-flow/0.0.7: + resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz} + name: ast-types-flow + version: 0.0.7 + dev: true + registry.npmjs.org/astral-regex/2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz} name: astral-regex @@ -922,6 +1336,19 @@ packages: engines: {node: '>= 4.0.0'} dev: true + registry.npmjs.org/axe-core/4.4.3: + resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz} + name: axe-core + version: 4.4.3 + engines: {node: '>=4'} + dev: true + + registry.npmjs.org/axobject-query/2.2.0: + resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz} + name: axobject-query + version: 2.2.0 + dev: true + registry.npmjs.org/balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz} name: balanced-match @@ -1225,6 +1652,13 @@ packages: version: 2.0.19 dev: true + registry.npmjs.org/colors/1.2.5: + resolution: {integrity: sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/colors/-/colors-1.2.5.tgz} + name: colors + version: 1.2.5 + engines: {node: '>=0.1.90'} + dev: true + registry.npmjs.org/combined-stream/1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz} name: combined-stream @@ -1234,6 +1668,14 @@ packages: delayed-stream: registry.npmjs.org/delayed-stream/1.0.0 dev: true + registry.npmjs.org/commander/2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/commander/-/commander-2.20.3.tgz} + name: commander + version: 2.20.3 + requiresBuild: true + dev: true + optional: true + registry.npmjs.org/commander/9.4.0: resolution: {integrity: sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/commander/-/commander-9.4.0.tgz} name: commander @@ -1350,6 +1792,13 @@ packages: safe-buffer: registry.npmjs.org/safe-buffer/5.1.2 dev: true + registry.npmjs.org/core-js-pure/3.25.2: + resolution: {integrity: sha512-ItD7YpW1cUB4jaqFLZXe1AXkyqIxz6GqPnsDV4uF4hVcWh/WAGIqSqw5p0/WdsILM0Xht9s3Koyw05R3K6RtiA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.2.tgz} + name: core-js-pure + version: 3.25.2 + requiresBuild: true + dev: true + registry.npmjs.org/core-util-is/1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz} name: core-util-is @@ -1443,6 +1892,12 @@ packages: - '@swc/wasm' dev: true + registry.npmjs.org/damerau-levenshtein/1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz} + name: damerau-levenshtein + version: 1.0.8 + dev: true + registry.npmjs.org/dargs/7.0.0: resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz} name: dargs @@ -1536,6 +1991,13 @@ packages: clone: registry.npmjs.org/clone/1.0.4 dev: true + registry.npmjs.org/define-lazy-prop/2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz} + name: define-lazy-prop + version: 2.0.0 + engines: {node: '>=8'} + dev: true + registry.npmjs.org/define-properties/1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz} name: define-properties @@ -1616,6 +2078,12 @@ packages: version: 0.2.0 dev: true + registry.npmjs.org/emoji-regex/10.1.0: + resolution: {integrity: sha512-xAEnNCT3w2Tg6MA7ly6QqYJvEoY1tm9iIjJ3yMKK9JPlWuRHAMoe5iETwQnx3M9TVbFMfsrBgWKR+IsmswwNjg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.1.0.tgz} + name: emoji-regex + version: 10.1.0 + dev: true + registry.npmjs.org/emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz} name: emoji-regex @@ -1628,6 +2096,16 @@ packages: version: 9.2.2 dev: true + registry.npmjs.org/enhanced-resolve/5.10.0: + resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz} + name: enhanced-resolve + version: 5.10.0 + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: registry.npmjs.org/graceful-fs/4.2.10 + tapable: registry.npmjs.org/tapable/2.2.1 + dev: true + registry.npmjs.org/error-ex/1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz} name: error-ex @@ -1636,10 +2114,10 @@ packages: is-arrayish: registry.npmjs.org/is-arrayish/0.2.1 dev: true - registry.npmjs.org/es-abstract/1.20.2: - resolution: {integrity: sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz} + registry.npmjs.org/es-abstract/1.20.3: + resolution: {integrity: sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz} name: es-abstract - version: 1.20.2 + version: 1.20.3 engines: {node: '>= 0.4'} dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 @@ -1662,6 +2140,7 @@ packages: object-keys: registry.npmjs.org/object-keys/1.1.1 object.assign: registry.npmjs.org/object.assign/4.1.4 regexp.prototype.flags: registry.npmjs.org/regexp.prototype.flags/1.4.3 + safe-regex-test: registry.npmjs.org/safe-regex-test/1.0.0 string.prototype.trimend: registry.npmjs.org/string.prototype.trimend/1.0.5 string.prototype.trimstart: registry.npmjs.org/string.prototype.trimstart/1.0.5 unbox-primitive: registry.npmjs.org/unbox-primitive/1.0.2 @@ -1970,12 +2449,30 @@ packages: dependencies: confusing-browser-globals: registry.npmjs.org/confusing-browser-globals/1.0.11 eslint: registry.npmjs.org/eslint/8.21.0 - eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_eslint@8.21.0 + eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_qspdds2d277rjvvrg4o6ugrmri object.assign: registry.npmjs.org/object.assign/4.1.4 object.entries: registry.npmjs.org/object.entries/1.1.5 semver: registry.npmjs.org/semver/6.3.0 dev: true + registry.npmjs.org/eslint-config-airbnb-typescript/17.0.0_sphhbn67vok74w6b43lskmqmma: + resolution: {integrity: sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz} + id: registry.npmjs.org/eslint-config-airbnb-typescript/17.0.0 + name: eslint-config-airbnb-typescript + version: 17.0.0 + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.13.0 + '@typescript-eslint/parser': ^5.0.0 + eslint: ^7.32.0 || ^8.2.0 + eslint-plugin-import: ^2.25.3 + dependencies: + '@typescript-eslint/eslint-plugin': registry.npmjs.org/@typescript-eslint/eslint-plugin/5.38.0_pt53jaadousbhf4ji77i2waxdu + '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + eslint: registry.npmjs.org/eslint/8.21.0 + eslint-config-airbnb-base: registry.npmjs.org/eslint-config-airbnb-base/15.0.0_jatgrcxl4x7ywe7ak6cnjca2ae + eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_qspdds2d277rjvvrg4o6ugrmri + dev: true + registry.npmjs.org/eslint-config-prettier/8.5.0_eslint@8.21.0: resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz} id: registry.npmjs.org/eslint-config-prettier/8.5.0 @@ -1988,10 +2485,30 @@ packages: eslint: registry.npmjs.org/eslint/8.21.0 dev: true - registry.npmjs.org/eslint-config-vitest-globals/0.0.3: - resolution: {integrity: sha512-w+opH7EFLErO82C1LzuY5xXCzDtUi8NtnPwng5Xzlz0UN+bJ48JgR1UqygAnZYPghdqSJNbeB6N2Z34zPr5f2Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-config-vitest-globals/-/eslint-config-vitest-globals-0.0.3.tgz} - name: eslint-config-vitest-globals - version: 0.0.3 + registry.npmjs.org/eslint-config-sets/1.8.3: + resolution: {integrity: sha512-X9OtGgO3olmrUB42aWMIm9rO+ehz89dysyfWBITHq8N9hB/AxHuNkqHVNU3YLT53WpbRopVCEHIBhZ2i1dMFyw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-config-sets/-/eslint-config-sets-1.8.3.tgz} + name: eslint-config-sets + version: 1.8.3 + dev: true + + registry.npmjs.org/eslint-define-config/1.7.0: + resolution: {integrity: sha512-13zk8z8eKO4tpPMvAGV0sa6ok0XuMeu7Zhcizu2bLwcLy1fbNt7/h8PU1wbp9IoIgQETggZJozU0nPXUXOao2g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-define-config/-/eslint-define-config-1.7.0.tgz} + name: eslint-define-config + version: 1.7.0 + engines: {node: '>= 14.6.0', npm: '>= 6.0.0', pnpm: '>= 7.0.0'} + dev: true + + registry.npmjs.org/eslint-import-resolver-custom-alias/1.3.0_fkfqfehjtk7sk2efaqbgxsuasa: + resolution: {integrity: sha512-9rrpduF6/SZHFXrJgjeA+edJek6xulplYfo/UJvLPrY38O9UY00rAq76dHRnZ289yftc5NIfx3THi0IILRQ3dg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-import-resolver-custom-alias/-/eslint-import-resolver-custom-alias-1.3.0.tgz} + id: registry.npmjs.org/eslint-import-resolver-custom-alias/1.3.0 + name: eslint-import-resolver-custom-alias + version: 1.3.0 + peerDependencies: + eslint-plugin-import: '>=2.2.0' + dependencies: + eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_qspdds2d277rjvvrg4o6ugrmri + glob-parent: registry.npmjs.org/glob-parent/5.1.2 + resolve: registry.npmjs.org/resolve/1.22.1 dev: true registry.npmjs.org/eslint-import-resolver-node/0.3.6: @@ -2005,6 +2522,62 @@ packages: - supports-color dev: true + registry.npmjs.org/eslint-import-resolver-typescript/3.5.1_jatgrcxl4x7ywe7ak6cnjca2ae: + resolution: {integrity: sha512-U7LUjNJPYjNsHvAUAkt/RU3fcTSpbllA0//35B4eLYTX74frmOepbt7F7J3D1IGtj9k21buOpaqtDd4ZlS/BYQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.1.tgz} + id: registry.npmjs.org/eslint-import-resolver-typescript/3.5.1 + name: eslint-import-resolver-typescript + version: 3.5.1 + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + dependencies: + debug: registry.npmjs.org/debug/4.3.4 + enhanced-resolve: registry.npmjs.org/enhanced-resolve/5.10.0 + eslint: registry.npmjs.org/eslint/8.21.0 + eslint-plugin-import: registry.npmjs.org/eslint-plugin-import/2.26.0_qspdds2d277rjvvrg4o6ugrmri + get-tsconfig: registry.npmjs.org/get-tsconfig/4.2.0 + globby: registry.npmjs.org/globby/13.1.2 + is-core-module: registry.npmjs.org/is-core-module/2.10.0 + is-glob: registry.npmjs.org/is-glob/4.0.3 + synckit: registry.npmjs.org/synckit/0.8.4 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmjs.org/eslint-module-utils/2.7.4_jjwcczaayvoo46whgxj7gbwdoi: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz} + id: registry.npmjs.org/eslint-module-utils/2.7.4 + name: eslint-module-utils + version: 2.7.4 + 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': registry.npmjs.org/@typescript-eslint/parser/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + debug: registry.npmjs.org/debug/3.2.7 + eslint: registry.npmjs.org/eslint/8.21.0 + eslint-import-resolver-node: registry.npmjs.org/eslint-import-resolver-node/0.3.6 + eslint-import-resolver-typescript: registry.npmjs.org/eslint-import-resolver-typescript/3.5.1_jatgrcxl4x7ywe7ak6cnjca2ae + transitivePeerDependencies: + - supports-color + dev: true + registry.npmjs.org/eslint-module-utils/2.7.4_zflgaj7ueoqxy2roamlbaacdgq: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz} id: registry.npmjs.org/eslint-module-utils/2.7.4 @@ -2069,24 +2642,97 @@ packages: - supports-color dev: true - registry.npmjs.org/eslint-plugin-prettier/4.2.1_h62lvancfh4b7r6zn2dgodrh5e: - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz} - id: registry.npmjs.org/eslint-plugin-prettier/4.2.1 - name: eslint-plugin-prettier - version: 4.2.1 - engines: {node: '>=12.0.0'} + registry.npmjs.org/eslint-plugin-import/2.26.0_qspdds2d277rjvvrg4o6ugrmri: + resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz} + id: registry.npmjs.org/eslint-plugin-import/2.26.0 + name: eslint-plugin-import + version: 2.26.0 + engines: {node: '>=4'} peerDependencies: - eslint: '>=7.28.0' - eslint-config-prettier: '*' - prettier: '>=2.0.0' + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 peerDependenciesMeta: - eslint-config-prettier: + '@typescript-eslint/parser': optional: true dependencies: + '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.38.0_iopuwovpd3qd4ttrbpmiexfkga + array-includes: registry.npmjs.org/array-includes/3.1.5 + array.prototype.flat: registry.npmjs.org/array.prototype.flat/1.3.0 + debug: registry.npmjs.org/debug/2.6.9 + doctrine: registry.npmjs.org/doctrine/2.1.0 + eslint: registry.npmjs.org/eslint/8.21.0 + eslint-import-resolver-node: registry.npmjs.org/eslint-import-resolver-node/0.3.6 + eslint-module-utils: registry.npmjs.org/eslint-module-utils/2.7.4_jjwcczaayvoo46whgxj7gbwdoi + has: registry.npmjs.org/has/1.0.3 + is-core-module: registry.npmjs.org/is-core-module/2.10.0 + is-glob: registry.npmjs.org/is-glob/4.0.3 + minimatch: registry.npmjs.org/minimatch/3.1.2 + object.values: registry.npmjs.org/object.values/1.1.5 + resolve: registry.npmjs.org/resolve/1.22.1 + tsconfig-paths: registry.npmjs.org/tsconfig-paths/3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + registry.npmjs.org/eslint-plugin-jsx-a11y/6.6.1_eslint@8.21.0: + resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz} + id: registry.npmjs.org/eslint-plugin-jsx-a11y/6.6.1 + name: eslint-plugin-jsx-a11y + version: 6.6.1 + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + '@babel/runtime': registry.npmjs.org/@babel/runtime/7.19.0 + aria-query: registry.npmjs.org/aria-query/4.2.2 + array-includes: registry.npmjs.org/array-includes/3.1.5 + ast-types-flow: registry.npmjs.org/ast-types-flow/0.0.7 + axe-core: registry.npmjs.org/axe-core/4.4.3 + axobject-query: registry.npmjs.org/axobject-query/2.2.0 + damerau-levenshtein: registry.npmjs.org/damerau-levenshtein/1.0.8 + emoji-regex: registry.npmjs.org/emoji-regex/9.2.2 + eslint: registry.npmjs.org/eslint/8.21.0 + has: registry.npmjs.org/has/1.0.3 + jsx-ast-utils: registry.npmjs.org/jsx-ast-utils/3.3.3 + language-tags: registry.npmjs.org/language-tags/1.0.5 + minimatch: registry.npmjs.org/minimatch/3.1.2 + semver: registry.npmjs.org/semver/6.3.0 + dev: true + + registry.npmjs.org/eslint-plugin-react/7.31.8_eslint@8.21.0: + resolution: {integrity: sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz} + id: registry.npmjs.org/eslint-plugin-react/7.31.8 + name: eslint-plugin-react + version: 7.31.8 + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: registry.npmjs.org/array-includes/3.1.5 + array.prototype.flatmap: registry.npmjs.org/array.prototype.flatmap/1.3.0 + doctrine: registry.npmjs.org/doctrine/2.1.0 eslint: registry.npmjs.org/eslint/8.21.0 - eslint-config-prettier: registry.npmjs.org/eslint-config-prettier/8.5.0_eslint@8.21.0 - prettier: registry.npmjs.org/prettier/2.7.1 - prettier-linter-helpers: registry.npmjs.org/prettier-linter-helpers/1.0.0 + estraverse: registry.npmjs.org/estraverse/5.3.0 + jsx-ast-utils: registry.npmjs.org/jsx-ast-utils/3.3.3 + minimatch: registry.npmjs.org/minimatch/3.1.2 + object.entries: registry.npmjs.org/object.entries/1.1.5 + object.fromentries: registry.npmjs.org/object.fromentries/2.0.5 + object.hasown: registry.npmjs.org/object.hasown/1.1.1 + object.values: registry.npmjs.org/object.values/1.1.5 + prop-types: registry.npmjs.org/prop-types/15.8.1 + resolve: registry.npmjs.org/resolve/2.0.0-next.4 + semver: registry.npmjs.org/semver/6.3.0 + string.prototype.matchall: registry.npmjs.org/string.prototype.matchall/4.0.7 + dev: true + + registry.npmjs.org/eslint-plugin-vitest-globals/1.2.0: + resolution: {integrity: sha512-vINsci+UOvObny6vutsa0c9xzM0PfdKgtkhnH8lLSe4+gZPjhK9O4v26oSu5Svb1n8Rvug4iX2k6keuKBoRlOg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-plugin-vitest-globals/-/eslint-plugin-vitest-globals-1.2.0.tgz} + name: eslint-plugin-vitest-globals + version: 1.2.0 + dependencies: + eslint-config-sets: registry.npmjs.org/eslint-config-sets/1.8.3 dev: true registry.npmjs.org/eslint-plugin-vue/9.3.0_eslint@8.21.0: @@ -2110,6 +2756,32 @@ packages: - supports-color dev: true + registry.npmjs.org/eslint-plugin-vuejs-accessibility/1.2.0_eslint@8.21.0: + resolution: {integrity: sha512-wF7kT22lS2VOmIpDeI65bnFFKFgESEEpI+CWKr43mdfDRywA4sCk7cKhtZsvfbPOtKO0GDlnpFxZbOIGsFn7IQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-plugin-vuejs-accessibility/-/eslint-plugin-vuejs-accessibility-1.2.0.tgz} + id: registry.npmjs.org/eslint-plugin-vuejs-accessibility/1.2.0 + name: eslint-plugin-vuejs-accessibility + version: 1.2.0 + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + aria-query: registry.npmjs.org/aria-query/5.0.2 + emoji-regex: registry.npmjs.org/emoji-regex/10.1.0 + eslint: registry.npmjs.org/eslint/8.21.0 + vue-eslint-parser: registry.npmjs.org/vue-eslint-parser/9.1.0_eslint@8.21.0 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmjs.org/eslint-scope/5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz} + name: eslint-scope + version: 5.1.1 + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: registry.npmjs.org/esrecurse/4.3.0 + estraverse: registry.npmjs.org/estraverse/4.3.0 + dev: true + registry.npmjs.org/eslint-scope/7.1.1: resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz} name: eslint-scope @@ -2155,7 +2827,7 @@ packages: hasBin: true dependencies: '@eslint/eslintrc': registry.npmjs.org/@eslint/eslintrc/1.3.2 - '@humanwhocodes/config-array': registry.npmjs.org/@humanwhocodes/config-array/0.10.4 + '@humanwhocodes/config-array': registry.npmjs.org/@humanwhocodes/config-array/0.10.5 '@humanwhocodes/gitignore-to-minimatch': registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/1.0.2 ajv: registry.npmjs.org/ajv/6.12.6 chalk: registry.npmjs.org/chalk/4.1.2 @@ -2226,6 +2898,13 @@ packages: estraverse: registry.npmjs.org/estraverse/5.3.0 dev: true + registry.npmjs.org/estraverse/4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz} + name: estraverse + version: 4.3.0 + engines: {node: '>=4.0'} + dev: true + registry.npmjs.org/estraverse/5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz} name: estraverse @@ -2306,12 +2985,6 @@ packages: version: 3.1.3 dev: true - registry.npmjs.org/fast-diff/1.2.0: - resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz} - name: fast-diff - version: 1.2.0 - dev: true - registry.npmjs.org/fast-glob/3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz} name: fast-glob @@ -2467,6 +3140,17 @@ packages: universalify: registry.npmjs.org/universalify/2.0.0 dev: true + registry.npmjs.org/fs-extra/7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz} + name: fs-extra + version: 7.0.1 + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: registry.npmjs.org/graceful-fs/4.2.10 + jsonfile: registry.npmjs.org/jsonfile/4.0.0 + universalify: registry.npmjs.org/universalify/0.1.2 + dev: true + registry.npmjs.org/fs-extra/9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz} name: fs-extra @@ -2509,7 +3193,7 @@ packages: dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 define-properties: registry.npmjs.org/define-properties/1.1.4 - es-abstract: registry.npmjs.org/es-abstract/1.20.2 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 functions-have-names: registry.npmjs.org/functions-have-names/1.2.3 dev: true @@ -2572,6 +3256,12 @@ packages: get-intrinsic: registry.npmjs.org/get-intrinsic/1.1.3 dev: true + registry.npmjs.org/get-tsconfig/4.2.0: + resolution: {integrity: sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.2.0.tgz} + name: get-tsconfig + version: 4.2.0 + dev: true + registry.npmjs.org/git-raw-commits/2.0.11: resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz} name: git-raw-commits @@ -2659,6 +3349,12 @@ packages: type-fest: registry.npmjs.org/type-fest/0.20.2 dev: true + registry.npmjs.org/globalyzer/0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz} + name: globalyzer + version: 0.1.0 + dev: true + registry.npmjs.org/globby/11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/globby/-/globby-11.1.0.tgz} name: globby @@ -2673,6 +3369,25 @@ packages: slash: registry.npmjs.org/slash/3.0.0 dev: true + registry.npmjs.org/globby/13.1.2: + resolution: {integrity: sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/globby/-/globby-13.1.2.tgz} + name: globby + version: 13.1.2 + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + dir-glob: registry.npmjs.org/dir-glob/3.0.1 + fast-glob: registry.npmjs.org/fast-glob/3.2.12 + ignore: registry.npmjs.org/ignore/5.2.0 + merge2: registry.npmjs.org/merge2/1.4.1 + slash: registry.npmjs.org/slash/4.0.0 + dev: true + + registry.npmjs.org/globrex/0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz} + name: globrex + version: 0.1.2 + dev: true + registry.npmjs.org/graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz} name: graceful-fs @@ -2879,6 +3594,13 @@ packages: resolve-from: registry.npmjs.org/resolve-from/4.0.0 dev: true + registry.npmjs.org/import-lazy/4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz} + name: import-lazy + version: 4.0.0 + engines: {node: '>=8'} + dev: true + registry.npmjs.org/imurmurhash/0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz} name: imurmurhash @@ -3005,6 +3727,14 @@ packages: has-tostringtag: registry.npmjs.org/has-tostringtag/1.0.0 dev: true + registry.npmjs.org/is-docker/2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz} + name: is-docker + version: 2.2.1 + engines: {node: '>=8'} + hasBin: true + dev: true + registry.npmjs.org/is-extglob/2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz} name: is-extglob @@ -3166,6 +3896,15 @@ packages: engines: {node: '>=0.10.0'} dev: true + registry.npmjs.org/is-wsl/2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz} + name: is-wsl + version: 2.2.0 + engines: {node: '>=8'} + dependencies: + is-docker: registry.npmjs.org/is-docker/2.2.1 + dev: true + registry.npmjs.org/isarray/1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz} name: isarray @@ -3206,6 +3945,12 @@ packages: istanbul-lib-report: registry.npmjs.org/istanbul-lib-report/3.0.0 dev: true + registry.npmjs.org/jju/1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/jju/-/jju-1.4.0.tgz} + name: jju + version: 1.4.0 + dev: true + registry.npmjs.org/js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz} name: js-tokens @@ -3254,6 +3999,14 @@ packages: minimist: registry.npmjs.org/minimist/1.2.6 dev: true + registry.npmjs.org/jsonfile/4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz} + name: jsonfile + version: 4.0.0 + optionalDependencies: + graceful-fs: registry.npmjs.org/graceful-fs/4.2.10 + dev: true + registry.npmjs.org/jsonfile/6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz} name: jsonfile @@ -3271,6 +4024,16 @@ packages: engines: {'0': node >= 0.2.0} dev: true + registry.npmjs.org/jsx-ast-utils/3.3.3: + resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz} + name: jsx-ast-utils + version: 3.3.3 + engines: {node: '>=4.0'} + dependencies: + array-includes: registry.npmjs.org/array-includes/3.1.5 + object.assign: registry.npmjs.org/object.assign/4.1.4 + dev: true + registry.npmjs.org/kind-of/6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz} name: kind-of @@ -3278,6 +4041,20 @@ packages: engines: {node: '>=0.10.0'} dev: true + registry.npmjs.org/language-subtag-registry/0.3.22: + resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz} + name: language-subtag-registry + version: 0.3.22 + dev: true + + registry.npmjs.org/language-tags/1.0.5: + resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz} + name: language-tags + version: 1.0.5 + dependencies: + language-subtag-registry: registry.npmjs.org/language-subtag-registry/0.3.22 + dev: true + registry.npmjs.org/levn/0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/levn/-/levn-0.4.1.tgz} name: levn @@ -3372,6 +4149,18 @@ packages: p-locate: registry.npmjs.org/p-locate/5.0.0 dev: true + registry.npmjs.org/lodash.get/4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz} + name: lodash.get + version: 4.4.2 + dev: true + + registry.npmjs.org/lodash.isequal/4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz} + name: lodash.isequal + version: 4.5.0 + dev: true + registry.npmjs.org/lodash.map/4.6.0: resolution: {integrity: sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz} name: lodash.map @@ -3419,6 +4208,15 @@ packages: engines: {node: '>=0.10.0'} dev: true + registry.npmjs.org/loose-envify/1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz} + name: loose-envify + version: 1.4.0 + hasBin: true + dependencies: + js-tokens: registry.npmjs.org/js-tokens/4.0.0 + dev: true + registry.npmjs.org/loupe/2.3.4: resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz} name: loupe @@ -3698,6 +4496,13 @@ packages: boolbase: registry.npmjs.org/boolbase/1.0.0 dev: true + registry.npmjs.org/object-assign/4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz} + name: object-assign + version: 4.1.1 + engines: {node: '>=0.10.0'} + dev: true + registry.npmjs.org/object-inspect/1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz} name: object-inspect @@ -3731,7 +4536,27 @@ packages: dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 define-properties: registry.npmjs.org/define-properties/1.1.4 - es-abstract: registry.npmjs.org/es-abstract/1.20.2 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 + dev: true + + registry.npmjs.org/object.fromentries/2.0.5: + resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz} + name: object.fromentries + version: 2.0.5 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmjs.org/call-bind/1.0.2 + define-properties: registry.npmjs.org/define-properties/1.1.4 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 + dev: true + + registry.npmjs.org/object.hasown/1.1.1: + resolution: {integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz} + name: object.hasown + version: 1.1.1 + dependencies: + define-properties: registry.npmjs.org/define-properties/1.1.4 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 dev: true registry.npmjs.org/object.values/1.1.5: @@ -3742,7 +4567,7 @@ packages: dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 define-properties: registry.npmjs.org/define-properties/1.1.4 - es-abstract: registry.npmjs.org/es-abstract/1.20.2 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 dev: true registry.npmjs.org/once/1.4.0: @@ -3771,6 +4596,17 @@ packages: mimic-fn: registry.npmjs.org/mimic-fn/4.0.0 dev: true + registry.npmjs.org/open/8.4.0: + resolution: {integrity: sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/open/-/open-8.4.0.tgz} + name: open + version: 8.4.0 + engines: {node: '>=12'} + dependencies: + define-lazy-prop: registry.npmjs.org/define-lazy-prop/2.0.0 + is-docker: registry.npmjs.org/is-docker/2.2.1 + is-wsl: registry.npmjs.org/is-wsl/2.2.0 + dev: true + registry.npmjs.org/optionator/0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz} name: optionator @@ -3999,15 +4835,6 @@ packages: engines: {node: '>= 0.8.0'} dev: true - registry.npmjs.org/prettier-linter-helpers/1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz} - name: prettier-linter-helpers - version: 1.0.0 - engines: {node: '>=6.0.0'} - dependencies: - fast-diff: registry.npmjs.org/fast-diff/1.2.0 - dev: true - registry.npmjs.org/prettier/2.7.1: resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz} name: prettier @@ -4030,6 +4857,16 @@ packages: asap: registry.npmjs.org/asap/2.0.6 dev: true + registry.npmjs.org/prop-types/15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz} + name: prop-types + version: 15.8.1 + dependencies: + loose-envify: registry.npmjs.org/loose-envify/1.4.0 + object-assign: registry.npmjs.org/object-assign/4.1.1 + react-is: registry.npmjs.org/react-is/16.13.1 + dev: true + registry.npmjs.org/punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz} name: punycode @@ -4066,6 +4903,12 @@ packages: engines: {node: '>=8'} dev: true + registry.npmjs.org/react-is/16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz} + name: react-is + version: 16.13.1 + dev: true + registry.npmjs.org/read-pkg-up/7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz} name: read-pkg-up @@ -4133,6 +4976,12 @@ packages: strip-indent: registry.npmjs.org/strip-indent/3.0.0 dev: true + registry.npmjs.org/regenerator-runtime/0.13.9: + resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz} + name: regenerator-runtime + version: 0.13.9 + dev: true + registry.npmjs.org/regexp.prototype.flags/1.4.3: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz} name: regexp.prototype.flags @@ -4198,6 +5047,23 @@ packages: global-dirs: registry.npmjs.org/global-dirs/0.1.1 dev: true + registry.npmjs.org/resolve/1.17.0: + resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz} + name: resolve + version: 1.17.0 + dependencies: + path-parse: registry.npmjs.org/path-parse/1.0.7 + dev: true + + registry.npmjs.org/resolve/1.19.0: + resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz} + name: resolve + version: 1.19.0 + dependencies: + is-core-module: registry.npmjs.org/is-core-module/2.10.0 + path-parse: registry.npmjs.org/path-parse/1.0.7 + dev: true + registry.npmjs.org/resolve/1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz} name: resolve @@ -4209,6 +5075,17 @@ packages: supports-preserve-symlinks-flag: registry.npmjs.org/supports-preserve-symlinks-flag/1.0.0 dev: true + registry.npmjs.org/resolve/2.0.0-next.4: + resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz} + name: resolve + version: 2.0.0-next.4 + hasBin: true + dependencies: + is-core-module: registry.npmjs.org/is-core-module/2.10.0 + path-parse: registry.npmjs.org/path-parse/1.0.7 + supports-preserve-symlinks-flag: registry.npmjs.org/supports-preserve-symlinks-flag/1.0.0 + dev: true + registry.npmjs.org/restore-cursor/3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz} name: restore-cursor @@ -4241,10 +5118,10 @@ packages: glob: registry.npmjs.org/glob/7.2.3 dev: true - registry.npmjs.org/rollup/2.79.0: - resolution: {integrity: sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz} + registry.npmjs.org/rollup/2.79.1: + resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz} name: rollup - version: 2.79.0 + version: 2.79.1 engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: @@ -4286,6 +5163,16 @@ packages: version: 5.2.1 dev: true + registry.npmjs.org/safe-regex-test/1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz} + name: safe-regex-test + version: 1.0.0 + dependencies: + call-bind: registry.npmjs.org/call-bind/1.0.2 + get-intrinsic: registry.npmjs.org/get-intrinsic/1.1.3 + is-regex: registry.npmjs.org/is-regex/1.1.4 + dev: true + registry.npmjs.org/safer-buffer/2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz} name: safer-buffer @@ -4386,6 +5273,13 @@ packages: engines: {node: '>=8'} dev: true + registry.npmjs.org/slash/4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/slash/-/slash-4.0.0.tgz} + name: slash + version: 4.0.0 + engines: {node: '>=12'} + dev: true + registry.npmjs.org/slice-ansi/3.0.0: resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz} name: slice-ansi @@ -4476,6 +5370,12 @@ packages: readable-stream: registry.npmjs.org/readable-stream/3.6.0 dev: true + registry.npmjs.org/sprintf-js/1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz} + name: sprintf-js + version: 1.0.3 + dev: true + registry.npmjs.org/string-argv/0.3.1: resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz} name: string-argv @@ -4505,6 +5405,21 @@ packages: strip-ansi: registry.npmjs.org/strip-ansi/7.0.1 dev: true + registry.npmjs.org/string.prototype.matchall/4.0.7: + resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz} + name: string.prototype.matchall + version: 4.0.7 + dependencies: + call-bind: registry.npmjs.org/call-bind/1.0.2 + define-properties: registry.npmjs.org/define-properties/1.1.4 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 + get-intrinsic: registry.npmjs.org/get-intrinsic/1.1.3 + has-symbols: registry.npmjs.org/has-symbols/1.0.3 + internal-slot: registry.npmjs.org/internal-slot/1.0.3 + regexp.prototype.flags: registry.npmjs.org/regexp.prototype.flags/1.4.3 + side-channel: registry.npmjs.org/side-channel/1.0.4 + dev: true + registry.npmjs.org/string.prototype.trimend/1.0.5: resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz} name: string.prototype.trimend @@ -4512,7 +5427,7 @@ packages: dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 define-properties: registry.npmjs.org/define-properties/1.1.4 - es-abstract: registry.npmjs.org/es-abstract/1.20.2 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 dev: true registry.npmjs.org/string.prototype.trimstart/1.0.5: @@ -4522,7 +5437,7 @@ packages: dependencies: call-bind: registry.npmjs.org/call-bind/1.0.2 define-properties: registry.npmjs.org/define-properties/1.1.4 - es-abstract: registry.npmjs.org/es-abstract/1.20.2 + es-abstract: registry.npmjs.org/es-abstract/1.20.3 dev: true registry.npmjs.org/string_decoder/1.1.1: @@ -4647,6 +5562,23 @@ packages: get-port: registry.npmjs.org/get-port/3.2.0 dev: true + registry.npmjs.org/synckit/0.8.4: + resolution: {integrity: sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/synckit/-/synckit-0.8.4.tgz} + name: synckit + version: 0.8.4 + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/utils': registry.npmjs.org/@pkgr/utils/2.3.1 + tslib: registry.npmjs.org/tslib/2.4.0 + dev: true + + registry.npmjs.org/tapable/2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz} + name: tapable + version: 2.2.1 + engines: {node: '>=6'} + dev: true + registry.npmjs.org/test-exclude/6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz} name: test-exclude @@ -4704,6 +5636,15 @@ packages: readable-stream: registry.npmjs.org/readable-stream/3.6.0 dev: true + registry.npmjs.org/tiny-glob/0.2.9: + resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz} + name: tiny-glob + version: 0.2.9 + dependencies: + globalyzer: registry.npmjs.org/globalyzer/0.1.0 + globrex: registry.npmjs.org/globrex/0.1.2 + dev: true + registry.npmjs.org/tinypool/0.2.4: resolution: {integrity: sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/tinypool/-/tinypool-0.2.4.tgz} name: tinypool @@ -4808,12 +5749,31 @@ packages: strip-bom: registry.npmjs.org/strip-bom/3.0.0 dev: true + registry.npmjs.org/tslib/1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz} + name: tslib + version: 1.14.1 + dev: true + registry.npmjs.org/tslib/2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz} name: tslib version: 2.4.0 dev: true + registry.npmjs.org/tsutils/3.21.0_typescript@4.8.3: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz} + id: registry.npmjs.org/tsutils/3.21.0 + name: tsutils + version: 3.21.0 + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: registry.npmjs.org/tslib/1.14.1 + typescript: registry.npmjs.org/typescript/4.8.3 + dev: true + registry.npmjs.org/type-check/0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz} name: type-check @@ -4871,6 +5831,14 @@ packages: version: 0.0.6 dev: true + registry.npmjs.org/typescript/4.7.4: + resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz} + name: typescript + version: 4.7.4 + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + registry.npmjs.org/typescript/4.8.3: resolution: {integrity: sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz} name: typescript @@ -4890,6 +5858,13 @@ packages: which-boxed-primitive: registry.npmjs.org/which-boxed-primitive/1.0.2 dev: true + registry.npmjs.org/universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz} + name: universalify + version: 0.1.2 + engines: {node: '>= 4.0.0'} + dev: true + registry.npmjs.org/universalify/2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz} name: universalify @@ -4943,6 +5918,13 @@ packages: spdx-expression-parse: registry.npmjs.org/spdx-expression-parse/3.0.1 dev: true + registry.npmjs.org/validator/13.7.0: + resolution: {integrity: sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/validator/-/validator-13.7.0.tgz} + name: validator + version: 13.7.0 + engines: {node: '>= 0.10'} + dev: true + registry.npmjs.org/vite/3.0.5_sass@1.54.3: resolution: {integrity: sha512-bRvrt9Tw8EGW4jj64aYFTnVg134E8hgDxyl/eEHnxiGqYk7/pTPss6CWlurqPOUzqvEoZkZ58Ws+Iu8MB87iMA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/vite/-/vite-3.0.5.tgz} id: registry.npmjs.org/vite/3.0.5 @@ -4968,7 +5950,7 @@ packages: esbuild: registry.npmjs.org/esbuild/0.14.54 postcss: registry.npmjs.org/postcss/8.4.16 resolve: registry.npmjs.org/resolve/1.22.1 - rollup: registry.npmjs.org/rollup/2.79.0 + rollup: registry.npmjs.org/rollup/2.79.1 sass: registry.npmjs.org/sass/1.54.3 optionalDependencies: fsevents: registry.npmjs.org/fsevents/2.3.2 @@ -5270,3 +6252,17 @@ packages: version: 0.1.0 engines: {node: '>=10'} dev: true + + registry.npmjs.org/z-schema/5.0.4: + resolution: {integrity: sha512-gm/lx3hDzJNcLwseIeQVm1UcwhWIKpSB4NqH89pTBtFns4k/HDHudsICtvG05Bvw/Mv3jMyk700y5dadueLHdA==, registry: https://registry.yarnpkg.com/, tarball: https://registry.npmjs.org/z-schema/-/z-schema-5.0.4.tgz} + name: z-schema + version: 5.0.4 + engines: {node: '>=8.0.0'} + hasBin: true + dependencies: + lodash.get: registry.npmjs.org/lodash.get/4.4.2 + lodash.isequal: registry.npmjs.org/lodash.isequal/4.5.0 + validator: registry.npmjs.org/validator/13.7.0 + optionalDependencies: + commander: registry.npmjs.org/commander/2.20.3 + dev: true diff --git a/src/components/LazyHydrationWrapper.js b/src/components/LazyHydrationWrapper.js deleted file mode 100644 index 5df39d7..0000000 --- a/src/components/LazyHydrationWrapper.js +++ /dev/null @@ -1,84 +0,0 @@ -import { computed, defineComponent, markRaw, toRef } from 'vue'; - -import { - useLazyHydration, - useHydrateWhenIdle, - useHydrateWhenVisible, - useHydrateOnInteraction, - useHydrateWhenTriggered, -} from '../composables'; - -const normalizeSlot = (slotContent) => { - return slotContent.length === 1 ? slotContent[0] : slotContent; -}; - -export default markRaw( - defineComponent({ - name: 'LazyHydrationWrapper', - inheritAttrs: false, - suspensible: false, - props: { - whenIdle: { - default: false, - type: [Boolean, Number], - }, - whenVisible: { - default: false, - type: [Boolean, Object], - }, - onInteraction: { - default: false, - type: [Array, Boolean, String], - }, - whenTriggered: { - default: undefined, - type: [Boolean, Object], - }, - }, - emits: ['hydrated'], - - setup(props, { slots, emit }) { - const result = useLazyHydration(); - - if (!result.willPerformHydration) { - return () => normalizeSlot(slots.default()); - } - - result.onHydrated(() => emit('hydrated')); - - if (props.whenIdle) { - useHydrateWhenIdle( - result, - props.whenIdle !== true ? props.whenIdle : undefined - ); - } - - if (props.whenVisible) { - useHydrateWhenVisible( - result, - props.whenVisible !== true ? props.whenVisible : undefined - ); - } - - if (props.onInteraction) { - let events; - - if (props.onInteraction !== true) { - events = computed(() => - Array.isArray(props.onInteraction) - ? props.onInteraction - : [props.onInteraction] - ); - } - - useHydrateOnInteraction(result, events); - } - - if (props.whenTriggered !== undefined) { - useHydrateWhenTriggered(result, toRef(props, 'whenTriggered')); - } - - return () => normalizeSlot(slots.default()); - }, - }) -); diff --git a/src/components/LazyHydrationWrapper.spec.js b/src/components/LazyHydrationWrapper.spec.ts similarity index 97% rename from src/components/LazyHydrationWrapper.spec.js rename to src/components/LazyHydrationWrapper.spec.ts index a8e87db..cc06db1 100644 --- a/src/components/LazyHydrationWrapper.spec.js +++ b/src/components/LazyHydrationWrapper.spec.ts @@ -1,4 +1,4 @@ -import { createSSRApp, h, nextTick, ref } from 'vue'; +import { createSSRApp, h, nextTick, ref, type VNode } from 'vue'; import { renderToString } from '@vue/server-renderer'; import { flushPromises } from '@vue/test-utils'; @@ -11,7 +11,7 @@ import { triggerEvent } from '../../test/utils'; import LazyHydrationWrapper from './LazyHydrationWrapper'; -function mountWithHydration(html, template) { +function mountWithHydration(html: string, template: VNode) { const app = createSSRApp({ render: () => template, }); @@ -131,7 +131,7 @@ it('should hydrate when component element is visible', async () => { // trigger hydration and wait for it to complete intersectionObserver.simulate({ - target: container.querySelector('button'), + target: container.querySelector('button')!, isIntersecting: true, }); await nextTick(); @@ -308,7 +308,7 @@ it('should hydrate when component element is visible (full integration)', async // trigger hydration and wait for it to complete intersectionObserver.simulate({ - target: container.querySelector('button'), + target: container.querySelector('button')!, isIntersecting: true, }); await nextTick(); diff --git a/src/components/LazyHydrationWrapper.ts b/src/components/LazyHydrationWrapper.ts new file mode 100644 index 0000000..3dfeec6 --- /dev/null +++ b/src/components/LazyHydrationWrapper.ts @@ -0,0 +1,86 @@ +import { computed, defineComponent, markRaw, toRef, type VNode } from 'vue'; + +import { + useLazyHydration, + useHydrateWhenIdle, + useHydrateWhenVisible, + useHydrateOnInteraction, + useHydrateWhenTriggered, +} from '../composables'; + +const normalizeSlot = (slotContent: VNode[]) => + slotContent.length === 1 ? slotContent[0] : slotContent; + +const LazyHydrationWrapper = defineComponent({ + name: 'LazyHydrationWrapper', + inheritAttrs: false, + suspensible: false, + props: { + whenIdle: { + default: false, + type: [Boolean, Number], + }, + whenVisible: { + default: false, + type: [Boolean, Object], + }, + onInteraction: { + default: false, + type: [Array, Boolean, String], + }, + whenTriggered: { + default: undefined, + type: [Boolean, Object], + }, + }, + emits: ['hydrated'], + + setup(props, { slots, emit }) { + const result = useLazyHydration(); + + if (!result.willPerformHydration) { + return () => normalizeSlot(slots.default!()); + } + + result.onHydrated(() => emit('hydrated')); + + if (props.whenIdle) { + useHydrateWhenIdle( + result, + props.whenIdle !== true ? props.whenIdle : undefined + ); + } + + if (props.whenVisible) { + useHydrateWhenVisible( + result, + props.whenVisible !== true ? props.whenVisible : undefined + ); + } + + if (props.onInteraction) { + let events; + + if (props.onInteraction !== true) { + events = computed(() => + Array.isArray(props.onInteraction) + ? props.onInteraction + : [props.onInteraction] + ).value; + } + + useHydrateOnInteraction(result, events); + } + + if (props.whenTriggered !== undefined) { + useHydrateWhenTriggered(result, toRef(props, 'whenTriggered')); + } + + return () => normalizeSlot(slots.default!()); + }, +}); + +/** + * @public A renderless Vue.js component to lazy hydrate its children. + */ +export default markRaw(LazyHydrationWrapper) as typeof LazyHydrationWrapper; diff --git a/src/composables/index.js b/src/composables/index.ts similarity index 100% rename from src/composables/index.js rename to src/composables/index.ts diff --git a/src/composables/useHydrateOnInteraction.spec.js b/src/composables/useHydrateOnInteraction.spec.ts similarity index 88% rename from src/composables/useHydrateOnInteraction.spec.js rename to src/composables/useHydrateOnInteraction.spec.ts index 9ff6c56..6f65ef7 100644 --- a/src/composables/useHydrateOnInteraction.spec.js +++ b/src/composables/useHydrateOnInteraction.spec.ts @@ -72,7 +72,7 @@ it('should remove listeners when component has been hydrated', async () => { }); const spyRemoveEventListener = vi.spyOn( - container.querySelector('button'), + container.querySelector('button') as Element, 'removeEventListener' ); @@ -108,7 +108,7 @@ it('should remove listeners when component has been unmounted', async () => { }); const spyRemoveEventListener = vi.spyOn( - container.querySelector('button'), + container.querySelector('button') as Element, 'removeEventListener' ); @@ -122,13 +122,15 @@ it('should remove listeners when component has been unmounted', async () => { it('should hydrate on interaction when composedPath API is not supported', async () => { const spyClick = vi.fn(); - const triggerLegacyEvent = (type, el) => { - const event = new Event(type, { bubbles: true }); + const triggerLegacyEvent = (type: string, el: Element) => { + const event: (Omit & Partial) & { + path?: EventTarget; + } = new Event(type, { bubbles: true }); event.path = undefined; event.composedPath = undefined; - el.dispatchEvent(event); + el.dispatchEvent(event as Event); }; const { container } = await withSSRSetup(() => { @@ -140,15 +142,15 @@ it('should hydrate on interaction when composedPath API is not supported', async }); // hydration not complete yet - triggerLegacyEvent('click', container.querySelector('button')); + triggerLegacyEvent('click', container.querySelector('button') as Element); expect(spyClick).not.toHaveBeenCalled(); // trigger hydration and wait for it to complete - triggerLegacyEvent('focus', container.querySelector('button')); + triggerLegacyEvent('focus', container.querySelector('button') as Element); await flushPromises(); // should be hydrated now - triggerLegacyEvent('click', container.querySelector('button')); + triggerLegacyEvent('click', container.querySelector('button') as Element); expect(spyClick).toHaveBeenCalledOnce(); }); diff --git a/src/composables/useHydrateOnInteraction.js b/src/composables/useHydrateOnInteraction.ts similarity index 71% rename from src/composables/useHydrateOnInteraction.js rename to src/composables/useHydrateOnInteraction.ts index 2e85687..a12c8ed 100644 --- a/src/composables/useHydrateOnInteraction.js +++ b/src/composables/useHydrateOnInteraction.ts @@ -1,9 +1,17 @@ import { getCurrentInstance, onMounted, unref } from 'vue'; import getRootElements from '../utils/get-root-elements'; +import type useLazyHydration from './useLazyHydration'; +/** + * @public A Vue.js composable to delay hydration until a specified HTML event occurs on any component element. + */ export default function useHydrateOnInteraction( - { willPerformHydration, hydrate, onCleanup }, - events = ['focus'] + { + willPerformHydration, + hydrate, + onCleanup, + }: ReturnType, + events: (keyof HTMLElementEventMap)[] = ['focus'] ) { if (!willPerformHydration) { return; @@ -23,7 +31,7 @@ export default function useHydrateOnInteraction( const targets = getRootElements(instance); // container is the single root element or the parent element of the multiple root elements - const container = + const container: Element = targets.length > 1 ? targets[0].parentElement || document : targets[0]; const eventListenerOptions = { @@ -32,13 +40,13 @@ export default function useHydrateOnInteraction( passive: true, }; - const listener = (event) => { + const listener = (event: Event & { path?: EventTarget }) => { event.stopPropagation(); - const paths = event.path || (event.composedPath && event.composedPath()); + const paths = (event.composedPath && event.composedPath()) || event.path; if (!paths) { - let el = event.target; + let el = event.target as HTMLElement | null; while (el) { if (targets.includes(el)) { @@ -58,7 +66,7 @@ export default function useHydrateOnInteraction( } targets.forEach((target) => { - if (paths.includes(target)) { + if (paths.includes(target as EventTarget)) { hydrate(); } }); diff --git a/src/composables/useHydrateWhenIdle.spec.js b/src/composables/useHydrateWhenIdle.spec.ts similarity index 98% rename from src/composables/useHydrateWhenIdle.spec.js rename to src/composables/useHydrateWhenIdle.spec.ts index 9b1da5c..d676728 100644 --- a/src/composables/useHydrateWhenIdle.spec.js +++ b/src/composables/useHydrateWhenIdle.spec.ts @@ -123,7 +123,7 @@ it('should throw error when used outside of the setup or lifecycle hook method', 'useHydrateWhenIdle must be called from the setup or lifecycle hook methods.' ); - let result; + let result: ReturnType; const LazyComp = { setup() { diff --git a/src/composables/useHydrateWhenIdle.js b/src/composables/useHydrateWhenIdle.ts similarity index 71% rename from src/composables/useHydrateWhenIdle.js rename to src/composables/useHydrateWhenIdle.ts index 26e885e..ec42e5d 100644 --- a/src/composables/useHydrateWhenIdle.js +++ b/src/composables/useHydrateWhenIdle.ts @@ -1,7 +1,15 @@ import { getCurrentInstance } from 'vue'; +import type useLazyHydration from './useLazyHydration'; +/** + * @public A Vue.js composable to delay hydration until the browser is idle. + */ export default function useHydrateWhenIdle( - { willPerformHydration, hydrate, onCleanup }, + { + willPerformHydration, + hydrate, + onCleanup, + }: ReturnType, timeout = 2000 ) { if (!willPerformHydration) { diff --git a/src/composables/useHydrateWhenTriggered.spec.js b/src/composables/useHydrateWhenTriggered.spec.ts similarity index 96% rename from src/composables/useHydrateWhenTriggered.spec.js rename to src/composables/useHydrateWhenTriggered.spec.ts index a818b5a..42cc6db 100644 --- a/src/composables/useHydrateWhenTriggered.spec.js +++ b/src/composables/useHydrateWhenTriggered.spec.ts @@ -78,7 +78,7 @@ it('should throw error when used outside of the setup or lifecycle hook method', 'useHydrateWhenTriggered must be called from the setup or lifecycle hook methods.' ); - let result; + let result: ReturnType; const LazyComp = { setup() { @@ -91,7 +91,7 @@ it('should throw error when used outside of the setup or lifecycle hook method', const App = { setup() { function onClick() { - useHydrateWhenTriggered(result); + useHydrateWhenTriggered(result, () => true); } return () => [h('button', { onClick }, 'foo'), h(LazyComp)]; diff --git a/src/composables/useHydrateWhenTriggered.js b/src/composables/useHydrateWhenTriggered.ts similarity index 59% rename from src/composables/useHydrateWhenTriggered.js rename to src/composables/useHydrateWhenTriggered.ts index 9078c4f..6c591ad 100644 --- a/src/composables/useHydrateWhenTriggered.js +++ b/src/composables/useHydrateWhenTriggered.ts @@ -1,8 +1,16 @@ -import { watch, isRef, getCurrentInstance } from 'vue'; +import { watch, isRef, getCurrentInstance, type Ref } from 'vue'; +import type useLazyHydration from './useLazyHydration'; +/** + * @public A Vue.js composable to manually trigger hydration. + */ export default function useHydrateWhenTriggered( - { willPerformHydration, hydrate, onCleanup }, - trigger + { + willPerformHydration, + hydrate, + onCleanup, + }: ReturnType, + trigger: Ref | (() => boolean) ) { if (!willPerformHydration) { return; diff --git a/src/composables/useHydrateWhenVisible.spec.js b/src/composables/useHydrateWhenVisible.spec.ts similarity index 86% rename from src/composables/useHydrateWhenVisible.spec.js rename to src/composables/useHydrateWhenVisible.spec.ts index 8eaa71a..31582b9 100644 --- a/src/composables/useHydrateWhenVisible.spec.js +++ b/src/composables/useHydrateWhenVisible.spec.ts @@ -30,11 +30,17 @@ it('should hydrate when single root element is visible', async () => { // hydration not complete yet triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); - expect(container.querySelector('button').hydrate).toBeDefined(); + expect( + ( + container.querySelector('button') as Element & { + hydrate?: () => Promise; + } + ).hydrate + ).toBeDefined(); // make an element outside lazily hydrated component visible intersectionObserver.simulate({ - target: container.querySelector('div'), + target: container.querySelector('div') || undefined, isIntersecting: false, }); await flushPromises(); @@ -42,11 +48,17 @@ it('should hydrate when single root element is visible', async () => { // hydration not complete yet triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); - expect(container.querySelector('button').hydrate).toBeDefined(); + expect( + ( + container.querySelector('button') as Element & { + hydrate?: () => Promise; + } + ).hydrate + ).toBeDefined(); // trigger hydration and wait for it to complete intersectionObserver.simulate({ - target: container.querySelector('button'), + target: container.querySelector('button') || undefined, isIntersecting: true, }); await flushPromises(); @@ -54,7 +66,13 @@ it('should hydrate when single root element is visible', async () => { // should be hydrated now triggerEvent('click', container.querySelector('button')); expect(spyClick).toHaveBeenCalledOnce(); - expect(container.querySelector('button').hydrate).toBeUndefined(); + expect( + ( + container.querySelector('button') as Element & { + hydrate?: () => Promise; + } + ).hydrate + ).toBeUndefined(); intersectionObserver.restore(); }); @@ -81,7 +99,7 @@ it('should hydrate when one of multiple root elements is visible', async () => { // trigger hydration (intersect on second root element) and wait for it to complete intersectionObserver.simulate({ - target: container.querySelector('span'), + target: container.querySelector('span') || undefined, isIntersecting: true, }); await flushPromises(); @@ -120,7 +138,7 @@ it('should unobserve root elements when component has been unmounted', async () const show = ref(true); const { observer } = createHydrationObserver(); - const spyUnobserve = vi.spyOn(observer, 'unobserve'); + const spyUnobserve = vi.spyOn(observer!, 'unobserve'); await withSSRSetup(() => { const LazyComp = { diff --git a/src/composables/useHydrateWhenVisible.js b/src/composables/useHydrateWhenVisible.ts similarity index 67% rename from src/composables/useHydrateWhenVisible.js rename to src/composables/useHydrateWhenVisible.ts index 7148a14..9781e59 100644 --- a/src/composables/useHydrateWhenVisible.js +++ b/src/composables/useHydrateWhenVisible.ts @@ -1,9 +1,17 @@ import { getCurrentInstance, onMounted } from 'vue'; import { createHydrationObserver, getRootElements } from '../utils'; +import type useLazyHydration from './useLazyHydration'; +/** + * @public A Vue.js composable to delay hydration until one of the component's root elements is visible. + */ export default function useHydrateWhenVisible( - { willPerformHydration, hydrate, onCleanup }, - observerOptions + { + willPerformHydration, + hydrate, + onCleanup, + }: ReturnType, + observerOptions?: IntersectionObserverInit ) { if (!willPerformHydration) { return; @@ -32,14 +40,14 @@ export default function useHydrateWhenVisible( els.forEach((target) => { target.hydrate = hydrate; - observer.observe(target); + observer!.observe(target as Element); }); onCleanup(() => { els.forEach((target) => { delete target.hydrate; - observer.unobserve(target); + observer!.unobserve(target as Element); }); }); }); diff --git a/src/composables/useLazyHydration.spec.js b/src/composables/useLazyHydration.spec.ts similarity index 74% rename from src/composables/useLazyHydration.spec.js rename to src/composables/useLazyHydration.spec.ts index 25eaae0..26b2687 100644 --- a/src/composables/useLazyHydration.spec.js +++ b/src/composables/useLazyHydration.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-void */ /* eslint-disable no-underscore-dangle */ import { defineAsyncComponent, @@ -7,6 +8,8 @@ import { Suspense, onMounted, ref, + type Component, + type ComponentInternalInstance, } from 'vue'; import { flushPromises } from '@vue/test-utils'; @@ -14,10 +17,15 @@ import { withSSRSetup, triggerEvent, createApp } from '../../test/utils'; import { useLazyHydration } from '.'; +interface Result { + client: ReturnType | null; + server: ReturnType | null; +} + it('should delay hydration', async () => { - const result = { - client: {}, - server: {}, + const result: Result = { + client: null, + server: null, }; const spyClick = vi.fn(); @@ -28,15 +36,15 @@ it('should delay hydration', async () => { return () => h('button', { onClick: spyClick }, 'foo'); }); - expect(result.client.willPerformHydration).toBe(true); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBe(true); + expect(result.server?.willPerformHydration).toBe(false); // hydration not complete yet triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); // trigger hydration and wait for it to complete - result.client.hydrate(); + void result.client!.hydrate!(); await flushPromises(); // should be hydrated now @@ -45,9 +53,9 @@ it('should delay hydration', async () => { }); it('should run onCleanup hook when component has been unmounted', async () => { - const result = { - client: {}, - server: {}, + const result: Result = { + client: null, + server: null, }; const spyCleanup = vi.fn(); @@ -60,7 +68,7 @@ it('should run onCleanup hook when component has been unmounted', async () => { result[isClient ? 'client' : 'server'] = useLazyHydration(); if (isClient) { - result.client.onCleanup(spyCleanup); + result.client!.onCleanup!(spyCleanup); } return () => h('button', 'foo'); @@ -79,9 +87,9 @@ it('should run onCleanup hook when component has been unmounted', async () => { }); it('should not update component if hydration is delayed', async () => { - const result = { - client: {}, - server: {}, + const result: Result = { + client: null, + server: null, }; const spyClick = vi.fn(); @@ -100,8 +108,8 @@ it('should not update component if hydration is delayed', async () => { return () => h('div', h(LazyComp, { style: { color: color.value } })); }); - expect(result.client.willPerformHydration).toBe(true); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBe(true); + expect(result.server?.willPerformHydration).toBe(false); // should have not been hydrated triggerEvent('click', container.querySelector('button')); @@ -114,44 +122,44 @@ it('should not update component if hydration is delayed', async () => { // should have not been updated triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); - expect(container.querySelector('button').style.color).toBe('red'); + expect(container.querySelector('button')?.style.color).toBe('red'); }); it('should update props even if hydration is delayed', async () => { - const result = { - client: {}, - server: {}, + const result: Result = { + client: null, + server: null, }; const spyClick = vi.fn(); const bar = ref(false); - let lazyCompInstance; + let lazyCompInstance: ComponentInternalInstance | null; const { container } = await withSSRSetup((isClient) => { - const LazyComp = { + const LazyComp: Component = { props: ['foo'], setup(props) { result[isClient ? 'client' : 'server'] = useLazyHydration(); lazyCompInstance = getCurrentInstance(); - return () => h('button', { onClick: spyClick }, props.foo); + return () => h('button', { onClick: spyClick }, props.foo as boolean); }, }; return () => h('div', h(LazyComp, { foo: bar.value })); }); - expect(result.client.willPerformHydration).toBe(true); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBe(true); + expect(result.server?.willPerformHydration).toBe(false); // should have not been hydrated triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); - expect(container.querySelector('button').innerText).toBe('false'); - expect(lazyCompInstance.props.foo).toBeFalsy(); + expect(container.querySelector('button')?.innerText).toBe('false'); + expect(lazyCompInstance!.props.foo).toBeFalsy(); // update props and wait for it to complete bar.value = true; @@ -160,48 +168,48 @@ it('should update props even if hydration is delayed', async () => { // should have only updated props triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); - expect(container.querySelector('button').innerText).toBe('false'); - expect(lazyCompInstance.props.foo).toBeTruthy(); + expect(container.querySelector('button')?.innerText).toBe('false'); + expect(lazyCompInstance!.props.foo).toBeTruthy(); }); it('should update props even if hydration is delayed (with Suspense)', async () => { // is an experimental feature and its API will likely change. vi.spyOn(console, 'info').mockImplementation(() => {}); - const result = { - client: {}, - server: {}, + const result: Result = { + client: null, + server: null, }; const spyClick = vi.fn(); const bar = ref(false); - let lazyCompInstance; + let lazyCompInstance: ComponentInternalInstance | null; const { container } = await withSSRSetup((isClient) => { - const LazyComp = { + const LazyComp: Component = { props: ['foo'], setup(props) { result[isClient ? 'client' : 'server'] = useLazyHydration(); lazyCompInstance = getCurrentInstance(); - return () => h('button', { onClick: spyClick }, props.foo); + return () => h('button', { onClick: spyClick }, props.foo as boolean); }, }; return () => h(Suspense, h(LazyComp, { foo: bar.value })); }); - expect(result.client.willPerformHydration).toBe(true); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBe(true); + expect(result.server?.willPerformHydration).toBe(false); // should have not been hydrated triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); - expect(container.querySelector('button').innerText).toBe('false'); - expect(lazyCompInstance.props.foo).toBeFalsy(); + expect(container.querySelector('button')?.innerText).toBe('false'); + expect(lazyCompInstance!.props.foo).toBeFalsy(); // update props and wait for it to complete bar.value = true; @@ -210,23 +218,23 @@ it('should update props even if hydration is delayed (with Suspense)', async () // should have only updated props triggerEvent('click', container.querySelector('button')); expect(spyClick).not.toHaveBeenCalled(); - expect(container.querySelector('button').innerText).toBe('false'); - expect(lazyCompInstance.props.foo).toBeTruthy(); + expect(container.querySelector('button')?.innerText).toBe('false'); + expect(lazyCompInstance!.props.foo).toBeTruthy(); vi.restoreAllMocks(); }); it('should not break if the parent is a renderless component and has been updated', async () => { - const result = { - client: {}, - server: {}, + const result: Result = { + client: null, + server: null, }; const spyClick = vi.fn(); const foo = ref(false); - let lazyCompInstance; + let lazyCompInstance: ComponentInternalInstance | null; const { container } = await withSSRSetup((isClient) => { const LazyComp = defineComponent({ @@ -242,7 +250,7 @@ it('should not break if the parent is a renderless component and has been update const AsyncComp = defineAsyncComponent( () => new Promise((resolve) => { - resolve(LazyComp); + resolve(LazyComp as never); }) ); @@ -255,14 +263,14 @@ it('should not break if the parent is a renderless component and has been update ); }); - expect(result.client.willPerformHydration).toBeUndefined(); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBeUndefined(); + expect(result.server?.willPerformHydration).toBe(false); // wait for the lazy hydrated component to be resolved by async wrapper await flushPromises(); - expect(result.client.willPerformHydration).toBe(true); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBe(true); + expect(result.server?.willPerformHydration).toBe(false); // should have not been hydrated yet triggerEvent('click', container.querySelector('button')); @@ -273,7 +281,7 @@ it('should not break if the parent is a renderless component and has been update await flushPromises(); // parent component should still have a subtree element - expect(lazyCompInstance.parent.subTree.el).not.toBeNull(); + expect(lazyCompInstance!.parent?.subTree.el).not.toBeNull(); // should have not been hydrated yet triggerEvent('click', container.querySelector('button')); @@ -289,7 +297,7 @@ it('should not break if the parent is a renderless component and has been update ).not.toHaveBeenWarned(); // trigger hydration and wait for it to complete - result.client.hydrate(); + void result.client!.hydrate!(); await flushPromises(); // should be hydrated now @@ -301,9 +309,9 @@ it('should not break if the parent is a renderless component and has been update }); it('should run onHydrated hook when component has been hydrated', async () => { - const result = { - client: {}, - server: {}, + const result: Result = { + client: null, + server: null, }; const spyClick = vi.fn(); @@ -315,7 +323,7 @@ it('should run onHydrated hook when component has been hydrated', async () => { result[isClient ? 'client' : 'server'] = useLazyHydration(); if (isClient) { - result.client.onHydrated(spyOnHydratedHook); + result.client?.onHydrated(spyOnHydratedHook); } return () => h('button', { onClick: spyClick }, 'foo'); @@ -325,8 +333,8 @@ it('should run onHydrated hook when component has been hydrated', async () => { return () => h(LazyComp); }); - expect(result.client.willPerformHydration).toBe(true); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBe(true); + expect(result.server?.willPerformHydration).toBe(false); // hydration not complete yet triggerEvent('click', container.querySelector('button')); @@ -334,7 +342,7 @@ it('should run onHydrated hook when component has been hydrated', async () => { expect(spyOnHydratedHook).not.toHaveBeenCalled(); // trigger hydration and wait for it to complete - result.client.hydrate(); + void result.client!.hydrate!(); expect(spyOnHydratedHook).not.toHaveBeenCalled(); await flushPromises(); @@ -345,10 +353,11 @@ it('should run onHydrated hook when component has been hydrated', async () => { }); it('should run onHydrated hook when component has been hydrated and its children async components resolved', async () => { - const result = { - client: {}, - server: {}, - }; + const result: Result & { client: { resolveAsyncComp?: () => void } | null } = + { + client: null, + server: null, + }; const spyClick = vi.fn(); const spyAsyncCompClick = vi.fn(); @@ -359,9 +368,9 @@ it('should run onHydrated hook when component has been hydrated and its children setup() { result[isClient ? 'client' : 'server'] = useLazyHydration(); - let resolveAsyncComp; + let resolveAsyncComp!: () => void; - const promise = new Promise((resolve) => { + const promise: Promise = new Promise((resolve) => { resolveAsyncComp = () => resolve({ setup() { @@ -378,8 +387,8 @@ it('should run onHydrated hook when component has been hydrated and its children if (!isClient) { resolveAsyncComp(); } else { - result.client.resolveAsyncComp = resolveAsyncComp; - result.client.onHydrated(spyOnHydratedHook); + result.client!.resolveAsyncComp = resolveAsyncComp; + result.client!.onHydrated(spyOnHydratedHook); } return () => [ @@ -392,8 +401,8 @@ it('should run onHydrated hook when component has been hydrated and its children return () => h(LazyComp); }); - expect(result.client.willPerformHydration).toBe(true); - expect(result.server.willPerformHydration).toBe(false); + expect(result.client?.willPerformHydration).toBe(true); + expect(result.server?.willPerformHydration).toBe(false); // hydration not complete yet triggerEvent('click', container.querySelector('button.lazy')); @@ -404,7 +413,7 @@ it('should run onHydrated hook when component has been hydrated and its children expect(spyOnHydratedHook).not.toHaveBeenCalled(); // trigger hydration and wait for it to complete - result.client.hydrate(); + result.client!.hydrate!(); await flushPromises(); // should be hydrated now @@ -416,7 +425,7 @@ it('should run onHydrated hook when component has been hydrated and its children expect(spyOnHydratedHook).not.toHaveBeenCalled(); // wait for resolved async component - result.client.resolveAsyncComp(); + result.client!.resolveAsyncComp!(); await flushPromises(); triggerEvent('click', container.querySelector('button.async')); @@ -424,7 +433,7 @@ it('should run onHydrated hook when component has been hydrated and its children expect(spyOnHydratedHook).toHaveBeenCalledOnce(); }); -it('should throw error when used outside of the setup method', async () => { +it('should throw error when used outside of the setup method', () => { const handler = vi.fn(); const err = new Error( 'useLazyHydration must be called from the setup method.' diff --git a/src/composables/useLazyHydration.js b/src/composables/useLazyHydration.ts similarity index 67% rename from src/composables/useLazyHydration.js rename to src/composables/useLazyHydration.ts index 51f3fa9..f7fca02 100644 --- a/src/composables/useLazyHydration.js +++ b/src/composables/useLazyHydration.ts @@ -1,6 +1,15 @@ /* eslint-disable no-underscore-dangle */ -import { getCurrentInstance, nextTick, onBeforeMount, onUnmounted } from 'vue'; +import { + type ComponentInternalInstance, + type ConcreteComponent, + getCurrentInstance, + nextTick, + onBeforeMount, + onUnmounted, + type VNodeTypes, + type VNodeChild, +} from 'vue'; import { trackDepsOnRender, @@ -10,6 +19,17 @@ import { ensureParentHasSubTreeEl, } from '../utils'; +export type ExtendedVnodeTypes = VNodeTypes & { __isLazilyHydrated?: boolean }; +export type ExtendedConcreteComponent = ConcreteComponent & { + __asyncLoader?: () => Promise; +}; +export type ExtendedComponentInternalInstance = ComponentInternalInstance & { + asyncDep: Promise | null; +}; + +/** + * @public A Vue.js composable to delay hydration until the hydrate function is called. + */ export default function useLazyHydration() { const instance = getCurrentInstance(); @@ -29,7 +49,7 @@ export default function useLazyHydration() { * Components should be wrapped with defineAsyncComponent() * to let the bundler doing code-splitting. */ - instance.vnode.type.__isLazilyHydrated = true; + (instance.vnode.type as ExtendedVnodeTypes).__isLazilyHydrated = true; if (!willPerformHydration) { /** @@ -47,7 +67,7 @@ export default function useLazyHydration() { onResolvedPromise: onBeforeHydrate, } = createHydrationPromise(cleanup); - const onHydrated = (cb) => + const onHydrated = (cb: () => void) => onBeforeHydrate(() => nextTick(() => waitForAsyncComponents(instance, cb))); /** @@ -55,7 +75,7 @@ export default function useLazyHydration() { * This delays hydration until the promise is resolved. * @see https://github.com/vuejs/core/blob/v3.2.36/packages/runtime-core/src/renderer.ts#L1361&L1369 */ - instance.type.__asyncLoader = () => promise; + (instance.type as ExtendedConcreteComponent).__asyncLoader = () => promise; /** * In some cases the parent subtree element might be set to null @@ -64,7 +84,9 @@ export default function useLazyHydration() { * It occurs when the parent is a renderless component (an async wrapper for example) * and has been updated before the actual component has been hydrated. */ - ensureParentHasSubTreeEl(instance.parent); + ensureParentHasSubTreeEl( + instance.parent as ComponentInternalInstance & { u: null | (() => void)[] } + ); /** * In case a parent triggers an update, @@ -72,9 +94,10 @@ export default function useLazyHydration() { * @see https://github.com/vuejs/core/blob/v3.2.36/packages/runtime-core/src/renderer.ts#L1269&L1275 */ onBeforeMount(() => { - instance.asyncDep = new Promise((r) => { - r(true); - }); + (instance as ExtendedComponentInternalInstance).asyncDep = + new Promise((r) => { + r(true); + }); }); onBeforeHydrate(() => { @@ -84,10 +107,14 @@ export default function useLazyHydration() { * * Re-run the reactive effect in sync with the render call. */ - trackDepsOnRender(instance); + trackDepsOnRender( + instance as ComponentInternalInstance & { + render: () => VNodeChild; + } + ); // allow subsequent full updates - instance.asyncDep = null; + (instance as ExtendedComponentInternalInstance).asyncDep = null; }); onUnmounted(cleanup); diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..04cc0ec --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/naming-convention, no-underscore-dangle +declare const __DEV__: string; diff --git a/src/index.js b/src/index.ts similarity index 100% rename from src/index.js rename to src/index.ts diff --git a/src/utils/create-hydration-cleanup.js b/src/utils/create-hydration-cleanup.ts similarity index 65% rename from src/utils/create-hydration-cleanup.js rename to src/utils/create-hydration-cleanup.ts index 970152c..3c09ac6 100644 --- a/src/utils/create-hydration-cleanup.js +++ b/src/utils/create-hydration-cleanup.ts @@ -1,13 +1,13 @@ export default function createHydrationCleanup() { - let cleanups = []; + let cleanups: (() => void)[] = []; - const onCleanup = (cb) => { + const onCleanup = (cb: () => void) => { cleanups.push(cb); }; const cleanup = () => { // run each cleaning function then remove it from array - cleanups = cleanups.filter((fn) => { + cleanups = cleanups.filter((fn: () => void) => { fn(); return false; diff --git a/src/utils/create-hydration-observer.js b/src/utils/create-hydration-observer.js deleted file mode 100644 index c03a787..0000000 --- a/src/utils/create-hydration-observer.js +++ /dev/null @@ -1,35 +0,0 @@ -const observers = new Map(); - -export default function createHydrationObserver(options) { - const supported = typeof IntersectionObserver !== 'undefined'; - - if (!supported) { - return { supported }; - } - - const optionKey = JSON.stringify(options); - - if (observers.has(optionKey)) { - return { supported, observer: observers.get(optionKey) }; - } - - const observer = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - // Use `intersectionRatio` because of Edge 15's - // lack of support for `isIntersecting`. - // See: https://github.com/w3c/IntersectionObserver/issues/211 - const isIntersecting = - entry.isIntersecting || entry.intersectionRatio > 0; - - if (!isIntersecting || !entry.target.hydrate) { - return; - } - - entry.target.hydrate(); - }); - }, options); - - observers.set(optionKey, observer); - - return { supported, observer }; -} diff --git a/src/utils/create-hydration-observer.ts b/src/utils/create-hydration-observer.ts new file mode 100644 index 0000000..6f48cb9 --- /dev/null +++ b/src/utils/create-hydration-observer.ts @@ -0,0 +1,46 @@ +const observers = new Map(); + +export default function createHydrationObserver( + options?: IntersectionObserverInit +): { + supported: boolean; + observer?: IntersectionObserver; +} { + const supported = typeof IntersectionObserver !== 'undefined'; + + if (!supported) { + return { supported }; + } + + const optionKey = JSON.stringify(options); + + if (observers.has(optionKey)) { + return { supported, observer: observers.get(optionKey) }; + } + + const observer = new IntersectionObserver((entries) => { + entries.forEach( + ( + entry: IntersectionObserverEntry & { + target: { hydrate?: () => Promise }; + } + ) => { + // Use `intersectionRatio` because of Edge 15's + // lack of support for `isIntersecting`. + // See: https://github.com/w3c/IntersectionObserver/issues/211 + const isIntersecting = + entry.isIntersecting || entry.intersectionRatio > 0; + + if (!isIntersecting || !entry.target.hydrate) { + return; + } + + entry.target.hydrate(); + } + ); + }, options); + + observers.set(optionKey, observer); + + return { supported, observer }; +} diff --git a/src/utils/create-hydration-promise.js b/src/utils/create-hydration-promise.js deleted file mode 100644 index c51c3f1..0000000 --- a/src/utils/create-hydration-promise.js +++ /dev/null @@ -1,21 +0,0 @@ -export default function createHydrationPromise(cleanup) { - let resolvePromise = () => {}; - - const promise = new Promise((resolve) => { - resolvePromise = () => { - cleanup(); - - resolve(); - }; - }); - - const onResolvedPromise = (cb) => { - promise.then(cb); - }; - - return { - promise, - resolvePromise, - onResolvedPromise, - }; -} diff --git a/src/utils/create-hydration-promise.ts b/src/utils/create-hydration-promise.ts new file mode 100644 index 0000000..de961ba --- /dev/null +++ b/src/utils/create-hydration-promise.ts @@ -0,0 +1,22 @@ +export default function createHydrationPromise(cleanup: () => void) { + let resolvePromise: () => void | Promise = () => {}; + + const promise = new Promise((resolve) => { + resolvePromise = () => { + cleanup(); + + resolve(); + }; + }); + + const onResolvedPromise = (cb: () => void | Promise) => { + // eslint-disable-next-line no-void + void promise.then(cb); + }; + + return { + promise, + resolvePromise, + onResolvedPromise, + }; +} diff --git a/src/utils/create-hydration-wrapper.spec.js b/src/utils/create-hydration-wrapper.spec.ts similarity index 87% rename from src/utils/create-hydration-wrapper.spec.js rename to src/utils/create-hydration-wrapper.spec.ts index 6834e45..bf0b105 100644 --- a/src/utils/create-hydration-wrapper.spec.js +++ b/src/utils/create-hydration-wrapper.spec.ts @@ -1,4 +1,13 @@ -import { h, createApp as createClientApp, ref, nextTick } from 'vue'; +import { + h, + createApp as createClientApp, + ref, + nextTick, + type RendererElement, + type RendererNode, + type VNode, + type ConcreteComponent, +} from 'vue'; import { renderToString } from '@vue/server-renderer'; import { flushPromises } from '@vue/test-utils'; @@ -25,9 +34,7 @@ it('should handle error at server-side', async () => { // make sure window is undefined at server-side vi.stubGlobal('window', undefined); - const app = createApp(() => { - return () => h(WrappedComp); - }); + const app = createApp(() => () => h(WrappedComp)); app.config.errorHandler = handler; @@ -45,9 +52,11 @@ it('should handle error at client-side when hydrating', async () => { const spyClick = vi.fn(); const err = new Error('foo'); - let resolve; - let reject; - let hydrate; + let resolve!: ( + arg0: () => VNode + ) => void; + let reject!: (arg0: Error) => void; + let hydrate!: () => void | Promise; // pre-rendered html const container = document.createElement('div'); @@ -61,13 +70,11 @@ it('should handle error at client-side when hydrating', async () => { reject = _reject; }), (result) => { - hydrate = result.hydrate; + hydrate = result.hydrate!; } ); - const app = createApp(() => { - return () => h(WrappedComp); - }); + const app = createApp(() => () => h(WrappedComp)); app.config.errorHandler = handler; @@ -103,8 +110,8 @@ it('should handle error at client-side without hydration', async () => { const handler = vi.fn(); const err = new Error('foo'); - let resolve; - let reject; + let resolve!: (arg0: ConcreteComponent) => void; + let reject!: (arg0: Error) => void; const container = document.createElement('div'); document.append(container); @@ -171,9 +178,7 @@ it('should handle error when load result is invalid', async () => { // make sure window is undefined at server-side vi.stubGlobal('window', undefined); - const app = createApp(() => { - return () => h(WrappedComp); - }); + const app = createApp(() => () => h(WrappedComp)); app.config.errorHandler = handler; @@ -197,9 +202,7 @@ it('should warn when component loader resolved to undefined', async () => { // make sure window is undefined at server-side vi.stubGlobal('window', undefined); - const app = createApp(() => { - return () => h(WrappedComp); - }); + const app = createApp(() => () => h(WrappedComp)); await renderToString(app); diff --git a/src/utils/create-hydration-wrapper.js b/src/utils/create-hydration-wrapper.ts similarity index 69% rename from src/utils/create-hydration-wrapper.js rename to src/utils/create-hydration-wrapper.ts index c6fb62c..10275e5 100644 --- a/src/utils/create-hydration-wrapper.js +++ b/src/utils/create-hydration-wrapper.ts @@ -7,11 +7,18 @@ import { ref, createVNode, handleError, + type Component, + type ComponentInternalInstance, + type ConcreteComponent, + type AsyncComponentLoader, } from 'vue'; import { isFunction, isObject } from './helpers'; import { useLazyHydration } from '../composables'; -function createInnerComp(comp, { vnode: { ref: refOwner, props, children } }) { +function createInnerComp( + comp: ConcreteComponent, + { vnode: { ref: refOwner, props, children } }: ComponentInternalInstance +) { const vnode = createVNode(comp, props, children); // ensure inner component inherits the lazy hydrate wrapper's ref owner @@ -20,16 +27,21 @@ function createInnerComp(comp, { vnode: { ref: refOwner, props, children } }) { return vnode; } -export default function createHydrationWrapper(source, onSetup) { - let pendingRequest; - let resolvedComp; +export default function createHydrationWrapper( + source: Component | AsyncComponentLoader, + onSetup: (result: ReturnType) => void +): Component { + let pendingRequest: Promise | null = null; + let resolvedComp: ConcreteComponent | undefined; - const loader = isFunction(source) ? source : () => Promise.resolve(source); + const loader = isFunction(source) + ? (source as AsyncComponentLoader) + : () => Promise.resolve(source); const load = () => { - let thisRequest; + let thisRequest: Promise; - if (pendingRequest) { + if (pendingRequest !== null) { return pendingRequest; } @@ -39,8 +51,8 @@ export default function createHydrationWrapper(source, onSetup) { .catch((err) => { throw err instanceof Error ? err : new Error(String(err)); }) - .then((comp) => { - if (thisRequest !== pendingRequest && pendingRequest) { + .then((comp: any) => { + if (thisRequest !== pendingRequest && pendingRequest !== null) { return pendingRequest; } @@ -61,7 +73,9 @@ export default function createHydrationWrapper(source, onSetup) { if (__DEV__ && comp && !isObject(comp) && !isFunction(comp)) { throw new Error( - `Invalid async lazily hydrated wrapped component load result: ${comp}` + `Invalid async lazily hydrated wrapped component load result: ${ + comp as string + }` ); } @@ -85,10 +99,10 @@ export default function createHydrationWrapper(source, onSetup) { setup(_, { emit }) { const instance = getCurrentInstance(); - const onError = (err) => { + const onError = (err: unknown) => { pendingRequest = null; - handleError(err, instance, 'async component loader'); + handleError(err, instance, 13); }; const loaded = ref(false); @@ -97,9 +111,7 @@ export default function createHydrationWrapper(source, onSetup) { if (typeof window === 'undefined') { // on Server-side return load() - .then((comp) => { - return () => createInnerComp(comp, instance); - }) + .then((comp) => () => createInnerComp(comp, instance!)) .catch((err) => { onError(err); @@ -110,7 +122,7 @@ export default function createHydrationWrapper(source, onSetup) { if (!result.willPerformHydration) { // already resolved if (resolvedComp) { - return () => createInnerComp(resolvedComp, instance); + return () => createInnerComp(resolvedComp!, instance!); } load() @@ -123,7 +135,7 @@ export default function createHydrationWrapper(source, onSetup) { return () => { if (loaded.value && resolvedComp) { - return createInnerComp(resolvedComp, instance); + return createInnerComp(resolvedComp, instance!); } return null; @@ -138,7 +150,8 @@ export default function createHydrationWrapper(source, onSetup) { .then(() => { loaded.value = true; - hydrate(); + // eslint-disable-next-line no-void + void hydrate(); }) .catch((err) => { onError(err); @@ -148,7 +161,7 @@ export default function createHydrationWrapper(source, onSetup) { onSetup(result); - return () => createInnerComp(resolvedComp, instance); + return () => createInnerComp(resolvedComp!, instance!); }, }) ); diff --git a/src/utils/ensure-parent-has-subtree-el.js b/src/utils/ensure-parent-has-subtree-el.ts similarity index 74% rename from src/utils/ensure-parent-has-subtree-el.js rename to src/utils/ensure-parent-has-subtree-el.ts index ded8f49..e2aff88 100644 --- a/src/utils/ensure-parent-has-subtree-el.js +++ b/src/utils/ensure-parent-has-subtree-el.ts @@ -1,4 +1,8 @@ -export default function ensureParentHasSubTreeEl(parent) { +import type { ComponentInternalInstance } from 'vue'; + +export default function ensureParentHasSubTreeEl( + parent: ComponentInternalInstance & { u: null | (() => void)[] } +) { if (!parent || !parent.subTree) { return; } diff --git a/src/utils/get-root-elements.js b/src/utils/get-root-elements.js deleted file mode 100644 index 0d22fe0..0000000 --- a/src/utils/get-root-elements.js +++ /dev/null @@ -1,43 +0,0 @@ -const DOMNodeTypes = { - ELEMENT: 1, - TEXT: 3, - COMMENT: 8, -}; - -const isElement = (node) => node && node.nodeType === DOMNodeTypes.ELEMENT; -const isComment = (node) => node && node.nodeType === DOMNodeTypes.COMMENT; -const isFragmentStart = (node) => isComment(node) && node.data === '['; -const isFragmentEnd = (node) => isComment(node) && node.data === ']'; - -export default function getRootElements({ vnode, subTree }) { - if (!vnode || vnode.el === null) { - return []; - } - - // single Root Element - if (isElement(vnode.el)) { - return [vnode.el]; - } - - const els = []; - - // multiple Root Elements - if (subTree && isFragmentStart(subTree.el) && isFragmentEnd(subTree.anchor)) { - let node = vnode.el.nextSibling; - - while (node) { - if (node && isElement(node)) { - els.push(node); - } - - if (node === subTree.anchor) { - return els; - } - - node = node.nextSibling; - } - } - - // no elements found - return els; -} diff --git a/src/utils/get-root-elements.ts b/src/utils/get-root-elements.ts new file mode 100644 index 0000000..2ca0483 --- /dev/null +++ b/src/utils/get-root-elements.ts @@ -0,0 +1,52 @@ +import type { ComponentInternalInstance, RendererNode } from 'vue'; + +const DOMNodeTypes = { + ELEMENT: 1, + TEXT: 3, + COMMENT: 8, +}; + +const isElement = (node: RendererNode | null) => + node && node.nodeType === DOMNodeTypes.ELEMENT; +const isComment = (node: RendererNode | null) => + node && node.nodeType === DOMNodeTypes.COMMENT; +const isFragmentStart = (node: RendererNode | null) => + isComment(node) && node?.data === '['; +const isFragmentEnd = (node: RendererNode | null) => + isComment(node) && node?.data === ']'; + +export default function getRootElements({ + vnode, + subTree, +}: ComponentInternalInstance) { + if (!vnode || vnode.el === null) { + return []; + } + + // single Root Element + if (isElement(vnode.el)) { + return [vnode.el]; + } + + const els: Node[] = []; + + // multiple Root Elements + if (subTree && isFragmentStart(subTree.el) && isFragmentEnd(subTree.anchor)) { + let node = (vnode.el as Node).nextSibling; + + while (node) { + if (node && isElement(node)) { + els.push(node); + } + + if (node === subTree.anchor) { + return els; + } + + node = node.nextSibling; + } + } + + // no elements found + return els; +} diff --git a/src/utils/helpers.js b/src/utils/helpers.js deleted file mode 100644 index 44ec6e8..0000000 --- a/src/utils/helpers.js +++ /dev/null @@ -1,2 +0,0 @@ -export const isFunction = (val) => typeof val === 'function'; -export const isObject = (val) => val !== null && typeof val === 'object'; diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts new file mode 100644 index 0000000..47f5235 --- /dev/null +++ b/src/utils/helpers.ts @@ -0,0 +1,2 @@ +export const isFunction = (val: any) => typeof val === 'function'; +export const isObject = (val: any) => val !== null && typeof val === 'object'; diff --git a/src/utils/index.js b/src/utils/index.ts similarity index 100% rename from src/utils/index.js rename to src/utils/index.ts diff --git a/src/utils/track-deps-on-render.js b/src/utils/track-deps-on-render.ts similarity index 58% rename from src/utils/track-deps-on-render.js rename to src/utils/track-deps-on-render.ts index 2bdfdb8..379177d 100644 --- a/src/utils/track-deps-on-render.js +++ b/src/utils/track-deps-on-render.ts @@ -1,11 +1,17 @@ -export default function trackDepsOnRender(instance) { +import type { ComponentInternalInstance, VNodeChild } from 'vue'; + +export default function trackDepsOnRender( + instance: ComponentInternalInstance & { + render: () => VNodeChild; + } +) { const componentUpdateFn = instance.effect.fn; const originalRender = instance.render; instance.render = (...args) => { instance.effect.fn = () => originalRender(...args); - const result = instance.effect.run(); + const result = instance.effect.run() as VNodeChild; /** * Restore render and effect functions diff --git a/src/utils/traverse-children.js b/src/utils/traverse-children.js deleted file mode 100644 index 260b760..0000000 --- a/src/utils/traverse-children.js +++ /dev/null @@ -1,38 +0,0 @@ -import { isVNode } from 'vue'; -import { isFunction, isObject } from './helpers'; - -export default function traverseChildren(vnode, fn) { - if (!isVNode(vnode)) { - return; - } - - fn(vnode); - - if (vnode.children === null) { - return; - } - - if (Array.isArray(vnode.children)) { - vnode.children.forEach((child) => traverseChildren(child, fn)); - - return; - } - - if (isObject(vnode.children)) { - Object.keys(vnode.children).forEach((slotName) => { - if (!isFunction(vnode.children[slotName])) { - return; - } - - const slotContent = vnode.children[slotName](); - - if (Array.isArray(slotContent)) { - slotContent.forEach((child) => traverseChildren(child, fn)); - - return; - } - - traverseChildren(slotContent, fn); - }); - } -} diff --git a/src/utils/traverse-children.spec.js b/src/utils/traverse-children.spec.ts similarity index 76% rename from src/utils/traverse-children.spec.js rename to src/utils/traverse-children.spec.ts index e7f2cde..54a5d84 100644 --- a/src/utils/traverse-children.spec.js +++ b/src/utils/traverse-children.spec.ts @@ -1,4 +1,5 @@ -import { getCurrentInstance, h, onMounted } from 'vue'; +/* eslint-disable vue/one-component-per-file */ +import { defineComponent, getCurrentInstance, h, onMounted } from 'vue'; import { withSSRSetup } from '../../test/utils'; @@ -17,14 +18,14 @@ it('should traverse slots children with single element', async () => { } }); - const Child = { + const Child = defineComponent({ setup(_, { slots }) { - return () => slots.default(); + return () => slots.default && slots.default(); }, - }; + }); await withSSRSetup(() => { - const instance = getCurrentInstance(); + const instance = getCurrentInstance()!; onMounted(() => { traverseChildren(instance.subTree, spyFn); @@ -48,14 +49,14 @@ it('should traverse slots children with multiple elements', async () => { } }); - const Child = { + const Child = defineComponent({ setup(_, { slots }) { - return () => slots.default(); + return () => slots.default && slots.default(); }, - }; + }); await withSSRSetup(() => { - const instance = getCurrentInstance(); + const instance = getCurrentInstance()!; onMounted(() => { traverseChildren(instance.subTree, spyFn); diff --git a/src/utils/traverse-children.ts b/src/utils/traverse-children.ts new file mode 100644 index 0000000..74c3a06 --- /dev/null +++ b/src/utils/traverse-children.ts @@ -0,0 +1,54 @@ +import type { ExtendedConcreteComponent } from 'src/composables/useLazyHydration'; +import { isVNode, type Slots, type VNode, type VNodeChild } from 'vue'; +import { isFunction, isObject } from './helpers'; + +export default function traverseChildren( + vnode: + | (VNode & { + type: ExtendedConcreteComponent; + }) + | VNodeChild, + fn: ( + vnode: VNode & { + type: ExtendedConcreteComponent; + } + ) => void +) { + if (!isVNode(vnode)) { + return; + } + + fn( + vnode as VNode & { + type: ExtendedConcreteComponent; + } + ); + + if (vnode.children === null) { + return; + } + + if (Array.isArray(vnode.children)) { + vnode.children.forEach((child) => traverseChildren(child, fn)); + + return; + } + + if (isObject(vnode.children)) { + Object.keys(vnode.children).forEach((slotName) => { + if (!isFunction((vnode.children as Slots)[slotName])) { + return; + } + + const slotContent = (vnode.children as Slots)[slotName]!(); + + if (Array.isArray(slotContent)) { + slotContent.forEach((child) => traverseChildren(child, fn)); + + return; + } + + traverseChildren(slotContent, fn); + }); + } +} diff --git a/src/utils/wait-for-async-components.js b/src/utils/wait-for-async-components.js deleted file mode 100644 index b29ead3..0000000 --- a/src/utils/wait-for-async-components.js +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint-disable no-underscore-dangle */ - -import traverseChildren from './traverse-children'; - -function isAsyncWrapper(vnode) { - return ( - vnode.type && - vnode.type.__asyncLoader && - vnode.type.name === 'AsyncComponentWrapper' - ); -} - -export default function waitForAsyncComponents({ subTree }, cb) { - const promises = []; - - traverseChildren(subTree, (vnode) => { - if (isAsyncWrapper(vnode)) { - promises.push(vnode.type.__asyncLoader()); - } - }); - - if (promises.length > 0) { - Promise.all(promises).then(cb); - - return; - } - - cb(); -} diff --git a/src/utils/wait-for-async-components.ts b/src/utils/wait-for-async-components.ts new file mode 100644 index 0000000..fa8e422 --- /dev/null +++ b/src/utils/wait-for-async-components.ts @@ -0,0 +1,38 @@ +/* eslint-disable no-underscore-dangle */ + +import type { ExtendedConcreteComponent } from 'src/composables/useLazyHydration'; +import type { ComponentInternalInstance, VNode } from 'vue'; +import traverseChildren from './traverse-children'; + +function isAsyncWrapper( + vnode: + | VNode & { + type: ExtendedConcreteComponent; + } +) { + return ( + vnode.type?.__asyncLoader && vnode.type?.name === 'AsyncComponentWrapper' + ); +} + +export default function waitForAsyncComponents( + { subTree }: ComponentInternalInstance, + cb: () => void +) { + const promises: Promise[] = []; + + traverseChildren(subTree, (vnode) => { + if (isAsyncWrapper(vnode)) { + promises.push(vnode.type.__asyncLoader!()); + } + }); + + if (promises.length > 0) { + // eslint-disable-next-line no-void + void Promise.all(promises).then(cb); + + return; + } + + cb(); +} diff --git a/src/wrappers/hydrate-never.js b/src/wrappers/hydrate-never.js deleted file mode 100644 index 0fcf11b..0000000 --- a/src/wrappers/hydrate-never.js +++ /dev/null @@ -1,5 +0,0 @@ -import { createHydrationWrapper } from '../utils'; - -export default function hydrateNever(loader) { - return createHydrationWrapper(loader, () => {}); -} diff --git a/src/wrappers/hydrate-never.spec.js b/src/wrappers/hydrate-never.spec.ts similarity index 79% rename from src/wrappers/hydrate-never.spec.js rename to src/wrappers/hydrate-never.spec.ts index 436ff5e..cd8def9 100644 --- a/src/wrappers/hydrate-never.spec.js +++ b/src/wrappers/hydrate-never.spec.ts @@ -1,4 +1,4 @@ -import { h, onUpdated } from 'vue'; +import { defineComponent, h, onUpdated } from 'vue'; import { flushPromises } from '@vue/test-utils'; import { withSSRSetup, triggerEvent } from '../../test/utils'; @@ -13,17 +13,17 @@ it('should never hydrate and load the component', async () => { const spyClick = vi.fn(); const spyUpdated = vi.fn(); - const WrappedComp = hydrateNever({ - setup() { - onUpdated(spyUpdated); + const WrappedComp = hydrateNever( + defineComponent({ + setup() { + onUpdated(spyUpdated); - return () => h('button', { onClick: spyClick }, 'foo'); - }, - }); + return () => h('button', { onClick: spyClick }, 'foo'); + }, + }) + ); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); @@ -51,9 +51,7 @@ it('should never hydrate and load the component (with function)', async () => { }) ); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); diff --git a/src/wrappers/hydrate-never.ts b/src/wrappers/hydrate-never.ts new file mode 100644 index 0000000..a4b3853 --- /dev/null +++ b/src/wrappers/hydrate-never.ts @@ -0,0 +1,11 @@ +import type { AsyncComponentLoader, Component } from 'vue'; +import { createHydrationWrapper } from '../utils'; + +/** + * @public Wrap a Vue.js component in a renderless component so that it is never hydrated. + */ +export default function hydrateNever( + source: Component | AsyncComponentLoader +): Component { + return createHydrationWrapper(source, () => {}); +} diff --git a/src/wrappers/hydrate-on-interaction.js b/src/wrappers/hydrate-on-interaction.js deleted file mode 100644 index dc18b96..0000000 --- a/src/wrappers/hydrate-on-interaction.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useHydrateOnInteraction } from '../composables'; -import { createHydrationWrapper } from '../utils'; - -export default function hydrateOnInteraction(component, events = ['focus']) { - return createHydrationWrapper(component, (result) => { - useHydrateOnInteraction(result, events); - }); -} diff --git a/src/wrappers/hydrate-on-interaction.spec.js b/src/wrappers/hydrate-on-interaction.spec.ts similarity index 91% rename from src/wrappers/hydrate-on-interaction.spec.js rename to src/wrappers/hydrate-on-interaction.spec.ts index 992d83e..61d9c94 100644 --- a/src/wrappers/hydrate-on-interaction.spec.js +++ b/src/wrappers/hydrate-on-interaction.spec.ts @@ -21,9 +21,7 @@ it('should load the wrapped component just before hydration on interaction', asy }, }); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); @@ -54,9 +52,7 @@ it('should load the wrapped component just before hydration on interaction (with }) ); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); diff --git a/src/wrappers/hydrate-on-interaction.ts b/src/wrappers/hydrate-on-interaction.ts new file mode 100644 index 0000000..96c897b --- /dev/null +++ b/src/wrappers/hydrate-on-interaction.ts @@ -0,0 +1,15 @@ +import type { AsyncComponentLoader, Component } from 'vue'; +import { useHydrateOnInteraction } from '../composables'; +import { createHydrationWrapper } from '../utils'; + +/** + * @public Wrap a component in a renderless component so that it is hydrated when a specified HTML event occurs on one of its elements. + */ +export default function hydrateOnInteraction( + source: Component | AsyncComponentLoader, + events: (keyof HTMLElementEventMap)[] = ['focus'] +) { + return createHydrationWrapper(source, (result) => { + useHydrateOnInteraction(result, events); + }); +} diff --git a/src/wrappers/hydrate-when-idle.js b/src/wrappers/hydrate-when-idle.js deleted file mode 100644 index d3fd274..0000000 --- a/src/wrappers/hydrate-when-idle.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useHydrateWhenIdle } from '../composables'; -import { createHydrationWrapper } from '../utils'; - -export default function hydrateWhenIdle(component, timeout = 2000) { - return createHydrationWrapper(component, (result) => { - useHydrateWhenIdle(result, timeout); - }); -} diff --git a/src/wrappers/hydrate-when-idle.spec.js b/src/wrappers/hydrate-when-idle.spec.ts similarity index 92% rename from src/wrappers/hydrate-when-idle.spec.js rename to src/wrappers/hydrate-when-idle.spec.ts index d5d2a90..dcffdb2 100644 --- a/src/wrappers/hydrate-when-idle.spec.js +++ b/src/wrappers/hydrate-when-idle.spec.ts @@ -27,9 +27,7 @@ it('should load the wrapped component just before hydration when browser is idle }, }); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); @@ -63,9 +61,7 @@ it('should load the wrapped component just before hydration when browser is idle }) ); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); diff --git a/src/wrappers/hydrate-when-idle.ts b/src/wrappers/hydrate-when-idle.ts new file mode 100644 index 0000000..980faad --- /dev/null +++ b/src/wrappers/hydrate-when-idle.ts @@ -0,0 +1,15 @@ +import type { AsyncComponentLoader, Component } from 'vue'; +import { useHydrateWhenIdle } from '../composables'; +import { createHydrationWrapper } from '../utils'; + +/** + * @public Wrap a component in a renderless component so that it is hydrated when the browser is idle. + */ +export default function hydrateWhenIdle( + source: Component | AsyncComponentLoader, + timeout = 2000 +) { + return createHydrationWrapper(source, (result) => { + useHydrateWhenIdle(result, timeout); + }); +} diff --git a/src/wrappers/hydrate-when-triggered.js b/src/wrappers/hydrate-when-triggered.js deleted file mode 100644 index 9326f70..0000000 --- a/src/wrappers/hydrate-when-triggered.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useHydrateWhenTriggered } from '../composables'; -import { createHydrationWrapper } from '../utils'; - -export default function hydrateWhenTriggered(source, triggered) { - return createHydrationWrapper(source, (result) => { - useHydrateWhenTriggered(result, triggered); - }); -} diff --git a/src/wrappers/hydrate-when-triggered.spec.js b/src/wrappers/hydrate-when-triggered.spec.ts similarity index 91% rename from src/wrappers/hydrate-when-triggered.spec.js rename to src/wrappers/hydrate-when-triggered.spec.ts index de37fca..eaff0b9 100644 --- a/src/wrappers/hydrate-when-triggered.spec.js +++ b/src/wrappers/hydrate-when-triggered.spec.ts @@ -25,9 +25,7 @@ it('should load the wrapped component just before hydration when triggered', asy trigger ); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); @@ -61,9 +59,7 @@ it('should load the wrapped component just before hydration when triggered (with trigger ); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); diff --git a/src/wrappers/hydrate-when-triggered.ts b/src/wrappers/hydrate-when-triggered.ts new file mode 100644 index 0000000..5217bb1 --- /dev/null +++ b/src/wrappers/hydrate-when-triggered.ts @@ -0,0 +1,15 @@ +import type { AsyncComponentLoader, Component, Ref } from 'vue'; +import { useHydrateWhenTriggered } from '../composables'; +import { createHydrationWrapper } from '../utils'; + +/** + * @public Wrap a component in a renderless component so that it is hydrated when triggered. + */ +export default function hydrateWhenTriggered( + source: Component | AsyncComponentLoader, + triggered: Ref | (() => boolean) +) { + return createHydrationWrapper(source, (result) => { + useHydrateWhenTriggered(result, triggered); + }); +} diff --git a/src/wrappers/hydrate-when-visible.js b/src/wrappers/hydrate-when-visible.js deleted file mode 100644 index c8e10a7..0000000 --- a/src/wrappers/hydrate-when-visible.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useHydrateWhenVisible } from '../composables'; -import { createHydrationWrapper } from '../utils'; - -export default function hydrateWhenVisible(component, observerOpts) { - return createHydrationWrapper(component, (result) => { - useHydrateWhenVisible(result, observerOpts); - }); -} diff --git a/src/wrappers/hydrate-when-visible.spec.js b/src/wrappers/hydrate-when-visible.spec.ts similarity index 89% rename from src/wrappers/hydrate-when-visible.spec.js rename to src/wrappers/hydrate-when-visible.spec.ts index 68af2d0..6dcccdb 100644 --- a/src/wrappers/hydrate-when-visible.spec.js +++ b/src/wrappers/hydrate-when-visible.spec.ts @@ -27,9 +27,7 @@ it('should load the wrapped component just before hydration when component eleme }, }); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); @@ -37,7 +35,7 @@ it('should load the wrapped component just before hydration when component eleme // trigger hydration and wait for it to complete intersectionObserver.simulate({ - target: container.querySelector('button'), + target: container.querySelector('button') || undefined, isIntersecting: true, }); await flushPromises(); @@ -66,9 +64,7 @@ it('should load the wrapped component just before hydration when component eleme }) ); - const { container } = await withSSRSetup(() => { - return () => h(WrappedComp); - }); + const { container } = await withSSRSetup(() => () => h(WrappedComp)); // hydration not complete yet triggerEvent('click', container.querySelector('button')); @@ -76,7 +72,7 @@ it('should load the wrapped component just before hydration when component eleme // trigger hydration and wait for it to complete intersectionObserver.simulate({ - target: container.querySelector('button'), + target: container.querySelector('button') || undefined, isIntersecting: true, }); await flushPromises(); diff --git a/src/wrappers/hydrate-when-visible.ts b/src/wrappers/hydrate-when-visible.ts new file mode 100644 index 0000000..7b46718 --- /dev/null +++ b/src/wrappers/hydrate-when-visible.ts @@ -0,0 +1,15 @@ +import type { AsyncComponentLoader, Component } from 'vue'; +import { useHydrateWhenVisible } from '../composables'; +import { createHydrationWrapper } from '../utils'; + +/** + * @public Wrap a Vue.js component in a renderless component so that it is hydrated when one of the component's root elements is visible. + */ +export default function hydrateWhenVisible( + source: Component | AsyncComponentLoader, + observerOpts?: IntersectionObserverInit +) { + return createHydrationWrapper(source, (result) => { + useHydrateWhenVisible(result, observerOpts); + }); +} diff --git a/src/wrappers/index.js b/src/wrappers/index.ts similarity index 100% rename from src/wrappers/index.js rename to src/wrappers/index.ts diff --git a/test/dom-mocks/index.js b/test/dom-mocks/index.ts similarity index 84% rename from test/dom-mocks/index.js rename to test/dom-mocks/index.ts index 752fd92..d12bf2e 100644 --- a/test/dom-mocks/index.js +++ b/test/dom-mocks/index.ts @@ -4,7 +4,9 @@ import IntersectionObserver from './intersection-observer'; export const requestIdleCallback = new RequestIdleCallback(); export const intersectionObserver = new IntersectionObserver(); -const mocksToEnsureReset = { +const mocksToEnsureReset: { + [key: string]: typeof requestIdleCallback | typeof intersectionObserver; +} = { requestIdleCallback, intersectionObserver, }; diff --git a/test/dom-mocks/intersection-observer.js b/test/dom-mocks/intersection-observer.ts similarity index 60% rename from test/dom-mocks/intersection-observer.js rename to test/dom-mocks/intersection-observer.ts index 67c5a9f..980886a 100644 --- a/test/dom-mocks/intersection-observer.js +++ b/test/dom-mocks/intersection-observer.ts @@ -1,11 +1,27 @@ /* eslint-disable max-classes-per-file */ -function normalizeEntry(entry, target) { +interface Observer { + source: unknown; + target: Element; + callback: IntersectionObserverCallback; + options?: IntersectionObserverInit; +} + +interface WindowWithObserver extends Window { + intersectionObserver: Observer; +} + +function normalizeEntry( + entry: Partial, + target: Element +): IntersectionObserverEntry { const isIntersecting = entry.isIntersecting == null ? Boolean(entry.intersectionRatio) : entry.isIntersecting; + const intersectionRatio = entry.intersectionRatio || (isIntersecting ? 1 : 0); + return { boundingClientRect: entry.boundingClientRect || target.getBoundingClientRect(), @@ -19,15 +35,24 @@ function normalizeEntry(entry, target) { } export default class IntersectionObserverMock { - constructor() { - this.observers = []; - this.isUsingMockIntersectionObserver = false; - this.originalIntersectionObserver = global.IntersectionObserver; - this.originalIntersectionObserverEntry = global.IntersectionObserverEntry; - } + observers: Observer[] = []; + + private isUsingMockIntersectionObserver = false; + + private isMockingUnsupported = false; + + private originalIntersectionObserver = (global as any).IntersectionObserver; - simulate(entry) { + private originalIntersectionObserverEntry = (global as any) + .IntersectionObserverEntry; + + simulate( + entry: + | Partial + | Partial[] + ) { this.ensureMocked(); + const arrayOfEntries = Array.isArray(entry) ? entry : [entry]; const targets = arrayOfEntries.map(({ target }) => target); const noCustomTargets = targets.every((target) => target == null); @@ -38,7 +63,7 @@ export default class IntersectionObserverMock { arrayOfEntries.map((observerEntry) => normalizeEntry(observerEntry, observer.target) ), - observer + observer as any ); } }); @@ -53,11 +78,13 @@ export default class IntersectionObserverMock { this.isUsingMockIntersectionObserver = true; - const setObservers = (setter) => { + const setObservers = (setter: (observers: Observer[]) => Observer[]) => { this.observers = setter(this.observers); }; - global.IntersectionObserverEntry = class IntersectionObserverEntry {}; + ( + global as any + ).IntersectionObserverEntry = class IntersectionObserverEntry {}; Object.defineProperty( IntersectionObserverEntry.prototype, 'intersectionRatio', @@ -67,13 +94,14 @@ export default class IntersectionObserverMock { }, } ); - global.IntersectionObserver = class FakeIntersectionObserver { - constructor(callback, options) { - this.callback = callback; - this.options = options; - } - observe(target) { + (global as any).IntersectionObserver = class FakeIntersectionObserver { + constructor( + private callback: IntersectionObserverCallback, + private options?: IntersectionObserverInit + ) {} + + observe(target: Element) { setObservers((observers) => [ ...observers, { @@ -91,7 +119,7 @@ export default class IntersectionObserverMock { ); } - unobserve(target) { + unobserve(target: Element) { setObservers((observers) => observers.filter( (observer) => @@ -111,10 +139,11 @@ export default class IntersectionObserverMock { this.isUsingMockIntersectionObserver = true; this.isMockingUnsupported = true; - const windowIntersectionObserver = window; - this.originalIntersectionObserver = - windowIntersectionObserver.IntersectionObserver; - delete windowIntersectionObserver.IntersectionObserver; + + const windowWithObserver: WindowWithObserver = window as any; + + this.originalIntersectionObserver = windowWithObserver.intersectionObserver; + delete (windowWithObserver as any).intersectionObserver; } restore() { @@ -124,9 +153,12 @@ export default class IntersectionObserverMock { ); } - global.IntersectionObserver = this.originalIntersectionObserver; - global.IntersectionObserverEntry = this.originalIntersectionObserverEntry; + (global as any).IntersectionObserver = this.originalIntersectionObserver; + (global as any).IntersectionObserverEntry = + this.originalIntersectionObserverEntry; + this.isUsingMockIntersectionObserver = false; + this.isMockingUnsupported = false; this.observers.length = 0; } @@ -134,11 +166,17 @@ export default class IntersectionObserverMock { return this.isUsingMockIntersectionObserver; } - ensureMocked() { + private ensureMocked() { if (!this.isUsingMockIntersectionObserver) { throw new Error( 'You must call intersectionObserver.mock() before interacting with the fake IntersectionObserver.' ); } + + if (this.isMockingUnsupported) { + throw new Error( + 'You have mocked intersectionObserver as unsupported. Call intersectionObserver.restore(), then intersectionObserver.mock() if you want to simulate intersection Observer.' + ); + } } } diff --git a/test/dom-mocks/request-idle-callback.js b/test/dom-mocks/request-idle-callback.ts similarity index 58% rename from test/dom-mocks/request-idle-callback.js rename to test/dom-mocks/request-idle-callback.ts index 2e31f12..08cff68 100644 --- a/test/dom-mocks/request-idle-callback.js +++ b/test/dom-mocks/request-idle-callback.ts @@ -1,22 +1,38 @@ +type RequestIdleCallbackHandle = any; + +interface RequestIdleCallbackOptions { + timeout: number; +} + +interface RequestIdleCallbackDeadline { + readonly didTimeout: boolean; + timeRemaining(): number; +} + +type IdleCallback = (deadline: RequestIdleCallbackDeadline) => void; + +interface WindowWithRequestIdleCallback extends Window { + requestIdleCallback( + callback: IdleCallback, + opts?: RequestIdleCallbackOptions + ): RequestIdleCallbackHandle; + cancelIdleCallback: (handle: RequestIdleCallbackHandle) => void; +} + export default class RequestIdleCallback { - constructor() { - this.isUsingMockIdleCallback = false; - this.isMockingUnsupported = false; - this.queued = {}; - this.originalRequestIdleCallback = undefined; - this.originalCancelIdleCallback = undefined; - this.currentIdleCallback = 0; - - this.requestIdleCallback = (callback) => { - this.currentIdleCallback += 1; - this.queued[this.currentIdleCallback] = callback; - return this.currentIdleCallback; - }; - - this.cancelIdleCallback = (callback) => { - delete this.queued[callback]; - }; - } + private isUsingMockIdleCallback = false; + + private isMockingUnsupported = false; + + private queued: { + [key: string]: IdleCallback; + } = {}; + + private originalRequestIdleCallback: any; + + private originalCancelIdleCallback: any; + + private currentIdleCallback = 0; mock() { if (this.isUsingMockIdleCallback) { @@ -26,9 +42,12 @@ export default class RequestIdleCallback { } this.isUsingMockIdleCallback = true; - const windowWithIdle = window; + + const windowWithIdle: WindowWithRequestIdleCallback = window as any; + this.originalRequestIdleCallback = windowWithIdle.requestIdleCallback; windowWithIdle.requestIdleCallback = this.requestIdleCallback; + this.originalCancelIdleCallback = windowWithIdle.cancelIdleCallback; windowWithIdle.cancelIdleCallback = this.cancelIdleCallback; } @@ -42,11 +61,14 @@ export default class RequestIdleCallback { this.isUsingMockIdleCallback = true; this.isMockingUnsupported = true; - const windowWithIdle = window; + + const windowWithIdle: WindowWithRequestIdleCallback = window as any; + this.originalRequestIdleCallback = windowWithIdle.requestIdleCallback; - delete windowWithIdle.requestIdleCallback; + delete (windowWithIdle as any).requestIdleCallback; + this.originalCancelIdleCallback = windowWithIdle.cancelIdleCallback; - delete windowWithIdle.cancelIdleCallback; + delete (windowWithIdle as any).cancelIdleCallback; } restore() { @@ -61,6 +83,7 @@ export default class RequestIdleCallback { console.warn( 'You are restoring requestIdleCallback, but some idle callbacks have not been run. You can run requestIdleCallback.cancelIdleCallback() to clear them all and avoid this warning.' ); + this.cancelIdleCallbacks(); } @@ -68,15 +91,15 @@ export default class RequestIdleCallback { this.isMockingUnsupported = false; if (this.originalRequestIdleCallback) { - window.requestIdleCallback = this.originalRequestIdleCallback; + (window as any).requestIdleCallback = this.originalRequestIdleCallback; } else { - delete window.requestIdleCallback; + delete (window as any).requestIdleCallback; } if (this.originalCancelIdleCallback) { - window.cancelIdleCallback = this.originalCancelIdleCallback; + (window as any).cancelIdleCallback = this.originalCancelIdleCallback; } else { - delete window.cancelIdleCallback; + delete (window as any).cancelIdleCallback; } } @@ -86,16 +109,13 @@ export default class RequestIdleCallback { runIdleCallbacks(timeRemaining = Infinity, didTimeout = false) { this.ensureIdleCallbackIsMock(); + // We need to do it this way so that frames that queue other frames // don't get removed - - Object.keys(this.queued).forEach((frame) => { + Object.keys(this.queued).forEach((frame: any) => { const callback = this.queued[frame]; delete this.queued[frame]; - callback({ - timeRemaining: () => timeRemaining, - didTimeout, - }); + callback({ timeRemaining: () => timeRemaining, didTimeout }); }); } @@ -107,7 +127,21 @@ export default class RequestIdleCallback { }); } - ensureIdleCallbackIsMock() { + private requestIdleCallback = ( + callback: IdleCallback + ): ReturnType => { + this.currentIdleCallback += 1; + this.queued[this.currentIdleCallback] = callback; + return this.currentIdleCallback; + }; + + private cancelIdleCallback = ( + callback: ReturnType + ) => { + delete this.queued[callback]; + }; + + private ensureIdleCallbackIsMock() { if (!this.isUsingMockIdleCallback) { throw new Error( 'You must call requestIdleCallback.mock() before interacting with the mock request- or cancel- IdleCallback methods.' diff --git a/test/setupVitestEnv.js b/test/setupVitestEnv.ts similarity index 87% rename from test/setupVitestEnv.js rename to test/setupVitestEnv.ts index c1f0596..65cd24c 100644 --- a/test/setupVitestEnv.js +++ b/test/setupVitestEnv.ts @@ -1,4 +1,15 @@ -/* eslint-disable no-use-before-define */ +/* eslint-disable @typescript-eslint/no-use-before-define */ +import type { SpyInstance } from 'vitest'; + +declare global { + namespace Vi { + interface Assertion { + toHaveBeenWarned(): void; + toHaveBeenWarnedLast(): void; + toHaveBeenWarnedTimes(n: number): void; + } + } +} expect.extend({ toHaveBeenWarned(received) { @@ -63,7 +74,7 @@ expect.extend({ }, }); -let warn; +let warn: SpyInstance; const asserted = new Set(); beforeEach(() => { diff --git a/test/utils.js b/test/utils.ts similarity index 63% rename from test/utils.js rename to test/utils.ts index 4946474..404299f 100644 --- a/test/utils.js +++ b/test/utils.ts @@ -1,19 +1,22 @@ -import { createSSRApp } from 'vue'; +import { createSSRApp, defineComponent } from 'vue'; import { renderToString } from '@vue/server-renderer'; const originalWindow = window; -export function createApp(setupFn, isClient = false) { - const App = { - setup(props, ctx) { - return setupFn(isClient, props, ctx); +export function createApp( + setupFn: (isClient: boolean) => void, + isClient = false +) { + const App = defineComponent({ + setup() { + return setupFn(isClient); }, - }; + }); return createSSRApp(App); } -export async function withSSRSetup(setupFn) { +export async function withSSRSetup(setupFn: (isClient: boolean) => void) { // make sure window is undefined at server-side vi.stubGlobal('window', undefined); @@ -38,7 +41,11 @@ export async function withSSRSetup(setupFn) { return { app, container }; } -export const triggerEvent = (type, el) => { +export const triggerEvent = (type: string, el: Element | null) => { + if (el === null) { + return; + } + const event = new Event(type, { bubbles: true }); el.dispatchEvent(event); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ec35d0f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "@vue/tsconfig/tsconfig.json", + "compilerOptions": { + "target": "es2020", + "resolveJsonModule": true, + "baseUrl": "./", + "outDir": "dist", + "declaration": true, + "declarationDir": "./temp", + "noEmitOnError": true, + "importsNotUsedAsValues": "remove", + "preserveValueImports": false, + "sourceMap": false, + "strict": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "types": ["node", "vite/client", "vitest/globals"] + } +} diff --git a/tsconfig.types.json b/tsconfig.types.json new file mode 100644 index 0000000..27adede --- /dev/null +++ b/tsconfig.types.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"], + "exclude": ["./**/*.spec.ts"] +} diff --git a/vite.config.js b/vite.config.js deleted file mode 100644 index f972fef..0000000 --- a/vite.config.js +++ /dev/null @@ -1,83 +0,0 @@ -import path from 'node:path'; -import { defineConfig } from 'vite'; -import vue from '@vitejs/plugin-vue'; -import devSSR from './plugin-dev-server'; - -import { name as packageName } from './package.json'; - -const getPackageNameCamelCase = () => { - try { - return packageName.replace(/-./g, (char) => char[1].toUpperCase()); - } catch (err) { - throw new Error('Name property in package.json is missing.'); - } -}; - -let format; - -// https://vitejs.dev/config/ -export default defineConfig(({ command }) => ({ - plugins: [vue(), devSSR()], - publicDir: command === 'build' ? false : 'public', - define: { - __DEV__: `${ - command === 'build' - ? `process.env.NODE_ENV === 'development'` - : 'import.meta.env.DEV' - }`, - }, - build: { - lib: { - entry: path.resolve(__dirname, 'src/index.js'), - name: getPackageNameCamelCase(), - formats: ['cjs', 'es'], - fileName: (moduleFormat) => { - format = moduleFormat; - - if (moduleFormat === 'cjs') { - return `${getPackageNameCamelCase()}.cjs.js`; - } - - return `${format === 'es' ? 'esm' : 'cjs'}/[name].js`; - }, - }, - rollupOptions: { - external: ['vue'], - manualChunks: (id) => { - if (format === 'cjs') { - return null; - } - - if (id.includes('src/components')) { - return `components/${path.parse(id).name}`; - } - - if (id.includes('src/composables')) { - return `composables/${path.parse(id).name}`; - } - - if (id.includes('src/wrappers')) { - return `wrappers/${path.parse(id).name}`; - } - - if (id.includes('src/utils')) { - return `utils/${path.parse(id).name}`; - } - - return path.parse(id).name; - }, - output: { - chunkFileNames: () => { - return 'esm/[name].js'; - }, - }, - }, - minify: false, - sourcemap: false, - }, - test: { - globals: true, - environment: 'happy-dom', - setupFiles: ['./test/setupVitestEnv.js'], - }, -})); diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..01b1ea2 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,57 @@ +import path from 'node:path'; +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; + +import { name as packageName } from './package.json'; +import devSSR from './plugin-dev-server'; + +// https://vitejs.dev/config/ +export default defineConfig(({ command }) => ({ + plugins: [vue(), devSSR()], + publicDir: command === 'build' ? false : 'public', + define: { + __DEV__: `${ + command === 'build' + ? `process.env.NODE_ENV === 'development'` + : 'import.meta.env.DEV' + }`, + }, + build: { + lib: { + entry: path.resolve(__dirname, 'src/index.ts'), + name: packageName, + }, + rollupOptions: { + external: ['vue'], + treeshake: { + moduleSideEffects: 'no-external', + }, + output: [ + { + format: 'cjs', + entryFileNames: `${packageName}.cjs`, + dir: 'dist', + }, + { + format: 'es', + dir: 'dist/esm', + entryFileNames: ({ facadeModuleId }) => { + if (facadeModuleId?.endsWith('src/index.ts')) { + return `${packageName}.mjs`; + } + + return '[name].mjs'; + }, + preserveModules: true, + }, + ], + }, + minify: false, + sourcemap: false, + }, + test: { + globals: true, + environment: 'happy-dom', + setupFiles: ['./test/setupVitestEnv.ts'], + }, +}));