]> git.ipfire.org Git - thirdparty/vuejs/create-vue.git/commitdiff
feat!: migrate to the same codebase as v3
authorHaoqun Jiang <haoqunjiang@gmail.com>
Mon, 11 Jul 2022 09:11:24 +0000 (17:11 +0800)
committerHaoqun Jiang <haoqunjiang@gmail.com>
Mon, 11 Jul 2022 09:11:24 +0000 (17:11 +0800)
63 files changed:
index.ts [moved from index.js with 57% similarity]
package.json
pnpm-lock.yaml
pnpm-workspace.yaml
scripts/build.mjs
scripts/snapshot.mjs
scripts/test.mjs
snapshot.js [deleted file]
template/base/package.json
template/base/vite.config.js
template/code/default/src/components/__tests__/HelloWorld.spec.js [deleted file]
template/code/router/cypress/integration/example.spec.js [deleted file]
template/code/typescript-default/cypress/integration/example.spec.ts [deleted file]
template/code/typescript-default/src/components/__tests__/HelloWorld.spec.ts [deleted file]
template/code/typescript-router/cypress/integration/example.spec.ts [deleted file]
template/code/typescript-router/src/components/__tests__/HelloWorld.spec.ts [deleted file]
template/config/cypress-ct/cypress.config.js [new file with mode: 0644]
template/config/cypress-ct/cypress.config.ts [new file with mode: 0644]
template/config/cypress-ct/cypress/support/component-index.html [new file with mode: 0644]
template/config/cypress-ct/cypress/support/component.js [new file with mode: 0644]
template/config/cypress-ct/cypress/support/component.ts [new file with mode: 0644]
template/config/cypress-ct/package.json [new file with mode: 0644]
template/config/cypress-ct/src/components/__tests__/HelloWorld.cy.js [moved from template/code/router/src/components/__tests__/HelloWorld.spec.js with 55% similarity]
template/config/cypress/cypress.config.js [new file with mode: 0644]
template/config/cypress/cypress.config.ts [new file with mode: 0644]
template/config/cypress/cypress.json [deleted file]
template/config/cypress/cypress/e2e/example.cy.js [moved from template/code/default/cypress/integration/example.spec.js with 100% similarity]
template/config/cypress/cypress/e2e/jsconfig.json [moved from template/config/cypress/cypress/jsconfig.json with 70% similarity]
template/config/cypress/cypress/plugins/index.js [deleted file]
template/config/cypress/cypress/support/commands.ts [new file with mode: 0644]
template/config/cypress/cypress/support/e2e.js [moved from template/config/cypress/cypress/support/index.js with 100% similarity]
template/config/cypress/package.json
template/config/jsx/package.json [new file with mode: 0644]
template/config/jsx/vite.config.js [new file with mode: 0644]
template/config/pinia/package.json
template/config/router/package.json
template/config/typescript/package.json
template/config/typescript/tsconfig.json [deleted file]
template/config/vitest/package.json [new file with mode: 0644]
template/config/vitest/src/components/__tests__/HelloWorld.spec.js [new file with mode: 0644]
template/eslint/package.json [new file with mode: 0644]
template/tsconfig/base/package.json [new file with mode: 0644]
template/tsconfig/base/tsconfig.config.json [new file with mode: 0644]
template/tsconfig/base/tsconfig.json [new file with mode: 0644]
template/tsconfig/cypress-ct/tsconfig.app.json [new file with mode: 0644]
template/tsconfig/cypress-ct/tsconfig.cypress-ct.json [new file with mode: 0644]
template/tsconfig/cypress-ct/tsconfig.json [new file with mode: 0644]
template/tsconfig/cypress/cypress/e2e/tsconfig.json [new file with mode: 0644]
template/tsconfig/vitest/package.json [new file with mode: 0644]
template/tsconfig/vitest/tsconfig.app.json [new file with mode: 0644]
template/tsconfig/vitest/tsconfig.json [new file with mode: 0644]
template/tsconfig/vitest/tsconfig.vitest.json [new file with mode: 0644]
test.js [deleted file]
tsconfig.json [new file with mode: 0644]
utils/banner.ts [new file with mode: 0644]
utils/deepMerge.ts [moved from utils/deepMerge.js with 100% similarity]
utils/directoryTraverse.ts [moved from utils/directoryTraverse.js with 94% similarity]
utils/generateReadme.js [deleted file]
utils/generateReadme.ts [new file with mode: 0644]
utils/getCommand.ts [moved from utils/getCommand.js with 100% similarity]
utils/renderEslint.ts [new file with mode: 0644]
utils/renderTemplate.ts [moved from utils/renderTemplate.js with 77% similarity]
utils/sortDependencies.ts [moved from utils/sortDependencies.js with 100% similarity]

similarity index 57%
rename from index.js
rename to index.ts
index 1f4c43fe20f310b51c43a2aa3b6c7aecd59497a9..a88828562b472d445b5fdcb91ba69d9e294a4c3d 100755 (executable)
--- a/index.js
+++ b/index.ts
@@ -1,17 +1,18 @@
 #!/usr/bin/env node
-// @ts-check
 
-import fs from 'fs'
-import path from 'path'
+import * as fs from 'fs'
+import * as path from 'path'
 
 import minimist from 'minimist'
 import prompts from 'prompts'
 import { red, green, bold } from 'kolorist'
 
-import renderTemplate from './utils/renderTemplate.js'
-import { postOrderDirectoryTraverse, preOrderDirectoryTraverse } from './utils/directoryTraverse.js'
-import generateReadme from './utils/generateReadme.js'
-import getCommand from './utils/getCommand.js'
+import renderTemplate from './utils/renderTemplate'
+import { postOrderDirectoryTraverse, preOrderDirectoryTraverse } from './utils/directoryTraverse'
+import generateReadme from './utils/generateReadme'
+import getCommand from './utils/getCommand'
+import renderEslint from './utils/renderEslint'
+import banner from './utils/banner'
 
 function isValidPackageName(projectName) {
   return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(projectName)
@@ -31,6 +32,10 @@ function canSafelyOverwrite(dir) {
 }
 
 function emptyDir(dir) {
+  if (!fs.existsSync(dir)) {
+    return
+  }
+
   postOrderDirectoryTraverse(
     dir,
     (dir) => fs.rmdirSync(dir),
@@ -39,18 +44,25 @@ function emptyDir(dir) {
 }
 
 async function init() {
+  console.log(`\n${banner}\n`)
+
   const cwd = process.cwd()
   // possible options:
   // --default
   // --typescript / --ts
+  // --jsx
   // --router / --vue-router
   // --pinia
-  // --with-tests / --tests / --cypress
+  // --with-tests / --tests (equals to `--vitest --cypress`)
+  // --vitest
+  // --cypress
+  // --eslint
+  // --eslint-with-prettier (only support prettier through eslint for simplicity)
   // --force (for force overwriting)
   const argv = minimist(process.argv.slice(2), {
     alias: {
       typescript: ['ts'],
-      'with-tests': ['tests', 'cypress'],
+      'with-tests': ['tests'],
       router: ['vue-router']
     },
     // all arguments are treated as booleans
@@ -58,16 +70,37 @@ async function init() {
   })
 
   // if any of the feature flags is set, we would skip the feature prompts
-  // use `??` instead of `||` once we drop Node.js 12 support
   const isFeatureFlagsUsed =
-    typeof (argv.default || argv.ts || argv.router || argv.pinia || argv.tests) === 'boolean'
+    typeof (
+      argv.default ??
+      argv.ts ??
+      argv.jsx ??
+      argv.router ??
+      argv.pinia ??
+      argv.tests ??
+      argv.vitest ??
+      argv.cypress ??
+      argv.eslint
+    ) === 'boolean'
 
   let targetDir = argv._[0]
   const defaultProjectName = !targetDir ? 'vue-project' : targetDir
 
   const forceOverwrite = argv.force
 
-  let result = {}
+  let result: {
+    projectName?: string
+    shouldOverwrite?: boolean
+    packageName?: string
+    needsTypeScript?: boolean
+    needsJsx?: boolean
+    needsRouter?: boolean
+    needsPinia?: boolean
+    needsVitest?: boolean
+    needsCypress?: boolean
+    needsEslint?: boolean
+    needsPrettier?: boolean
+  } = {}
 
   try {
     // Prompts:
@@ -75,9 +108,12 @@ async function init() {
     //   - whether to overwrite the existing directory or not?
     //   - enter a valid package name for package.json
     // - Project language: JavaScript / TypeScript
+    // - Add JSX Support?
     // - Install Vue Router for SPA development?
     // - Install Pinia for state management?
     // - Add Cypress for testing?
+    // - Add ESLint for code quality?
+    // - Add Prettier for code formatting?
     result = await prompts(
       [
         {
@@ -99,7 +135,7 @@ async function init() {
         },
         {
           name: 'overwriteChecker',
-          type: (prev, values = {}) => {
+          type: (prev, values) => {
             if (values.shouldOverwrite === false) {
               throw new Error(red('✖') + ' Operation cancelled')
             }
@@ -121,6 +157,14 @@ async function init() {
           active: 'Yes',
           inactive: 'No'
         },
+        {
+          name: 'needsJsx',
+          type: () => (isFeatureFlagsUsed ? null : 'toggle'),
+          message: 'Add JSX Support?',
+          initial: false,
+          active: 'Yes',
+          inactive: 'No'
+        },
         {
           name: 'needsRouter',
           type: () => (isFeatureFlagsUsed ? null : 'toggle'),
@@ -138,9 +182,41 @@ async function init() {
           inactive: 'No'
         },
         {
-          name: 'needsTests',
+          name: 'needsVitest',
+          type: () => (isFeatureFlagsUsed ? null : 'toggle'),
+          message: 'Add Vitest for Unit Testing?',
+          initial: false,
+          active: 'Yes',
+          inactive: 'No'
+        },
+        {
+          name: 'needsCypress',
           type: () => (isFeatureFlagsUsed ? null : 'toggle'),
-          message: 'Add Cypress for testing?',
+          message: (prev, answers) =>
+            answers.needsVitest
+              ? 'Add Cypress for End-to-End testing?'
+              : 'Add Cypress for both Unit and End-to-End testing?',
+          initial: false,
+          active: 'Yes',
+          inactive: 'No'
+        },
+        {
+          name: 'needsEslint',
+          type: () => (isFeatureFlagsUsed ? null : 'toggle'),
+          message: 'Add ESLint for code quality?',
+          initial: false,
+          active: 'Yes',
+          inactive: 'No'
+        },
+        {
+          name: 'needsPrettier',
+          type: (prev, values) => {
+            if (isFeatureFlagsUsed || !values.needsEslint) {
+              return null
+            }
+            return 'toggle'
+          },
+          message: 'Add Prettier for code formatting?',
           initial: false,
           active: 'Yes',
           inactive: 'No'
@@ -160,16 +236,22 @@ async function init() {
   // `initial` won't take effect if the prompt type is null
   // so we still have to assign the default values here
   const {
-    packageName = toValidPackageName(defaultProjectName),
-    shouldOverwrite,
+    projectName,
+    packageName = projectName ?? defaultProjectName,
+    shouldOverwrite = argv.force,
+    needsJsx = argv.jsx,
     needsTypeScript = argv.typescript,
     needsRouter = argv.router,
     needsPinia = argv.pinia,
-    needsTests = argv.tests
+    needsCypress = argv.cypress || argv.tests,
+    needsVitest = argv.vitest || argv.tests,
+    needsEslint = argv.eslint || argv['eslint-with-prettier'],
+    needsPrettier = argv['eslint-with-prettier']
   } = result
+  const needsCypressCT = needsCypress && !needsVitest
   const root = path.join(cwd, targetDir)
 
-  if (shouldOverwrite) {
+  if (fs.existsSync(root) && shouldOverwrite) {
     emptyDir(root)
   } else if (!fs.existsSync(root)) {
     fs.mkdirSync(root)
@@ -194,17 +276,43 @@ async function init() {
   render('base')
 
   // Add configs.
+  if (needsJsx) {
+    render('config/jsx')
+  }
   if (needsRouter) {
     render('config/router')
   }
   if (needsPinia) {
     render('config/pinia')
   }
-  if (needsTests) {
+  if (needsVitest) {
+    render('config/vitest')
+  }
+  if (needsCypress) {
     render('config/cypress')
   }
+  if (needsCypressCT) {
+    render('config/cypress-ct')
+  }
   if (needsTypeScript) {
     render('config/typescript')
+
+    // Render tsconfigs
+    render('tsconfig/base')
+    if (needsCypress) {
+      render('tsconfig/cypress')
+    }
+    if (needsCypressCT) {
+      render('tsconfig/cypress-ct')
+    }
+    if (needsVitest) {
+      render('tsconfig/vitest')
+    }
+  }
+
+  // Render ESLint config
+  if (needsEslint) {
+    renderEslint(root, { needsTypeScript, needsCypress, needsCypressCT, needsPrettier })
   }
 
   // Render code template.
@@ -227,17 +335,32 @@ async function init() {
 
   // Cleanup.
 
+  // We try to share as many files between TypeScript and JavaScript as possible.
+  // If that's not possible, we put `.ts` version alongside the `.js` one in the templates.
+  // So after all the templates are rendered, we need to clean up the redundant files.
+  // (Currently it's only `cypress/plugin/index.ts`, but we might add more in the future.)
+  // (Or, we might completely get rid of the plugins folder as Cypress 10 supports `cypress.config.ts`)
+
   if (needsTypeScript) {
-    // rename all `.js` files to `.ts`
-    // rename jsconfig.json to tsconfig.json
+    // Convert the JavaScript template to the TypeScript
+    // Check all the remaining `.js` files:
+    //   - If the corresponding TypeScript version already exists, remove the `.js` version.
+    //   - Otherwise, rename the `.js` file to `.ts`
+    // Remove `jsconfig.json`, because we already have tsconfig.json
+    // `jsconfig.json` is not reused, because we use solution-style `tsconfig`s, which are much more complicated.
     preOrderDirectoryTraverse(
       root,
       () => {},
       (filepath) => {
         if (filepath.endsWith('.js')) {
-          fs.renameSync(filepath, filepath.replace(/\.js$/, '.ts'))
+          const tsFilePath = filepath.replace(/\.js$/, '.ts')
+          if (fs.existsSync(tsFilePath)) {
+            fs.unlinkSync(filepath)
+          } else {
+            fs.renameSync(filepath, tsFilePath)
+          }
         } else if (path.basename(filepath) === 'jsconfig.json') {
-          fs.renameSync(filepath, filepath.replace(/jsconfig\.json$/, 'tsconfig.json'))
+          fs.unlinkSync(filepath)
         }
       }
     )
@@ -246,23 +369,16 @@ async function init() {
     const indexHtmlPath = path.resolve(root, 'index.html')
     const indexHtmlContent = fs.readFileSync(indexHtmlPath, 'utf8')
     fs.writeFileSync(indexHtmlPath, indexHtmlContent.replace('src/main.js', 'src/main.ts'))
-  }
-
-  if (!needsTests) {
-    // All templates assumes the need of tests.
-    // If the user doesn't need it:
-    // rm -rf cypress **/__tests__/
+  } else {
+    // Remove all the remaining `.ts` files
     preOrderDirectoryTraverse(
       root,
-      (dirpath) => {
-        const dirname = path.basename(dirpath)
-
-        if (dirname === 'cypress' || dirname === '__tests__') {
-          emptyDir(dirpath)
-          fs.rmdirSync(dirpath)
+      () => {},
+      (filepath) => {
+        if (filepath.endsWith('.ts')) {
+          fs.unlinkSync(filepath)
         }
-      },
-      () => {}
+      }
     )
   }
 
@@ -270,20 +386,20 @@ async function init() {
   // Supported package managers: pnpm > yarn > npm
   // Note: until <https://github.com/pnpm/pnpm/issues/3505> is resolved,
   // it is not possible to tell if the command is called by `pnpm init`.
-  const packageManager = /pnpm/.test(process.env.npm_execpath)
-    ? 'pnpm'
-    : /yarn/.test(process.env.npm_execpath)
-    ? 'yarn'
-    : 'npm'
+  const userAgent = process.env.npm_config_user_agent ?? ''
+  const packageManager = /pnpm/.test(userAgent) ? 'pnpm' : /yarn/.test(userAgent) ? 'yarn' : 'npm'
 
   // README generation
   fs.writeFileSync(
     path.resolve(root, 'README.md'),
     generateReadme({
-      projectName: result.projectName || defaultProjectName,
+      projectName: result.projectName ?? defaultProjectName,
       packageManager,
       needsTypeScript,
-      needsTests
+      needsVitest,
+      needsCypress,
+      needsCypressCT,
+      needsEslint
     })
   )
 
@@ -292,6 +408,9 @@ async function init() {
     console.log(`  ${bold(green(`cd ${path.relative(cwd, root)}`))}`)
   }
   console.log(`  ${bold(green(getCommand(packageManager, 'install')))}`)
+  if (needsPrettier) {
+    console.log(`  ${bold(green(getCommand(packageManager, 'lint')))}`)
+  }
   console.log(`  ${bold(green(getCommand(packageManager, 'dev')))}`)
   console.log()
 }
index 56e4abae46660553cd3e55fb547bd5f4a948e946..eb7c3462c85e2f69468e18616644fd833d0e5a3b 100644 (file)
   },
   "homepage": "https://github.com/vuejs/create-vue#readme",
   "devDependencies": {
+    "@types/eslint": "^8.4.5",
+    "@types/prompts": "^2.0.14",
+    "@vue/tsconfig": "^0.1.3",
     "esbuild": "^0.14.49",
     "esbuild-plugin-license": "^1.2.2",
     "husky": "^8.0.1",
     "kolorist": "^1.5.1",
-    "lint-staged": "^12.5.0",
+    "lint-staged": "^13.0.3",
     "minimist": "^1.2.6",
     "npm-run-all": "^4.1.5",
     "prettier": "^2.7.1",
index 1c083c73dd6a5889cccf61c5178a56c8010c4616..b27d8e4eee1b231168551ba805f2373c4d2c3d3e 100644 (file)
@@ -4,29 +4,65 @@ importers:
 
   .:
     specifiers:
+      '@types/eslint': ^8.4.5
+      '@types/prompts': ^2.0.14
+      '@vue/tsconfig': ^0.1.3
       esbuild: ^0.14.49
       esbuild-plugin-license: ^1.2.2
       husky: ^8.0.1
       kolorist: ^1.5.1
-      lint-staged: ^12.5.0
+      lint-staged: ^13.0.3
       minimist: ^1.2.6
       npm-run-all: ^4.1.5
       prettier: ^2.7.1
       prompts: ^2.4.2
       zx: ^4.3.0
     devDependencies:
+      '@types/eslint': 8.4.5
+      '@types/prompts': 2.0.14
+      '@vue/tsconfig': 0.1.3
       esbuild: 0.14.49
       esbuild-plugin-license: 1.2.2_esbuild@0.14.49
       husky: 8.0.1
       kolorist: 1.5.1
-      lint-staged: 12.5.0
+      lint-staged: 13.0.3
       minimist: 1.2.6
       npm-run-all: 4.1.5
       prettier: 2.7.1
       prompts: 2.4.2
       zx: 4.3.0
 
+  playground/cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      cypress: ^10.3.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
   playground/default:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      vite: 2.9.14
+
+  playground/jsx:
     specifiers:
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
@@ -41,7 +77,26 @@ importers:
       '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
       vite: 2.9.14
 
-  playground/pinia:
+  playground/jsx-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      cypress: ^10.3.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
+  playground/jsx-pinia:
     specifiers:
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
@@ -58,34 +113,111 @@ importers:
       '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
       vite: 2.9.14
 
-  playground/pinia-with-tests:
+  playground/jsx-pinia-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      cypress: ^10.3.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
+  playground/jsx-pinia-vitest:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-pinia-vitest-cypress:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
       '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
       pinia: ^2.0.14
       start-server-and-test: ^1.14.0
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
       vue-template-compiler: ^2.7.4
     dependencies:
       pinia: 2.0.14_vue@2.7.4
       vue: 2.7.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
       '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
       start-server-and-test: 1.14.0
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
 
-  playground/router:
+  playground/jsx-pinia-with-tests:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-router:
     specifiers:
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
@@ -102,7 +234,28 @@ importers:
       '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
       vite: 2.9.14
 
-  playground/router-pinia:
+  playground/jsx-router-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      cypress: ^10.3.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
+  playground/jsx-router-pinia:
     specifiers:
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
@@ -121,17 +274,68 @@ importers:
       '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
       vite: 2.9.14
 
-  playground/router-pinia-with-tests:
+  playground/jsx-router-pinia-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      cypress: ^10.3.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
+  playground/jsx-router-pinia-vitest:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-router-pinia-vitest-cypress:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
       '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
       pinia: ^2.0.14
       start-server-and-test: ^1.14.0
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
       vue-router: ^3.5.4
       vue-template-compiler: ^2.7.4
@@ -140,292 +344,2092 @@ importers:
       vue: 2.7.4
       vue-router: 3.5.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
       '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
       start-server-and-test: 1.14.0
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
 
-  playground/router-with-tests:
+  playground/jsx-router-pinia-with-tests:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-router-vitest:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-router-vitest-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-router-with-tests:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-vitest:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-vitest-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/jsx-with-tests:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/pinia:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      pinia: ^2.0.14
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      vite: 2.9.14
+
+  playground/pinia-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      cypress: ^10.3.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
+  playground/pinia-vitest:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/pinia-vitest-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/pinia-with-tests:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/router:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      vite: 2.9.14
+
+  playground/router-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      cypress: ^10.3.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
+  playground/router-pinia:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      pinia: ^2.0.14
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      vite: 2.9.14
+
+  playground/router-pinia-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      cypress: ^10.3.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      cypress: 10.3.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+
+  playground/router-pinia-vitest:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/router-pinia-vitest-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/router-pinia-with-tests:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/router-vitest:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/router-vitest-cypress:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/router-with-tests:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      start-server-and-test: ^1.14.0
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  playground/typescript:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-pinia:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-pinia-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-pinia-vitest:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-pinia-vitest-cypress:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-pinia-with-tests:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-pinia:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-pinia-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-pinia-vitest:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-pinia-vitest-cypress:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-pinia-with-tests:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-vitest:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-vitest-cypress:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-router-with-tests:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-vitest:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-vitest-cypress:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-jsx-with-tests:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-pinia:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-pinia-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-pinia-vitest:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-pinia-vitest-cypress:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-pinia-with-tests:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-router:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-router-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-router-pinia:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-router-pinia-cypress:
+    specifiers:
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-router-pinia-vitest:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-router-pinia-vitest-cypress:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
+      start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
+      vite: ^2.9.14
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
+    dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
+      vue: 2.7.4
+      vue-router: 3.5.4
+    devDependencies:
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
+      typescript: 4.7.4
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  playground/typescript-router-pinia-with-tests:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+      '@types/node': ^16.11.43
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      pinia: ^2.0.14
       start-server-and-test: ^1.14.0
+      typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
       vue-router: ^3.5.4
       vue-template-compiler: ^2.7.4
+      vue-tsc: ^0.38.4
     dependencies:
+      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
       vue: 2.7.4
       vue-router: 3.5.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
+      '@types/jsdom': 16.2.14
+      '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
       start-server-and-test: 1.14.0
+      typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript:
+  playground/typescript-router-vitest:
     specifiers:
+      '@types/jsdom': ^16.2.14
       '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
       typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
       vue-tsc: ^0.38.4
     dependencies:
       vue: 2.7.4
+      vue-router: 3.5.4
     devDependencies:
+      '@types/jsdom': 16.2.14
       '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
       typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
       vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript-pinia:
+  playground/typescript-router-vitest-cypress:
     specifiers:
+      '@types/jsdom': ^16.2.14
       '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      pinia: ^2.0.14
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
       typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
+      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
       vue-tsc: ^0.38.4
     dependencies:
-      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
       vue: 2.7.4
+      vue-router: 3.5.4
     devDependencies:
+      '@types/jsdom': 16.2.14
       '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
       typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
       vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript-pinia-with-tests:
+  playground/typescript-router-with-tests:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
+      '@types/jsdom': ^16.2.14
       '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
-      pinia: ^2.0.14
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
       start-server-and-test: ^1.14.0
       typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
+      vue-router: ^3.5.4
       vue-template-compiler: ^2.7.4
       vue-tsc: ^0.38.4
     dependencies:
-      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
       vue: 2.7.4
+      vue-router: 3.5.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
+      '@types/jsdom': 16.2.14
       '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
       start-server-and-test: 1.14.0
       typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
       vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript-router:
+  playground/typescript-vitest:
     specifiers:
+      '@types/jsdom': ^16.2.14
       '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
       typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
-      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
       vue-tsc: ^0.38.4
     dependencies:
       vue: 2.7.4
-      vue-router: 3.5.4
     devDependencies:
+      '@types/jsdom': 16.2.14
       '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
       typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
       vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript-router-pinia:
+  playground/typescript-vitest-cypress:
     specifiers:
+      '@types/jsdom': ^16.2.14
       '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      pinia: ^2.0.14
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
+      start-server-and-test: ^1.14.0
       typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
-      vue-router: ^3.5.4
+      vue-template-compiler: ^2.7.4
       vue-tsc: ^0.38.4
     dependencies:
-      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
       vue: 2.7.4
-      vue-router: 3.5.4
     devDependencies:
+      '@types/jsdom': 16.2.14
       '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
+      start-server-and-test: 1.14.0
       typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
       vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript-router-pinia-with-tests:
+  playground/typescript-with-tests:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
+      '@types/jsdom': ^16.2.14
       '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
-      pinia: ^2.0.14
+      '@vue/test-utils': ^1.3.0
+      '@vue/tsconfig': ^0.1.3
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
+      npm-run-all: ^4.1.5
       start-server-and-test: ^1.14.0
       typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
-      vue-router: ^3.5.4
       vue-template-compiler: ^2.7.4
       vue-tsc: ^0.38.4
     dependencies:
-      pinia: 2.0.14_typescript@4.7.4+vue@2.7.4
       vue: 2.7.4
-      vue-router: 3.5.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
+      '@types/jsdom': 16.2.14
       '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      '@vue/tsconfig': 0.1.3_@types+node@16.11.43
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      npm-run-all: 4.1.5
       start-server-and-test: 1.14.0
       typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
       vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript-router-with-tests:
+  playground/vitest:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
-      '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
-      start-server-and-test: ^1.14.0
-      typescript: ~4.7.4
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
-      vue-router: ^3.5.4
       vue-template-compiler: ^2.7.4
-      vue-tsc: ^0.38.4
     dependencies:
       vue: 2.7.4
-      vue-router: 3.5.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
-      '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
-      start-server-and-test: 1.14.0
-      typescript: 4.7.4
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
-      vue-tsc: 0.38.4_typescript@4.7.4
 
-  playground/typescript-with-tests:
+  playground/vitest-cypress:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
-      '@types/node': ^16.11.43
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
       start-server-and-test: ^1.14.0
-      typescript: ~4.7.4
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
       vue-template-compiler: ^2.7.4
-      vue-tsc: ^0.38.4
     dependencies:
       vue: 2.7.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
-      '@types/node': 16.11.43
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
       start-server-and-test: 1.14.0
-      typescript: 4.7.4
       vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
-      vue-tsc: 0.38.4_typescript@4.7.4
 
   playground/with-tests:
     specifiers:
-      '@cypress/vite-dev-server': ^2.2.3
-      '@cypress/vue': ^2.2.4
       '@vitejs/plugin-legacy': ^1.8.2
       '@vitejs/plugin-vue2': ^1.1.2
-      '@vitejs/plugin-vue2-jsx': ^1.0.1
-      cypress: ^9.7.0
+      '@vue/test-utils': ^1.3.0
+      cypress: ^10.3.0
+      jsdom: ^20.0.0
       start-server-and-test: ^1.14.0
       vite: ^2.9.14
+      vitest: ^0.15.2
       vue: ^2.7.4
       vue-template-compiler: ^2.7.4
     dependencies:
       vue: 2.7.4
     devDependencies:
-      '@cypress/vite-dev-server': 2.2.3_vite@2.9.14
-      '@cypress/vue': 2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4
       '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
       '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
-      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
-      cypress: 9.7.0
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      cypress: 10.3.0
+      jsdom: 20.0.0
+      start-server-and-test: 1.14.0
+      vite: 2.9.14
+      vitest: 0.15.2_jsdom@20.0.0
+      vue-template-compiler: 2.7.4
+
+  template/base:
+    specifiers:
+      '@vitejs/plugin-legacy': ^1.8.2
+      '@vitejs/plugin-vue2': ^1.1.2
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-legacy': 1.8.2_vite@2.9.14
+      '@vitejs/plugin-vue2': 1.1.2_vite@2.9.14+vue@2.7.4
+      vite: 2.9.14
+
+  template/config/cypress:
+    specifiers:
+      cypress: ^10.3.0
+      start-server-and-test: ^1.14.0
+    devDependencies:
+      cypress: 10.3.0
       start-server-and-test: 1.14.0
+
+  template/config/cypress-ct:
+    specifiers:
+      cypress: ^10.3.0
+      vue: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      cypress: 10.3.0
+
+  template/config/jsx:
+    specifiers:
+      '@vitejs/plugin-vue2-jsx': ^1.0.1
+      vite: ^2.9.14
+      vue: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vitejs/plugin-vue2-jsx': 1.0.1_vite@2.9.14+vue@2.7.4
       vite: 2.9.14
+
+  template/config/pinia:
+    specifiers:
+      pinia: ^2.0.14
+      vue: ^2.7.4
+    dependencies:
+      pinia: 2.0.14_vue@2.7.4
+      vue: 2.7.4
+
+  template/config/router:
+    specifiers:
+      vue-router: ^3.5.4
+    dependencies:
+      vue-router: 3.5.4
+
+  template/config/typescript:
+    specifiers:
+      '@types/node': ^16.11.43
+      npm-run-all: ^4.1.5
+      typescript: ~4.7.4
+      vue-tsc: ^0.38.4
+    devDependencies:
+      '@types/node': 16.11.43
+      npm-run-all: 4.1.5
+      typescript: 4.7.4
+      vue-tsc: 0.38.4_typescript@4.7.4
+
+  template/config/vitest:
+    specifiers:
+      '@vue/test-utils': ^1.3.0
+      jsdom: ^20.0.0
+      vitest: ^0.15.2
+      vue: ^2.7.4
+      vue-template-compiler: ^2.7.4
+    dependencies:
+      vue: 2.7.4
+    devDependencies:
+      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
+      jsdom: 20.0.0
+      vitest: 0.15.2_jsdom@20.0.0
       vue-template-compiler: 2.7.4
 
+  template/tsconfig/base:
+    specifiers:
+      '@vue/tsconfig': ^0.1.3
+    devDependencies:
+      '@vue/tsconfig': 0.1.3
+
+  template/tsconfig/vitest:
+    specifiers:
+      '@types/jsdom': ^16.2.14
+    devDependencies:
+      '@types/jsdom': 16.2.14
+
 packages:
 
   /@ampproject/remapping/2.2.0:
@@ -732,10 +2736,6 @@ packages:
     dev: true
     optional: true
 
-  /@cypress/mount-utils/1.0.2:
-    resolution: {integrity: sha512-Fn3fdTiyayHoy8Ol0RSu4MlBH2maQ2ZEXeEVKl/zHHXEQpld5HX3vdNLhK5YLij8cLynA4DxOT/nO9iEnIiOXw==}
-    dev: true
-
   /@cypress/request/2.88.10:
     resolution: {integrity: sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==}
     engines: {node: '>= 6'}
@@ -760,37 +2760,6 @@ packages:
       uuid: 8.3.2
     dev: true
 
-  /@cypress/vite-dev-server/2.2.3_vite@2.9.14:
-    resolution: {integrity: sha512-E9cPKwReweYGRsupfR6Va1R1bHv3zPb3gHG68fyQwAjG4oPORaQlgfFWiR2i1pF+tRftvNfM0O2PBuKX3IvPxg==}
-    peerDependencies:
-      vite: '>= 2.1.3'
-    dependencies:
-      debug: 4.3.4
-      get-port: 5.1.1
-      vite: 2.9.14
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@cypress/vue/2.2.4_3rn4t6l7e2lwxrytzpvxzfmli4:
-    resolution: {integrity: sha512-ve6aPUj1UHZRpfU9U/NKfsVgzCYVR2CeTdN/knhdWs8sbW5ERgbD1EkEdJ9+VCdqXcIoqRWdMQovnJUmJW6FLA==}
-    engines: {node: '>=8'}
-    peerDependencies:
-      '@cypress/webpack-dev-server': '*'
-      cypress: '>=4.5.0'
-      vue: ^2.0.0
-    peerDependenciesMeta:
-      '@cypress/webpack-dev-server':
-        optional: true
-    dependencies:
-      '@cypress/mount-utils': 1.0.2
-      '@vue/test-utils': 1.3.0_iw6utnfwh3sgibvdy6b3ezqjai
-      cypress: 9.7.0
-      vue: 2.7.4
-    transitivePeerDependencies:
-      - vue-template-compiler
-    dev: true
-
   /@cypress/xvfb/1.2.4_supports-color@8.1.1:
     resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==}
     dependencies:
@@ -891,12 +2860,50 @@ packages:
     resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
     dev: true
 
+  /@tootallnate/once/2.0.0:
+    resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
+    engines: {node: '>= 10'}
+    dev: true
+
+  /@types/chai-subset/1.3.3:
+    resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
+    dependencies:
+      '@types/chai': 4.3.1
+    dev: true
+
+  /@types/chai/4.3.1:
+    resolution: {integrity: sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==}
+    dev: true
+
+  /@types/eslint/8.4.5:
+    resolution: {integrity: sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==}
+    dependencies:
+      '@types/estree': 0.0.52
+      '@types/json-schema': 7.0.11
+    dev: true
+
+  /@types/estree/0.0.52:
+    resolution: {integrity: sha512-BZWrtCU0bMVAIliIV+HJO1f1PR41M7NKjfxrFJwwhKI1KwhwOxYw1SXg9ao+CIMt774nFuGiG6eU+udtbEI9oQ==}
+    dev: true
+
   /@types/fs-extra/9.0.13:
     resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
     dependencies:
       '@types/node': 16.11.43
     dev: true
 
+  /@types/jsdom/16.2.14:
+    resolution: {integrity: sha512-6BAy1xXEmMuHeAJ4Fv4yXKwBDTGTOseExKE3OaHiNycdHdZw59KfYzrt0DkDluvwmik1HRt6QS7bImxUmpSy+w==}
+    dependencies:
+      '@types/node': 16.11.43
+      '@types/parse5': 6.0.3
+      '@types/tough-cookie': 4.0.2
+    dev: true
+
+  /@types/json-schema/7.0.11:
+    resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
+    dev: true
+
   /@types/minimist/1.2.2:
     resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
     dev: true
@@ -916,6 +2923,20 @@ packages:
     resolution: {integrity: sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ==}
     dev: true
 
+  /@types/node/18.0.3:
+    resolution: {integrity: sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==}
+    dev: true
+
+  /@types/parse5/6.0.3:
+    resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==}
+    dev: true
+
+  /@types/prompts/2.0.14:
+    resolution: {integrity: sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==}
+    dependencies:
+      '@types/node': 18.0.3
+    dev: true
+
   /@types/sinonjs__fake-timers/8.1.1:
     resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
     dev: true
@@ -924,6 +2945,10 @@ packages:
     resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==}
     dev: true
 
+  /@types/tough-cookie/4.0.2:
+    resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==}
+    dev: true
+
   /@types/yauzl/2.10.0:
     resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
     requiresBuild: true
@@ -1187,8 +3212,65 @@ packages:
       vue-template-compiler: 2.7.4
     dev: true
 
-  /abbrev/1.1.1:
-    resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
+  /@vue/tsconfig/0.1.3:
+    resolution: {integrity: sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==}
+    peerDependencies:
+      '@types/node': '*'
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+    dev: true
+
+  /@vue/tsconfig/0.1.3_@types+node@16.11.43:
+    resolution: {integrity: sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==}
+    peerDependencies:
+      '@types/node': '*'
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+    dependencies:
+      '@types/node': 16.11.43
+    dev: true
+
+  /abab/2.0.6:
+    resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
+    dev: true
+
+  /abbrev/1.1.1:
+    resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
+    dev: true
+
+  /acorn-globals/6.0.0:
+    resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==}
+    dependencies:
+      acorn: 7.4.1
+      acorn-walk: 7.2.0
+    dev: true
+
+  /acorn-walk/7.2.0:
+    resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
+    engines: {node: '>=0.4.0'}
+    dev: true
+
+  /acorn/7.4.1:
+    resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+    dev: true
+
+  /acorn/8.7.1:
+    resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+    dev: true
+
+  /agent-base/6.0.2:
+    resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
+    engines: {node: '>= 6.0.0'}
+    dependencies:
+      debug: 4.3.4
+    transitivePeerDependencies:
+      - supports-color
     dev: true
 
   /aggregate-error/3.1.0:
@@ -1260,6 +3342,10 @@ packages:
     engines: {node: '>=0.8'}
     dev: true
 
+  /assertion-error/1.1.0:
+    resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
+    dev: true
+
   /astral-regex/2.0.0:
     resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
     engines: {node: '>=8'}
@@ -1330,6 +3416,10 @@ packages:
       fill-range: 7.0.1
     dev: true
 
+  /browser-process-hrtime/1.0.0:
+    resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}
+    dev: true
+
   /browserslist/4.21.1:
     resolution: {integrity: sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==}
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -1377,6 +3467,19 @@ packages:
     resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
     dev: true
 
+  /chai/4.3.6:
+    resolution: {integrity: sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==}
+    engines: {node: '>=4'}
+    dependencies:
+      assertion-error: 1.1.0
+      check-error: 1.0.2
+      deep-eql: 3.0.1
+      get-func-name: 2.0.0
+      loupe: 2.3.4
+      pathval: 1.1.1
+      type-detect: 4.0.8
+    dev: true
+
   /chalk/2.4.2:
     resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
     engines: {node: '>=4'}
@@ -1394,6 +3497,10 @@ packages:
       supports-color: 7.2.0
     dev: true
 
+  /check-error/1.0.2:
+    resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
+    dev: true
+
   /check-more-types/2.24.0:
     resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==}
     engines: {node: '>= 0.8.0'}
@@ -1546,11 +3653,26 @@ packages:
       which: 2.0.2
     dev: true
 
+  /cssom/0.3.8:
+    resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
+    dev: true
+
+  /cssom/0.5.0:
+    resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
+    dev: true
+
+  /cssstyle/2.3.0:
+    resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==}
+    engines: {node: '>=8'}
+    dependencies:
+      cssom: 0.3.8
+    dev: true
+
   /csstype/3.1.0:
     resolution: {integrity: sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==}
 
-  /cypress/9.7.0:
-    resolution: {integrity: sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==}
+  /cypress/10.3.0:
+    resolution: {integrity: sha512-txkQWKzvBVnWdCuKs5Xc08gjpO89W2Dom2wpZgT9zWZT5jXxqPIxqP/NC1YArtkpmp3fN5HW8aDjYBizHLUFvg==}
     engines: {node: '>=12.0.0'}
     hasBin: true
     requiresBuild: true
@@ -1606,6 +3728,15 @@ packages:
       assert-plus: 1.0.0
     dev: true
 
+  /data-urls/3.0.2:
+    resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      abab: 2.0.6
+      whatwg-mimetype: 3.0.0
+      whatwg-url: 11.0.0
+    dev: true
+
   /dayjs/1.11.3:
     resolution: {integrity: sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==}
     dev: true
@@ -1663,17 +3794,19 @@ packages:
       supports-color: 8.1.1
     dev: true
 
-  /debug/4.3.4_supports-color@9.2.2:
-    resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
-    engines: {node: '>=6.0'}
-    peerDependencies:
-      supports-color: '*'
-    peerDependenciesMeta:
-      supports-color:
-        optional: true
+  /decimal.js/10.3.1:
+    resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
+    dev: true
+
+  /deep-eql/3.0.1:
+    resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==}
+    engines: {node: '>=0.12'}
     dependencies:
-      ms: 2.1.2
-      supports-color: 9.2.2
+      type-detect: 4.0.8
+    dev: true
+
+  /deep-is/0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
     dev: true
 
   /define-properties/1.1.4:
@@ -1700,6 +3833,13 @@ packages:
     resolution: {integrity: sha512-jNCX+uNJ3v38BKvPbpki6j5ItVlnSqVV6vDWGS6rExzCMjsc39frLjm1n91o6YaKK6AZl0wLloItW6C6mr61BQ==}
     dev: true
 
+  /domexception/4.0.0:
+    resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
+    engines: {node: '>=12'}
+    dependencies:
+      webidl-conversions: 7.0.0
+    dev: true
+
   /duplexer/0.1.2:
     resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
     dev: true
@@ -1750,6 +3890,11 @@ packages:
       ansi-colors: 4.1.3
     dev: true
 
+  /entities/4.3.1:
+    resolution: {integrity: sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==}
+    engines: {node: '>=0.12'}
+    dev: true
+
   /error-ex/1.3.2:
     resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
     dependencies:
@@ -2020,10 +4165,39 @@ packages:
     engines: {node: '>=0.8.0'}
     dev: true
 
+  /escodegen/2.0.0:
+    resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==}
+    engines: {node: '>=6.0'}
+    hasBin: true
+    dependencies:
+      esprima: 4.0.1
+      estraverse: 5.3.0
+      esutils: 2.0.3
+      optionator: 0.8.3
+    optionalDependencies:
+      source-map: 0.6.1
+    dev: true
+
+  /esprima/4.0.1:
+    resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+    engines: {node: '>=4'}
+    hasBin: true
+    dev: true
+
+  /estraverse/5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+    dev: true
+
   /estree-walker/2.0.2:
     resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
     dev: true
 
+  /esutils/2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
   /event-stream/3.3.4:
     resolution: {integrity: sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=}
     dependencies:
@@ -2070,6 +4244,21 @@ packages:
       strip-final-newline: 2.0.0
     dev: true
 
+  /execa/6.1.0:
+    resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      cross-spawn: 7.0.3
+      get-stream: 6.0.1
+      human-signals: 3.0.1
+      is-stream: 3.0.0
+      merge-stream: 2.0.0
+      npm-run-path: 5.1.0
+      onetime: 6.0.0
+      signal-exit: 3.0.7
+      strip-final-newline: 3.0.0
+    dev: true
+
   /executable/4.1.1:
     resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==}
     engines: {node: '>=4'}
@@ -2118,6 +4307,10 @@ packages:
       micromatch: 4.0.5
     dev: true
 
+  /fast-levenshtein/2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+    dev: true
+
   /fastq/1.13.0:
     resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==}
     dependencies:
@@ -2178,6 +4371,15 @@ packages:
       mime-types: 2.1.35
     dev: true
 
+  /form-data/4.0.0:
+    resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+    engines: {node: '>= 6'}
+    dependencies:
+      asynckit: 0.4.0
+      combined-stream: 1.0.8
+      mime-types: 2.1.35
+    dev: true
+
   /from/0.1.7:
     resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
     dev: true
@@ -2236,6 +4438,10 @@ packages:
     engines: {node: '>=6.9.0'}
     dev: true
 
+  /get-func-name/2.0.0:
+    resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
+    dev: true
+
   /get-intrinsic/1.1.2:
     resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==}
     dependencies:
@@ -2244,11 +4450,6 @@ packages:
       has-symbols: 1.0.3
     dev: true
 
-  /get-port/5.1.1:
-    resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==}
-    engines: {node: '>=8'}
-    dev: true
-
   /get-stream/5.2.0:
     resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
     engines: {node: '>=8'}
@@ -2375,11 +4576,29 @@ packages:
     resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
     dev: true
 
+  /html-encoding-sniffer/3.0.0:
+    resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
+    engines: {node: '>=12'}
+    dependencies:
+      whatwg-encoding: 2.0.0
+    dev: true
+
   /html-tags/2.0.0:
     resolution: {integrity: sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==}
     engines: {node: '>=4'}
     dev: true
 
+  /http-proxy-agent/5.0.0:
+    resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
+    engines: {node: '>= 6'}
+    dependencies:
+      '@tootallnate/once': 2.0.0
+      agent-base: 6.0.2
+      debug: 4.3.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
   /http-signature/1.3.6:
     resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==}
     engines: {node: '>=0.10'}
@@ -2389,6 +4608,16 @@ packages:
       sshpk: 1.17.0
     dev: true
 
+  /https-proxy-agent/5.0.1:
+    resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
+    engines: {node: '>= 6'}
+    dependencies:
+      agent-base: 6.0.2
+      debug: 4.3.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
   /human-signals/1.1.1:
     resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
     engines: {node: '>=8.12.0'}
@@ -2399,12 +4628,24 @@ packages:
     engines: {node: '>=10.17.0'}
     dev: true
 
+  /human-signals/3.0.1:
+    resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==}
+    engines: {node: '>=12.20.0'}
+    dev: true
+
   /husky/8.0.1:
     resolution: {integrity: sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==}
     engines: {node: '>=14'}
     hasBin: true
     dev: true
 
+  /iconv-lite/0.6.3:
+    resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      safer-buffer: 2.1.2
+    dev: true
+
   /ieee754/1.2.1:
     resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
     dev: true
@@ -2552,6 +4793,10 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /is-potential-custom-element-name/1.0.1:
+    resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+    dev: true
+
   /is-regex/1.1.4:
     resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
     engines: {node: '>= 0.4'}
@@ -2571,6 +4816,11 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /is-stream/3.0.0:
+    resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dev: true
+
   /is-string/1.0.7:
     resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
     engines: {node: '>= 0.4'}
@@ -2642,6 +4892,48 @@ packages:
     resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
     dev: true
 
+  /jsdom/20.0.0:
+    resolution: {integrity: sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      canvas: ^2.5.0
+    peerDependenciesMeta:
+      canvas:
+        optional: true
+    dependencies:
+      abab: 2.0.6
+      acorn: 8.7.1
+      acorn-globals: 6.0.0
+      cssom: 0.5.0
+      cssstyle: 2.3.0
+      data-urls: 3.0.2
+      decimal.js: 10.3.1
+      domexception: 4.0.0
+      escodegen: 2.0.0
+      form-data: 4.0.0
+      html-encoding-sniffer: 3.0.0
+      http-proxy-agent: 5.0.0
+      https-proxy-agent: 5.0.1
+      is-potential-custom-element-name: 1.0.1
+      nwsapi: 2.2.1
+      parse5: 7.0.0
+      saxes: 6.0.0
+      symbol-tree: 3.2.4
+      tough-cookie: 4.0.0
+      w3c-hr-time: 1.0.2
+      w3c-xmlserializer: 3.0.0
+      webidl-conversions: 7.0.0
+      whatwg-encoding: 2.0.0
+      whatwg-mimetype: 3.0.0
+      whatwg-url: 11.0.0
+      ws: 8.8.0
+      xml-name-validator: 4.0.0
+    transitivePeerDependencies:
+      - bufferutil
+      - supports-color
+      - utf-8-validate
+    dev: true
+
   /jsesc/2.5.2:
     resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
     engines: {node: '>=4'}
@@ -2705,32 +4997,40 @@ packages:
     engines: {node: '> 0.8'}
     dev: true
 
+  /levn/0.3.0:
+    resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.1.2
+      type-check: 0.3.2
+    dev: true
+
   /lilconfig/2.0.5:
     resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==}
     engines: {node: '>=10'}
     dev: true
 
-  /lint-staged/12.5.0:
-    resolution: {integrity: sha512-BKLUjWDsKquV/JuIcoQW4MSAI3ggwEImF1+sB4zaKvyVx1wBk3FsG7UK9bpnmBTN1pm7EH2BBcMwINJzCRv12g==}
-    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+  /lint-staged/13.0.3:
+    resolution: {integrity: sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==}
+    engines: {node: ^14.13.1 || >=16.0.0}
     hasBin: true
     dependencies:
       cli-truncate: 3.1.0
       colorette: 2.0.19
       commander: 9.3.0
-      debug: 4.3.4_supports-color@9.2.2
-      execa: 5.1.1
+      debug: 4.3.4
+      execa: 6.1.0
       lilconfig: 2.0.5
       listr2: 4.0.5
       micromatch: 4.0.5
       normalize-path: 3.0.0
       object-inspect: 1.12.2
-      pidtree: 0.5.0
+      pidtree: 0.6.0
       string-argv: 0.3.1
-      supports-color: 9.2.2
-      yaml: 1.10.2
+      yaml: 2.1.1
     transitivePeerDependencies:
       - enquirer
+      - supports-color
     dev: true
 
   /listr2/3.14.0_enquirer@2.3.6:
@@ -2782,6 +5082,11 @@ packages:
       strip-bom: 3.0.0
     dev: true
 
+  /local-pkg/0.4.1:
+    resolution: {integrity: sha512-lL87ytIGP2FU5PWwNDo0w3WhIo2gopIAxPg9RxDYF7m4rr5ahuZxP22xnJHIvaLTe4Z9P6uKKY2UHiwyB4pcrw==}
+    engines: {node: '>=14'}
+    dev: true
+
   /lodash.kebabcase/4.1.1:
     resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==}
     dev: true
@@ -2812,6 +5117,12 @@ packages:
       wrap-ansi: 6.2.0
     dev: true
 
+  /loupe/2.3.4:
+    resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==}
+    dependencies:
+      get-func-name: 2.0.0
+    dev: true
+
   /lru-cache/4.1.5:
     resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
     dependencies:
@@ -2882,6 +5193,11 @@ packages:
     engines: {node: '>=6'}
     dev: true
 
+  /mimic-fn/4.0.0:
+    resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+    engines: {node: '>=12'}
+    dev: true
+
   /minimatch/3.1.2:
     resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
     dependencies:
@@ -2970,6 +5286,17 @@ packages:
       path-key: 3.1.1
     dev: true
 
+  /npm-run-path/5.1.0:
+    resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    dependencies:
+      path-key: 4.0.0
+    dev: true
+
+  /nwsapi/2.2.1:
+    resolution: {integrity: sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg==}
+    dev: true
+
   /object-inspect/1.12.2:
     resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==}
     dev: true
@@ -3002,6 +5329,25 @@ packages:
       mimic-fn: 2.1.0
     dev: true
 
+  /onetime/6.0.0:
+    resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      mimic-fn: 4.0.0
+    dev: true
+
+  /optionator/0.8.3:
+    resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      deep-is: 0.1.4
+      fast-levenshtein: 2.0.6
+      levn: 0.3.0
+      prelude-ls: 1.1.2
+      type-check: 0.3.2
+      word-wrap: 1.2.3
+    dev: true
+
   /ospath/1.2.2:
     resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==}
     dev: true
@@ -3021,6 +5367,12 @@ packages:
       json-parse-better-errors: 1.0.2
     dev: true
 
+  /parse5/7.0.0:
+    resolution: {integrity: sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==}
+    dependencies:
+      entities: 4.3.1
+    dev: true
+
   /path-is-absolute/1.0.1:
     resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
     engines: {node: '>=0.10.0'}
@@ -3036,6 +5388,11 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /path-key/4.0.0:
+    resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+    engines: {node: '>=12'}
+    dev: true
+
   /path-parse/1.0.7:
     resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
     dev: true
@@ -3052,6 +5409,10 @@ packages:
     engines: {node: '>=8'}
     dev: true
 
+  /pathval/1.1.1:
+    resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
+    dev: true
+
   /pause-stream/0.0.11:
     resolution: {integrity: sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=}
     dependencies:
@@ -3080,8 +5441,8 @@ packages:
     hasBin: true
     dev: true
 
-  /pidtree/0.5.0:
-    resolution: {integrity: sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==}
+  /pidtree/0.6.0:
+    resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
     engines: {node: '>=0.10'}
     hasBin: true
     dev: true
@@ -3139,6 +5500,11 @@ packages:
       picocolors: 1.0.0
       source-map-js: 1.0.2
 
+  /prelude-ls/1.1.2:
+    resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
+    engines: {node: '>= 0.8.0'}
+    dev: true
+
   /prettier/2.7.1:
     resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==}
     engines: {node: '>=10.13.0'}
@@ -3305,6 +5671,13 @@ packages:
     resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
     dev: true
 
+  /saxes/6.0.0:
+    resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+    engines: {node: '>=v12.22.7'}
+    dependencies:
+      xmlchars: 2.2.0
+    dev: true
+
   /semver/5.7.1:
     resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
     hasBin: true
@@ -3552,6 +5925,11 @@ packages:
     engines: {node: '>=6'}
     dev: true
 
+  /strip-final-newline/3.0.0:
+    resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+    engines: {node: '>=12'}
+    dev: true
+
   /supports-color/5.5.0:
     resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
     engines: {node: '>=4'}
@@ -3573,11 +5951,6 @@ packages:
       has-flag: 4.0.0
     dev: true
 
-  /supports-color/9.2.2:
-    resolution: {integrity: sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==}
-    engines: {node: '>=12'}
-    dev: true
-
   /supports-preserve-symlinks-flag/1.0.0:
     resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
     engines: {node: '>= 0.4'}
@@ -3587,6 +5960,10 @@ packages:
     resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
     dev: true
 
+  /symbol-tree/3.2.4:
+    resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+    dev: true
+
   /systemjs/6.12.1:
     resolution: {integrity: sha512-hqTN6kW+pN6/qro6G9OZ7ceDQOcYno020zBQKpZQLsJhYTDMCMNfXi/Y8duF5iW+4WWZr42ry0MMkcRGpbwG2A==}
     dev: true
@@ -3599,6 +5976,16 @@ packages:
     resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
     dev: true
 
+  /tinypool/0.1.3:
+    resolution: {integrity: sha512-2IfcQh7CP46XGWGGbdyO4pjcKqsmVqFAPcXfPxcPXmOWt9cYkTP9HcDmGgsfijYoAEc4z9qcpM/BaBz46Y9/CQ==}
+    engines: {node: '>=14.0.0'}
+    dev: true
+
+  /tinyspy/0.3.3:
+    resolution: {integrity: sha512-gRiUR8fuhUf0W9lzojPf1N1euJYA30ISebSfgca8z76FOvXtVXqd5ojEIaKLWbDQhAaC3ibxZIjqbyi4ybjcTw==}
+    engines: {node: '>=14.0.0'}
+    dev: true
+
   /tmp/0.2.1:
     resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
     engines: {node: '>=8.17.0'}
@@ -3625,10 +6012,26 @@ packages:
       punycode: 2.1.1
     dev: true
 
+  /tough-cookie/4.0.0:
+    resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==}
+    engines: {node: '>=6'}
+    dependencies:
+      psl: 1.9.0
+      punycode: 2.1.1
+      universalify: 0.1.2
+    dev: true
+
   /tr46/0.0.3:
     resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
     dev: true
 
+  /tr46/3.0.0:
+    resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
+    engines: {node: '>=12'}
+    dependencies:
+      punycode: 2.1.1
+    dev: true
+
   /tslib/2.4.0:
     resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
     dev: true
@@ -3643,6 +6046,18 @@ packages:
     resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
     dev: true
 
+  /type-check/0.3.2:
+    resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.1.2
+    dev: true
+
+  /type-detect/4.0.8:
+    resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+    engines: {node: '>=4'}
+    dev: true
+
   /type-fest/0.21.3:
     resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
     engines: {node: '>=10'}
@@ -3662,6 +6077,11 @@ packages:
       which-boxed-primitive: 1.0.2
     dev: true
 
+  /universalify/0.1.2:
+    resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
+    engines: {node: '>= 4.0.0'}
+    dev: true
+
   /universalify/2.0.0:
     resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
     engines: {node: '>= 10.0.0'}
@@ -3728,6 +6148,42 @@ packages:
       fsevents: 2.3.2
     dev: true
 
+  /vitest/0.15.2_jsdom@20.0.0:
+    resolution: {integrity: sha512-cMabuUqu+nNHafkdN7H8Z20+UZTrrUfqjGwAoLwUwrqFGWBz3gXwxndjbLf6mgSFs9lF/JWjKeNM1CXKwtk26w==}
+    engines: {node: '>=v14.16.0'}
+    hasBin: true
+    peerDependencies:
+      '@vitest/ui': '*'
+      c8: '*'
+      happy-dom: '*'
+      jsdom: '*'
+    peerDependenciesMeta:
+      '@vitest/ui':
+        optional: true
+      c8:
+        optional: true
+      happy-dom:
+        optional: true
+      jsdom:
+        optional: true
+    dependencies:
+      '@types/chai': 4.3.1
+      '@types/chai-subset': 1.3.3
+      '@types/node': 18.0.3
+      chai: 4.3.6
+      debug: 4.3.4
+      jsdom: 20.0.0
+      local-pkg: 0.4.1
+      tinypool: 0.1.3
+      tinyspy: 0.3.3
+      vite: 2.9.14
+    transitivePeerDependencies:
+      - less
+      - sass
+      - stylus
+      - supports-color
+    dev: true
+
   /vue-demi/0.13.2_vue@2.7.4:
     resolution: {integrity: sha512-41ukrclEbMddAyP7PvxMSYqnOSzPV6r7GNnyTSKSCNTaz19GehxmTiXyP9kwHSUv2+Dr6hHqiUiF7L1VAw2KdQ==}
     engines: {node: '>=12'}
@@ -3770,6 +6226,19 @@ packages:
       '@vue/compiler-sfc': 2.7.4
       csstype: 3.1.0
 
+  /w3c-hr-time/1.0.2:
+    resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
+    dependencies:
+      browser-process-hrtime: 1.0.0
+    dev: true
+
+  /w3c-xmlserializer/3.0.0:
+    resolution: {integrity: sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==}
+    engines: {node: '>=12'}
+    dependencies:
+      xml-name-validator: 4.0.0
+    dev: true
+
   /wait-on/6.0.0_debug@4.3.2:
     resolution: {integrity: sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw==}
     engines: {node: '>=10.0.0'}
@@ -3788,6 +6257,31 @@ packages:
     resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
     dev: true
 
+  /webidl-conversions/7.0.0:
+    resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /whatwg-encoding/2.0.0:
+    resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
+    engines: {node: '>=12'}
+    dependencies:
+      iconv-lite: 0.6.3
+    dev: true
+
+  /whatwg-mimetype/3.0.0:
+    resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /whatwg-url/11.0.0:
+    resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      tr46: 3.0.0
+      webidl-conversions: 7.0.0
+    dev: true
+
   /whatwg-url/5.0.0:
     resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
     dependencies:
@@ -3820,6 +6314,11 @@ packages:
       isexe: 2.0.0
     dev: true
 
+  /word-wrap/1.2.3:
+    resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
   /wrap-ansi/6.2.0:
     resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
     engines: {node: '>=8'}
@@ -3842,6 +6341,28 @@ packages:
     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
     dev: true
 
+  /ws/8.8.0:
+    resolution: {integrity: sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      bufferutil: ^4.0.1
+      utf-8-validate: ^5.0.2
+    peerDependenciesMeta:
+      bufferutil:
+        optional: true
+      utf-8-validate:
+        optional: true
+    dev: true
+
+  /xml-name-validator/4.0.0:
+    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /xmlchars/2.2.0:
+    resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+    dev: true
+
   /yallist/2.1.2:
     resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
     dev: true
@@ -3850,9 +6371,9 @@ packages:
     resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
     dev: true
 
-  /yaml/1.10.2:
-    resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
-    engines: {node: '>= 6'}
+  /yaml/2.1.1:
+    resolution: {integrity: sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==}
+    engines: {node: '>= 14'}
     dev: true
 
   /yauzl/2.10.0:
index 672be09fb5695d0740434ec64abb54f84a9e56c4..d7a06b644bc9ee1615f1d68565823a6e58f6ebef 100644 (file)
@@ -1,3 +1,5 @@
 packages:
   - 'playground/**'
-  - '!template/**'
+  - 'template/base'
+  - 'template/config/**'
+  - 'template/tsconfig/**'
index 612599368e39103d65f74e8a4b8494762f0d05a8..b255ccd673d69d5af3589cb863cae83bef7c90aa 100644 (file)
@@ -26,7 +26,7 @@ SOFTWARE.
 
 await esbuild.build({
   bundle: true,
-  entryPoints: ['index.js'],
+  entryPoints: ['index.ts'],
   outfile: 'outfile.cjs',
   format: 'cjs',
   platform: 'node',
index ad44a86c77fcd37dd175ea13b1079199f39d8e77..104fddf4d86131f5aea09ab4623f932fb2a30b60 100644 (file)
@@ -3,7 +3,7 @@ import 'zx/globals'
 
 $.verbose = false
 
-const featureFlags = ['typescript', 'router', 'pinia', 'with-tests']
+const featureFlags = ['typescript', 'jsx', 'router', 'pinia', 'vitest', 'cypress']
 
 // The following code & comments are generated by GitHub CoPilot.
 function fullCombination(arr) {
@@ -41,7 +41,7 @@ flagCombinations.push(['default'])
 // Previously it means `--cypress` without `--vitest`.
 // Here we generate the snapshots only for the sake of easier comparison with older templates.
 // They may be removed in later releases.
-const withTestsFlags = fullCombination(['typescript', 'router', 'pinia']).map((args) => [
+const withTestsFlags = fullCombination(['typescript', 'jsx', 'router', 'pinia']).map((args) => [
   ...args,
   'with-tests'
 ])
index 5d29eb1c8757d6b96ef0766498411fdab9177db4..a8c2eaa7324833a39aa2749130cb4b8566e26c11 100644 (file)
@@ -4,11 +4,40 @@ import 'zx/globals'
 const playgroundDir = path.resolve(__dirname, '../playground/')
 
 for (const projectName of fs.readdirSync(playgroundDir)) {
+  if (projectName.includes('vitest')) {
+    cd(path.resolve(playgroundDir, projectName))
+
+    console.log(`Running unit tests in ${projectName}`)
+    await $`pnpm test:unit`
+  }
+
+  if (projectName.includes('cypress')) {
+    cd(path.resolve(playgroundDir, projectName))
+
+    console.log(`Building ${projectName}`)
+    await $`pnpm build`
+
+    console.log(`Running e2e tests in ${projectName}`)
+    await $`pnpm test:e2e:ci`
+
+    // Without Vitest, the project will use Cypress Component Testing for unit testing
+    if (!projectName.includes('vitest')) {
+      // Cypress Component Testing is flaky in CI environment, so we need to tolerate the errors.
+      try {
+        await `pnpm test:unit:ci`
+      } catch (e) {
+        console.error(`Component Testing in ${projectName} fails:`)
+        console.error(e)
+      }
+    }
+  }
+
+  // equivalent of `--vitest --cypress`
   if (projectName.endsWith('with-tests')) {
     cd(path.resolve(playgroundDir, projectName))
 
     console.log(`Running unit tests in ${projectName}`)
-    await $`pnpm test:unit:ci`
+    await $`pnpm test:unit`
 
     console.log(`Building ${projectName}`)
     await $`pnpm build`
diff --git a/snapshot.js b/snapshot.js
deleted file mode 100644 (file)
index 5ff3824..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-import { spawnSync } from 'child_process'
-import path from 'path'
-
-const __dirname = path
-  .dirname(new URL(import.meta.url).pathname)
-  .substring(process.platform === 'win32' ? 1 : 0)
-
-const bin = path.resolve(__dirname, './outfile.cjs')
-const playgroundDir = path.resolve(__dirname, './playground/')
-
-function createProjectWithFeatureFlags(flags) {
-  const projectName = flags.join('-')
-  console.log(`Creating project ${projectName}`)
-  const { status } = spawnSync(
-    'node',
-    [bin, projectName, ...flags.map((flag) => `--${flag}`), '--force'],
-    {
-      cwd: playgroundDir,
-      stdio: ['pipe', 'pipe', 'inherit']
-    }
-  )
-
-  if (status !== 0) {
-    process.exit(status)
-  }
-}
-
-const featureFlags = ['typescript', 'router', 'pinia', 'with-tests']
-
-// The following code & comments are generated by GitHub CoPilot.
-function fullCombination(arr) {
-  const combinations = []
-
-  // for an array of 5 elements, there are 2^5 - 1= 31 combinations
-  // (excluding the empty combination)
-  // equivalent to the following:
-  // [0, 0, 0, 0, 1] ... [1, 1, 1, 1, 1]
-  // We can represent the combinations as a binary number
-  // where each digit represents a flag
-  // and the number is the index of the flag
-  // e.g.
-  // [0, 0, 0, 0, 1] = 0b0001
-  // [1, 1, 1, 1, 1] = 0b1111
-
-  // Note we need to exclude the empty comination in our case
-  for (let i = 1; i < 1 << arr.length; i++) {
-    const combination = []
-    for (let j = 0; j < arr.length; j++) {
-      if (i & (1 << j)) {
-        combination.push(arr[j])
-      }
-    }
-    combinations.push(combination)
-  }
-
-  return combinations
-}
-
-const flagCombinations = fullCombination(featureFlags)
-flagCombinations.push(['default'])
-
-for (const flags of flagCombinations) {
-  createProjectWithFeatureFlags(flags)
-}
index 572cb9e331f298f96cc03e4db3293df50e4c20ab..0238744034f02a942ac45b080f2e4133122ce15c 100644 (file)
@@ -2,15 +2,14 @@
   "scripts": {
     "dev": "vite",
     "build": "vite build",
-    "preview": "vite preview --port 5050"
+    "preview": "vite preview --port 4173"
   },
   "dependencies": {
-    "vue": "^2.7.0-0"
+    "vue": "^2.7.4"
   },
   "devDependencies": {
-    "@vitejs/plugin-legacy": "^1.7.1",
-    "@vitejs/plugin-vue2": "^1.1.1",
-    "@vitejs/plugin-vue2-jsx": "^1.0.1",
-    "vite": "^2.8.4"
+    "@vitejs/plugin-legacy": "^1.8.2",
+    "@vitejs/plugin-vue2": "^1.1.2",
+    "vite": "^2.9.14"
   }
 }
index 7cbd617eedb005606b7124de1d68ee8e33f2e1e2..4e5234335e3adf40ba8033b02c12a9ae1be5c8b7 100644 (file)
@@ -3,13 +3,11 @@ import { fileURLToPath } from 'url'
 import { defineConfig } from 'vite'
 import legacy from '@vitejs/plugin-legacy'
 import vue2 from '@vitejs/plugin-vue2'
-import vue2Jsx from '@vitejs/plugin-vue2-jsx'
 
 // https://vitejs.dev/config/
 export default defineConfig({
   plugins: [
     vue2(),
-    vue2Jsx(),
     legacy({
       targets: ['ie >= 11'],
       additionalLegacyPolyfills: ['regenerator-runtime/runtime']
diff --git a/template/code/default/src/components/__tests__/HelloWorld.spec.js b/template/code/default/src/components/__tests__/HelloWorld.spec.js
deleted file mode 100644 (file)
index d6fb360..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import { mount } from '@cypress/vue'
-import HelloWorld from '../HelloWorld.vue'
-
-describe('HelloWorld', () => {
-  it('playground', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
-  })
-
-  it('renders properly', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
-    cy.get('h1').should('contain', 'Hello Cypress')
-  })
-})
diff --git a/template/code/router/cypress/integration/example.spec.js b/template/code/router/cypress/integration/example.spec.js
deleted file mode 100644 (file)
index 13a2922..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// https://docs.cypress.io/api/introduction/api.html
-
-describe('My First Test', () => {
-  it('visits the app root url', () => {
-    cy.visit('/')
-    cy.contains('h1', 'You did it!')
-  })
-
-  it('navigates to the about page', () => {
-    cy.visit('/about')
-    cy.contains('h1', 'This is an about page')
-  })
-})
diff --git a/template/code/typescript-default/cypress/integration/example.spec.ts b/template/code/typescript-default/cypress/integration/example.spec.ts
deleted file mode 100644 (file)
index 7a8c909..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// https://docs.cypress.io/api/introduction/api.html
-
-describe('My First Test', () => {
-  it('visits the app root url', () => {
-    cy.visit('/')
-    cy.contains('h1', 'You did it!')
-  })
-})
diff --git a/template/code/typescript-default/src/components/__tests__/HelloWorld.spec.ts b/template/code/typescript-default/src/components/__tests__/HelloWorld.spec.ts
deleted file mode 100644 (file)
index d6fb360..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import { mount } from '@cypress/vue'
-import HelloWorld from '../HelloWorld.vue'
-
-describe('HelloWorld', () => {
-  it('playground', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
-  })
-
-  it('renders properly', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
-    cy.get('h1').should('contain', 'Hello Cypress')
-  })
-})
diff --git a/template/code/typescript-router/cypress/integration/example.spec.ts b/template/code/typescript-router/cypress/integration/example.spec.ts
deleted file mode 100644 (file)
index 13a2922..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// https://docs.cypress.io/api/introduction/api.html
-
-describe('My First Test', () => {
-  it('visits the app root url', () => {
-    cy.visit('/')
-    cy.contains('h1', 'You did it!')
-  })
-
-  it('navigates to the about page', () => {
-    cy.visit('/about')
-    cy.contains('h1', 'This is an about page')
-  })
-})
diff --git a/template/code/typescript-router/src/components/__tests__/HelloWorld.spec.ts b/template/code/typescript-router/src/components/__tests__/HelloWorld.spec.ts
deleted file mode 100644 (file)
index d6fb360..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import { mount } from '@cypress/vue'
-import HelloWorld from '../HelloWorld.vue'
-
-describe('HelloWorld', () => {
-  it('playground', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
-  })
-
-  it('renders properly', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
-    cy.get('h1').should('contain', 'Hello Cypress')
-  })
-})
diff --git a/template/config/cypress-ct/cypress.config.js b/template/config/cypress-ct/cypress.config.js
new file mode 100644 (file)
index 0000000..c3aba74
--- /dev/null
@@ -0,0 +1,15 @@
+const { defineConfig } = require('cypress')
+
+module.exports = defineConfig({
+  e2e: {
+    specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
+    baseUrl: 'http://localhost:4173'
+  },
+  component: {
+    specPattern: 'src/**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}',
+    devServer: {
+      framework: 'vue',
+      bundler: 'vite'
+    }
+  }
+})
diff --git a/template/config/cypress-ct/cypress.config.ts b/template/config/cypress-ct/cypress.config.ts
new file mode 100644 (file)
index 0000000..c8fac12
--- /dev/null
@@ -0,0 +1,15 @@
+import { defineConfig } from 'cypress'
+
+export default defineConfig({
+  e2e: {
+    specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
+    baseUrl: 'http://localhost:4173'
+  },
+  component: {
+    specPattern: 'src/**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}',
+    devServer: {
+      framework: 'vue',
+      bundler: 'vite'
+    }
+  }
+})
diff --git a/template/config/cypress-ct/cypress/support/component-index.html b/template/config/cypress-ct/cypress/support/component-index.html
new file mode 100644 (file)
index 0000000..5f9622a
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>Components App</title>
+  </head>
+  <body>
+    <div data-cy-root></div>
+  </body>
+</html>
diff --git a/template/config/cypress-ct/cypress/support/component.js b/template/config/cypress-ct/cypress/support/component.js
new file mode 100644 (file)
index 0000000..3d1a3d2
--- /dev/null
@@ -0,0 +1,27 @@
+// ***********************************************************
+// This example support/component.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
+
+import { mount } from 'cypress/vue2'
+
+Cypress.Commands.add('mount', mount)
+
+// Example use:
+// cy.mount(MyComponent)
diff --git a/template/config/cypress-ct/cypress/support/component.ts b/template/config/cypress-ct/cypress/support/component.ts
new file mode 100644 (file)
index 0000000..c56a294
--- /dev/null
@@ -0,0 +1,39 @@
+// ***********************************************************
+// This example support/component.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
+
+import { mount } from 'cypress/vue2'
+
+// Augment the Cypress namespace to include type definitions for
+// your custom command.
+// Alternatively, can be defined in cypress/support/component.d.ts
+// with a <reference path="./component" /> at the top of your spec.
+declare global {
+  namespace Cypress {
+    interface Chainable {
+      mount: typeof mount
+    }
+  }
+}
+
+Cypress.Commands.add('mount', mount)
+
+// Example use:
+// cy.mount(MyComponent)
diff --git a/template/config/cypress-ct/package.json b/template/config/cypress-ct/package.json
new file mode 100644 (file)
index 0000000..ef570bb
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "scripts": {
+    "test:unit": "cypress open --component",
+    "test:unit:ci": "cypress run --component --quiet --reporter spec"
+  },
+  "dependencies": {
+    "vue": "^2.7.4"
+  },
+  "devDependencies": {
+    "cypress": "^10.3.0"
+  }
+}
similarity index 55%
rename from template/code/router/src/components/__tests__/HelloWorld.spec.js
rename to template/config/cypress-ct/src/components/__tests__/HelloWorld.cy.js
index d6fb360b053b7de3b70e9fba6a11ff6c7db91a27..0e0c065a1b8a6cdfe094adc3a5af0c316772c18d 100644 (file)
@@ -1,13 +1,12 @@
-import { mount } from '@cypress/vue'
 import HelloWorld from '../HelloWorld.vue'
 
 describe('HelloWorld', () => {
   it('playground', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
+    cy.mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
   })
 
   it('renders properly', () => {
-    mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
+    cy.mount(HelloWorld, { propsData: { msg: 'Hello Cypress' } })
     cy.get('h1').should('contain', 'Hello Cypress')
   })
 })
diff --git a/template/config/cypress/cypress.config.js b/template/config/cypress/cypress.config.js
new file mode 100644 (file)
index 0000000..9cf6a19
--- /dev/null
@@ -0,0 +1,8 @@
+const { defineConfig } = require('cypress')
+
+module.exports = defineConfig({
+  e2e: {
+    specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
+    baseUrl: 'http://localhost:4173'
+  }
+})
diff --git a/template/config/cypress/cypress.config.ts b/template/config/cypress/cypress.config.ts
new file mode 100644 (file)
index 0000000..0f66080
--- /dev/null
@@ -0,0 +1,8 @@
+import { defineConfig } from 'cypress'
+
+export default defineConfig({
+  e2e: {
+    specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
+    baseUrl: 'http://localhost:4173'
+  }
+})
diff --git a/template/config/cypress/cypress.json b/template/config/cypress/cypress.json
deleted file mode 100644 (file)
index 3d37225..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "baseUrl": "http://localhost:5050",
-  "component": {
-    "componentFolder": "src",
-    "testFiles": "**/__tests__/*.spec.{js,ts,jsx,tsx}"
-  }
-}
similarity index 70%
rename from template/config/cypress/cypress/jsconfig.json
rename to template/config/cypress/cypress/e2e/jsconfig.json
index b5b2f972cd5b29097579b24dda59d3a760b0cbf3..c790a70d6eda522396f4e19c62f9500e190b243c 100644 (file)
@@ -4,5 +4,5 @@
     "lib": ["es5", "dom"],
     "types": ["cypress"]
   },
-  "include": ["./**/*"]
+  "include": ["./**/*", "../support/**/*"]
 }
diff --git a/template/config/cypress/cypress/plugins/index.js b/template/config/cypress/cypress/plugins/index.js
deleted file mode 100644 (file)
index ad2e351..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/// <reference types="cypress" />
-// ***********************************************************
-// This example plugins/index.js can be used to load plugins
-//
-// You can change the location of this file or turn off loading
-// the plugins file with the 'pluginsFile' configuration option.
-//
-// You can read more here:
-// https://on.cypress.io/plugins-guide
-// ***********************************************************
-
-// This function is called when a project is opened or re-opened (e.g. due to
-// the project's config changing)
-
-const { startDevServer } = require('@cypress/vite-dev-server')
-
-/**
- * @type {Cypress.PluginConfig}
- */
-// eslint-disable-next-line no-unused-vars
-module.exports = (on, config) => {
-  // `on` is used to hook into various events Cypress emits
-  // `config` is the resolved Cypress config
-  on('dev-server:start', (options) => {
-    return startDevServer({ options })
-  })
-  return config
-}
diff --git a/template/config/cypress/cypress/support/commands.ts b/template/config/cypress/cypress/support/commands.ts
new file mode 100644 (file)
index 0000000..95857ae
--- /dev/null
@@ -0,0 +1,37 @@
+/// <reference types="cypress" />
+// ***********************************************
+// This example commands.ts shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
+//
+// declare global {
+//   namespace Cypress {
+//     interface Chainable {
+//       login(email: string, password: string): Chainable<void>
+//       drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
+//       dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
+//       visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
+//     }
+//   }
+// }
index f631436ca46401f80a3997d8bd49afcefe49afe2..58cfb9655d9efb9d169edec24d6bd3221e70e074 100644 (file)
@@ -1,15 +1,10 @@
 {
   "scripts": {
-    "test:unit": "cypress open-ct",
-    "test:unit:ci": "cypress run-ct --quiet --reporter spec",
-    "test:e2e": "start-server-and-test preview http://127.0.0.1:5050/ 'cypress open'",
-    "test:e2e:ci": "start-server-and-test preview http://127.0.0.1:5050/ 'cypress run'"
+    "test:e2e": "start-server-and-test preview http://127.0.0.1:4173/ 'cypress open --e2e'",
+    "test:e2e:ci": "start-server-and-test preview http://127.0.0.1:4173/ 'cypress run --e2e'"
   },
   "devDependencies": {
-    "@cypress/vite-dev-server": "^2.2.2",
-    "@cypress/vue": "^2.2.4",
-    "cypress": "^9.5.0",
-    "start-server-and-test": "^1.14.0",
-    "vue-template-compiler": "^2.7.0-0"
+    "cypress": "^10.3.0",
+    "start-server-and-test": "^1.14.0"
   }
 }
diff --git a/template/config/jsx/package.json b/template/config/jsx/package.json
new file mode 100644 (file)
index 0000000..78c2448
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "dependencies": {
+    "vue": "^2.7.4"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue2-jsx": "^1.0.1",
+    "vite": "^2.9.14"
+  }
+}
diff --git a/template/config/jsx/vite.config.js b/template/config/jsx/vite.config.js
new file mode 100644 (file)
index 0000000..7cbd617
--- /dev/null
@@ -0,0 +1,23 @@
+import { fileURLToPath } from 'url'
+
+import { defineConfig } from 'vite'
+import legacy from '@vitejs/plugin-legacy'
+import vue2 from '@vitejs/plugin-vue2'
+import vue2Jsx from '@vitejs/plugin-vue2-jsx'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [
+    vue2(),
+    vue2Jsx(),
+    legacy({
+      targets: ['ie >= 11'],
+      additionalLegacyPolyfills: ['regenerator-runtime/runtime']
+    })
+  ],
+  resolve: {
+    alias: {
+      '@': fileURLToPath(new URL('./src', import.meta.url))
+    }
+  }
+})
index b5829b6dd41c85d31206e39618d330251d41f6fe..ca91d542e589c874f38379ed5f36a5093697bc4a 100644 (file)
@@ -1,5 +1,6 @@
 {
   "dependencies": {
-    "pinia": "^2.0.11"
+    "pinia": "^2.0.14",
+    "vue": "^2.7.4"
   }
 }
index aeb4cb0a0bc448c40626caaedc99d2e292f64962..b96bd7c6f7052822bbd1073be15e2f778b0a5607 100644 (file)
@@ -1,5 +1,5 @@
 {
   "dependencies": {
-    "vue-router": "^3.5.3"
+    "vue-router": "^3.5.4"
   }
 }
index 77382e2237b28b4cf644dbdc03e366666f9ac6c2..ead35722adc274ceb0671ce5c4fb245d2c0fb176 100644 (file)
@@ -1,11 +1,13 @@
 {
   "scripts": {
-    "build": "vue-tsc --noEmit && vite build",
-    "typecheck": "vue-tsc --noEmit"
+    "build": "run-p type-check build-only",
+    "build-only": "vite build",
+    "type-check": "vue-tsc --noEmit"
   },
   "devDependencies": {
-    "@types/node": "^16.11.25",
-    "typescript": "~4.7.3",
-    "vue-tsc": "^0.38.2"
+    "@types/node": "^16.11.43",
+    "npm-run-all": "^4.1.5",
+    "typescript": "~4.7.4",
+    "vue-tsc": "^0.38.4"
   }
 }
diff --git a/template/config/typescript/tsconfig.json b/template/config/typescript/tsconfig.json
deleted file mode 100644 (file)
index 764a052..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "compilerOptions": {
-    "baseUrl": "./",
-    "target": "esnext",
-    "useDefineForClassFields": true,
-    "module": "esnext",
-    "moduleResolution": "node",
-    "isolatedModules": true,
-    "strict": true,
-    "jsx": "preserve",
-    "sourceMap": true,
-    "resolveJsonModule": true,
-    "esModuleInterop": true,
-    "paths": {
-      "@/*": ["src/*"]
-    },
-    "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
-    "skipLibCheck": true
-  },
-  "vueCompilerOptions": {
-    "target": 2.7
-  },
-  "include": ["vite.config.*", "env.d.ts", "src/**/*", "src/**/*.vue"]
-}
diff --git a/template/config/vitest/package.json b/template/config/vitest/package.json
new file mode 100644 (file)
index 0000000..5e3bce7
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "scripts": {
+    "test:unit": "vitest --environment jsdom"
+  },
+  "dependencies": {
+    "vue": "^2.7.4"
+  },
+  "devDependencies": {
+    "@vue/test-utils": "^1.3.0",
+    "jsdom": "^20.0.0",
+    "vitest": "^0.15.2",
+    "vue-template-compiler": "^2.7.4"
+  }
+}
diff --git a/template/config/vitest/src/components/__tests__/HelloWorld.spec.js b/template/config/vitest/src/components/__tests__/HelloWorld.spec.js
new file mode 100644 (file)
index 0000000..293bf19
--- /dev/null
@@ -0,0 +1,11 @@
+import { describe, it, expect } from 'vitest'
+
+import { mount } from '@vue/test-utils'
+import HelloWorld from '../HelloWorld.vue'
+
+describe('HelloWorld', () => {
+  it('renders properly', () => {
+    const wrapper = mount(HelloWorld, { propsData: { msg: 'Hello Vitest' } })
+    expect(wrapper.text()).toContain('Hello Vitest')
+  })
+})
diff --git a/template/eslint/package.json b/template/eslint/package.json
new file mode 100644 (file)
index 0000000..c9fee82
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "devDependencies": {
+    "@rushstack/eslint-patch": "^1.1.0",
+    "@vue/eslint-config-prettier": "^7.0.0",
+    "@vue/eslint-config-typescript": "^11.0.0",
+    "eslint": "^8.5.0",
+    "eslint-plugin-cypress": "^2.12.1",
+    "eslint-plugin-vue": "^9.0.0",
+    "prettier": "^2.5.1"
+  }
+}
diff --git a/template/tsconfig/base/package.json b/template/tsconfig/base/package.json
new file mode 100644 (file)
index 0000000..aa3386c
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "devDependencies": {
+    "@vue/tsconfig": "^0.1.3"
+  }
+}
diff --git a/template/tsconfig/base/tsconfig.config.json b/template/tsconfig/base/tsconfig.config.json
new file mode 100644 (file)
index 0000000..c2d3a30
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.node.json",
+  "include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
+  "compilerOptions": {
+    "composite": true,
+    "types": ["node"]
+  }
+}
diff --git a/template/tsconfig/base/tsconfig.json b/template/tsconfig/base/tsconfig.json
new file mode 100644 (file)
index 0000000..8d23599
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.web.json",
+  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  },
+
+  "references": [
+    {
+      "path": "./tsconfig.config.json"
+    }
+  ]
+}
diff --git a/template/tsconfig/cypress-ct/tsconfig.app.json b/template/tsconfig/cypress-ct/tsconfig.app.json
new file mode 100644 (file)
index 0000000..cdbea1d
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.web.json",
+  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
+  "exclude": ["src/**/__tests__/*"],
+  "compilerOptions": {
+    "composite": true,
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  }
+}
diff --git a/template/tsconfig/cypress-ct/tsconfig.cypress-ct.json b/template/tsconfig/cypress-ct/tsconfig.cypress-ct.json
new file mode 100644 (file)
index 0000000..29cbaa4
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "extends": "./tsconfig.app.json",
+  "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "cypress/support/component.*"],
+  "exclude": [],
+  "compilerOptions": {
+    "composite": true
+  }
+}
diff --git a/template/tsconfig/cypress-ct/tsconfig.json b/template/tsconfig/cypress-ct/tsconfig.json
new file mode 100644 (file)
index 0000000..040665b
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "files": [],
+  "references": [
+    {
+      "path": "./tsconfig.config.json"
+    },
+    {
+      "path": "./tsconfig.app.json"
+    },
+    {
+      "path": "./tsconfig.cypress-ct.json"
+    }
+  ]
+}
diff --git a/template/tsconfig/cypress/cypress/e2e/tsconfig.json b/template/tsconfig/cypress/cypress/e2e/tsconfig.json
new file mode 100644 (file)
index 0000000..be213ae
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.web.json",
+  "include": ["./**/*", "../support/**/*"],
+  "compilerOptions": {
+    "isolatedModules": false,
+    "target": "es5",
+    "lib": ["es5", "dom"],
+    "types": ["cypress"]
+  }
+}
diff --git a/template/tsconfig/vitest/package.json b/template/tsconfig/vitest/package.json
new file mode 100644 (file)
index 0000000..ec8ee29
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "scripts": {
+    "type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false"
+  },
+  "devDependencies": {
+    "@types/jsdom": "^16.2.14"
+  }
+}
diff --git a/template/tsconfig/vitest/tsconfig.app.json b/template/tsconfig/vitest/tsconfig.app.json
new file mode 100644 (file)
index 0000000..cdbea1d
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.web.json",
+  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
+  "exclude": ["src/**/__tests__/*"],
+  "compilerOptions": {
+    "composite": true,
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  }
+}
diff --git a/template/tsconfig/vitest/tsconfig.json b/template/tsconfig/vitest/tsconfig.json
new file mode 100644 (file)
index 0000000..31f9003
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "files": [],
+  "references": [
+    {
+      "path": "./tsconfig.config.json"
+    },
+    {
+      "path": "./tsconfig.app.json"
+    },
+    {
+      "path": "./tsconfig.vitest.json"
+    }
+  ]
+}
diff --git a/template/tsconfig/vitest/tsconfig.vitest.json b/template/tsconfig/vitest/tsconfig.vitest.json
new file mode 100644 (file)
index 0000000..d080d61
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "extends": "./tsconfig.app.json",
+  "exclude": [],
+  "compilerOptions": {
+    "composite": true,
+    "lib": [],
+    "types": ["node", "jsdom"]
+  }
+}
diff --git a/test.js b/test.js
deleted file mode 100644 (file)
index c80ebd3..0000000
--- a/test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import fs from 'fs'
-import path from 'path'
-import { fileURLToPath } from 'url'
-
-import { spawnSync } from 'child_process'
-
-const __dirname = path.dirname(fileURLToPath(import.meta.url))
-const playgroundDir = path.resolve(__dirname, './playground/')
-
-for (const projectName of fs.readdirSync(playgroundDir)) {
-  if (projectName.endsWith('with-tests')) {
-    console.log(`Running unit tests in ${projectName}`)
-    const unitTestResult = spawnSync('pnpm', ['test:unit:ci'], {
-      cwd: path.resolve(playgroundDir, projectName),
-      stdio: 'inherit',
-      shell: true
-    })
-    if (unitTestResult.status !== 0) {
-      throw new Error(`Unit tests failed in ${projectName}`)
-    }
-
-    console.log(`Building ${projectName}`)
-    const buildResult = spawnSync('pnpm', ['build'], {
-      cwd: path.resolve(playgroundDir, projectName),
-      stdio: 'inherit',
-      shell: true
-    })
-    if (buildResult.status !== 0) {
-      throw new Error(`Build failed in ${projectName}`)
-    }
-
-    console.log(`Running e2e tests in ${projectName}`)
-    const e2eTestResult = spawnSync('pnpm', ['test:e2e:ci'], {
-      cwd: path.resolve(playgroundDir, projectName),
-      stdio: 'inherit',
-      shell: true
-    })
-    if (e2eTestResult.status !== 0) {
-      throw new Error(`E2E tests failed in ${projectName}`)
-    }
-  }
-}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644 (file)
index 0000000..3487a8e
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.node.json",
+  "include": ["index.ts", "utils/**/*"],
+  "compilerOptions": {
+    "strict": false
+  }
+}
diff --git a/utils/banner.ts b/utils/banner.ts
new file mode 100644 (file)
index 0000000..09ce34d
--- /dev/null
@@ -0,0 +1,14 @@
+// generated by the following code:
+//
+// require('gradient-string')([
+//   { color: '#42d392', pos: 0 },
+//   { color: '#42d392', pos: 0.1 },
+//   { color: '#647eff', pos: 1 }
+// ])('Vue.js - The Progressive JavaScript Framework'))
+//
+// Use the output directly here to keep the bundle small.
+
+const banner =
+  '\x1B[38;2;66;211;146mV\x1B[39m\x1B[38;2;66;211;146mu\x1B[39m\x1B[38;2;66;211;146me\x1B[39m\x1B[38;2;66;211;146m.\x1B[39m\x1B[38;2;66;211;146mj\x1B[39m\x1B[38;2;67;209;149ms\x1B[39m \x1B[38;2;68;206;152m-\x1B[39m \x1B[38;2;69;204;155mT\x1B[39m\x1B[38;2;70;201;158mh\x1B[39m\x1B[38;2;71;199;162me\x1B[39m \x1B[38;2;72;196;165mP\x1B[39m\x1B[38;2;73;194;168mr\x1B[39m\x1B[38;2;74;192;171mo\x1B[39m\x1B[38;2;75;189;174mg\x1B[39m\x1B[38;2;76;187;177mr\x1B[39m\x1B[38;2;77;184;180me\x1B[39m\x1B[38;2;78;182;183ms\x1B[39m\x1B[38;2;79;179;186ms\x1B[39m\x1B[38;2;80;177;190mi\x1B[39m\x1B[38;2;81;175;193mv\x1B[39m\x1B[38;2;82;172;196me\x1B[39m \x1B[38;2;83;170;199mJ\x1B[39m\x1B[38;2;83;167;202ma\x1B[39m\x1B[38;2;84;165;205mv\x1B[39m\x1B[38;2;85;162;208ma\x1B[39m\x1B[38;2;86;160;211mS\x1B[39m\x1B[38;2;87;158;215mc\x1B[39m\x1B[38;2;88;155;218mr\x1B[39m\x1B[38;2;89;153;221mi\x1B[39m\x1B[38;2;90;150;224mp\x1B[39m\x1B[38;2;91;148;227mt\x1B[39m \x1B[38;2;92;145;230mF\x1B[39m\x1B[38;2;93;143;233mr\x1B[39m\x1B[38;2;94;141;236ma\x1B[39m\x1B[38;2;95;138;239mm\x1B[39m\x1B[38;2;96;136;243me\x1B[39m\x1B[38;2;97;133;246mw\x1B[39m\x1B[38;2;98;131;249mo\x1B[39m\x1B[38;2;99;128;252mr\x1B[39m\x1B[38;2;100;126;255mk\x1B[39m'
+
+export default banner
similarity index 100%
rename from utils/deepMerge.js
rename to utils/deepMerge.ts
similarity index 94%
rename from utils/directoryTraverse.js
rename to utils/directoryTraverse.ts
index 73b7fa3b81bcb0a4dc65aab149524dedeeb43240..84f805f8d960d77c5be99866805c0e0422fa8a36 100644 (file)
@@ -1,5 +1,5 @@
-import fs from 'fs'
-import path from 'path'
+import * as fs from 'fs'
+import * as path from 'path'
 
 export function preOrderDirectoryTraverse(dir, dirCallback, fileCallback) {
   for (const filename of fs.readdirSync(dir)) {
diff --git a/utils/generateReadme.js b/utils/generateReadme.js
deleted file mode 100644 (file)
index eed1964..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-import fs from 'fs'
-
-import getCommand from './getCommand.js'
-
-const sfcTypeSupportDoc =
-  '\n' +
-  '## Type Support for `.vue` Imports in TS\n' +
-  '\n' +
-  "Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates.\n" +
-  '\n' +
-  'However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can run `Volar: Switch TS Plugin on/off` from VSCode command palette.\n'
-
-export default function generateReadme({
-  projectName,
-  packageManager,
-  needsTypeScript,
-  needsTests
-}) {
-  let readme = `# ${projectName}
-
-This template should help get you started developing with Vue 2 in Vite.
-
-## Recommended IDE Setup
-
-[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (and disable Vetur).
-${needsTypeScript ? sfcTypeSupportDoc : ''}
-## Customize configuration
-
-See [Vite Configuration Reference](https://vitejs.dev/config/).
-
-## Project Setup
-
-`
-
-  let npmScriptsDescriptions = `\`\`\`sh
-${getCommand(packageManager, 'install')}
-\`\`\`
-
-### Compile and Hot-Reload for Development
-
-\`\`\`sh
-${getCommand(packageManager, 'dev')}
-\`\`\`
-
-### ${needsTypeScript ? 'Type-Check, ' : ''}Compile and Minify for Production
-
-\`\`\`sh
-${getCommand(packageManager, 'build')}
-\`\`\`
-`
-
-  if (needsTests) {
-    npmScriptsDescriptions += `
-### Run Unit Tests with [Cypress Component Testing](https://docs.cypress.io/guides/component-testing/introduction)
-
-\`\`\`sh
-${getCommand(packageManager, 'test:unit')} # or \`${getCommand(
-      packageManager,
-      'test:unit:ci'
-    )}\` for headless testing
-\`\`\`
-
-### Run End-to-End Tests with [Cypress](https://www.cypress.io/)
-
-\`\`\`sh
-${getCommand(packageManager, 'build')}
-${getCommand(packageManager, 'test:e2e')} # or \`${getCommand(
-      packageManager,
-      'test:e2e:ci'
-    )}\` for headless testing
-\`\`\`
-`
-  }
-
-  readme += npmScriptsDescriptions
-
-  return readme
-}
diff --git a/utils/generateReadme.ts b/utils/generateReadme.ts
new file mode 100644 (file)
index 0000000..569bf0e
--- /dev/null
@@ -0,0 +1,110 @@
+import getCommand from './getCommand'
+
+const sfcTypeSupportDoc = [
+  '',
+  '## Type Support for `.vue` Imports in TS',
+  '',
+  'TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.',
+  '',
+  "If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:",
+  '',
+  '1. Disable the built-in TypeScript Extension',
+  "    1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette",
+  '    2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`',
+  '2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.',
+  ''
+].join('\n')
+
+export default function generateReadme({
+  projectName,
+  packageManager,
+  needsTypeScript,
+  needsCypress,
+  needsCypressCT,
+  needsVitest,
+  needsEslint
+}) {
+  let readme = `# ${projectName}
+
+This template should help get you started developing with Vue 3 in Vite.
+
+## Recommended IDE Setup
+
+[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
+${needsTypeScript ? sfcTypeSupportDoc : ''}
+## Customize configuration
+
+See [Vite Configuration Reference](https://vitejs.dev/config/).
+
+## Project Setup
+
+`
+
+  let npmScriptsDescriptions = `\`\`\`sh
+${getCommand(packageManager, 'install')}
+\`\`\`
+
+### Compile and Hot-Reload for Development
+
+\`\`\`sh
+${getCommand(packageManager, 'dev')}
+\`\`\`
+
+### ${needsTypeScript ? 'Type-Check, ' : ''}Compile and Minify for Production
+
+\`\`\`sh
+${getCommand(packageManager, 'build')}
+\`\`\`
+`
+
+  if (needsVitest) {
+    npmScriptsDescriptions += `
+### Run Unit Tests with [Vitest](https://vitest.dev/)
+
+\`\`\`sh
+${getCommand(packageManager, 'test:unit')}
+\`\`\`
+`
+  }
+
+  if (needsCypressCT) {
+    npmScriptsDescriptions += `
+### Run Headed Component Tests with [Cypress Component Testing](https://on.cypress.io/component)
+
+\`\`\`sh
+${getCommand(packageManager, 'test:unit')} # or \`${getCommand(
+      packageManager,
+      'test:unit:ci'
+    )}\` for headless testing
+\`\`\`
+`
+  }
+
+  if (needsCypress) {
+    npmScriptsDescriptions += `
+### Run End-to-End Tests with [Cypress](https://www.cypress.io/)
+
+\`\`\`sh
+${getCommand(packageManager, 'build')}
+${getCommand(packageManager, 'test:e2e')} # or \`${getCommand(
+      packageManager,
+      'test:e2e:ci'
+    )}\` for headless testing
+\`\`\`
+`
+  }
+
+  if (needsEslint) {
+    npmScriptsDescriptions += `
+### Lint with [ESLint](https://eslint.org/)
+
+\`\`\`sh
+${getCommand(packageManager, 'lint')}
+\`\`\`
+`
+  }
+
+  readme += npmScriptsDescriptions
+
+  return readme
+}
similarity index 100%
rename from utils/getCommand.js
rename to utils/getCommand.ts
diff --git a/utils/renderEslint.ts b/utils/renderEslint.ts
new file mode 100644 (file)
index 0000000..db5c15e
--- /dev/null
@@ -0,0 +1,105 @@
+import * as fs from 'fs'
+import * as path from 'path'
+
+import type { ESLint, Linter } from 'eslint'
+
+import { devDependencies as allEslintDeps } from '../template/eslint/package.json'
+import deepMerge from './deepMerge'
+import sortDependencies from './sortDependencies'
+
+const dependencies = {}
+function addEslintDependency(name) {
+  dependencies[name] = allEslintDeps[name]
+}
+
+addEslintDependency('eslint')
+addEslintDependency('eslint-plugin-vue')
+
+interface ESLintConfig extends Linter.Config {
+  extends: string[]
+}
+const config: ESLintConfig = {
+  root: true,
+  extends: ['plugin:vue/essential']
+}
+
+function configureEslint({ language, styleGuide, needsPrettier, needsCypress, needsCypressCT }) {
+  switch (`${styleGuide}-${language}`) {
+    case 'default-javascript':
+      config.extends.push('eslint:recommended')
+      break
+    case 'default-typescript':
+      addEslintDependency('@vue/eslint-config-typescript')
+      config.extends.push('eslint:recommended')
+      config.extends.push('@vue/eslint-config-typescript/recommended')
+      break
+    // TODO: airbnb and standard
+  }
+
+  if (needsPrettier) {
+    addEslintDependency('prettier')
+    addEslintDependency('@vue/eslint-config-prettier')
+    config.extends.push('@vue/eslint-config-prettier')
+  }
+
+  if (needsCypress) {
+    const cypressOverrides = [
+      {
+        files: needsCypressCT
+          ? ['**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}', 'cypress/e2e/**.{cy,spec}.{js,ts,jsx,tsx}']
+          : ['cypress/e2e/**.{cy,spec}.{js,ts,jsx,tsx}'],
+        extends: ['plugin:cypress/recommended']
+      }
+    ]
+
+    addEslintDependency('eslint-plugin-cypress')
+    config.overrides = cypressOverrides
+  }
+
+  // generate the configuration file
+  let configuration = '/* eslint-env node */\n'
+  if (styleGuide !== 'default' || language !== 'javascript' || needsPrettier) {
+    addEslintDependency('@rushstack/eslint-patch')
+    configuration += `require("@rushstack/eslint-patch/modern-module-resolution");\n\n`
+  }
+  configuration += `module.exports = ${JSON.stringify(config, undefined, 2)}\n`
+
+  return {
+    dependencies,
+    configuration
+  }
+}
+
+export default function renderEslint(
+  rootDir,
+  { needsTypeScript, needsCypress, needsCypressCT, needsPrettier }
+) {
+  const { dependencies, configuration } = configureEslint({
+    language: needsTypeScript ? 'typescript' : 'javascript',
+    // we currently don't support other style guides
+    styleGuide: 'default',
+    needsPrettier,
+    needsCypress,
+    needsCypressCT
+  })
+
+  // update package.json
+  const packageJsonPath = path.resolve(rootDir, 'package.json')
+  const existingPkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
+  const pkg = sortDependencies(
+    deepMerge(existingPkg, {
+      scripts: {
+        // Note that we reuse .gitignore here to avoid duplicating the configuration
+        lint: needsTypeScript
+          ? 'eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore'
+          : 'eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore'
+      },
+      devDependencies: dependencies
+    })
+  )
+  fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n')
+
+  // write to .eslintrc.cjs
+  const eslintrcPath = path.resolve(rootDir, '.eslintrc.cjs')
+  fs.writeFileSync(eslintrcPath, configuration)
+}
similarity index 77%
rename from utils/renderTemplate.js
rename to utils/renderTemplate.ts
index 3423f3a1954fbb64a03eab4d4f7c9c67fdb1c6b8..971471434f351d030fd938dbfcd70c7d69a059f6 100644 (file)
@@ -1,8 +1,8 @@
-import fs from 'fs'
-import path from 'path'
+import * as fs from 'fs'
+import * as path from 'path'
 
-import deepMerge from './deepMerge.js'
-import sortDependencies from './sortDependencies.js'
+import deepMerge from './deepMerge'
+import sortDependencies from './sortDependencies'
 
 /**
  * Renders a template folder/file to the file system,
@@ -17,6 +17,11 @@ function renderTemplate(src, dest) {
   const stats = fs.statSync(src)
 
   if (stats.isDirectory()) {
+    // skip node_module
+    if (path.basename(src) === 'node_modules') {
+      return
+    }
+
     // if it's a directory, render its subdirectories and files recursively
     fs.mkdirSync(dest, { recursive: true })
     for (const file of fs.readdirSync(src)) {
@@ -29,8 +34,8 @@ function renderTemplate(src, dest) {
 
   if (filename === 'package.json' && fs.existsSync(dest)) {
     // merge instead of overwriting
-    const existing = JSON.parse(fs.readFileSync(dest))
-    const newPackage = JSON.parse(fs.readFileSync(src))
+    const existing = JSON.parse(fs.readFileSync(dest, 'utf8'))
+    const newPackage = JSON.parse(fs.readFileSync(src, 'utf8'))
     const pkg = sortDependencies(deepMerge(existing, newPackage))
     fs.writeFileSync(dest, JSON.stringify(pkg, null, 2) + '\n')
     return