]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
Merge remote-tracking branch 'upstream/main'
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Tue, 17 Sep 2024 02:32:28 +0000 (10:32 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Tue, 17 Sep 2024 02:33:35 +0000 (10:33 +0800)
77 files changed:
1  2 
.github/workflows/size-data.yml
eslint.config.js
package.json
packages-private/sfc-playground/index.html
packages-private/sfc-playground/src/App.vue
packages-private/sfc-playground/src/Header.vue
packages-private/sfc-playground/src/vue-vapor-dev-proxy.ts
packages-private/sfc-playground/src/welcome.vue
packages-private/sfc-playground/vite.config.ts
packages-private/template-explorer/package.json
packages-private/template-explorer/src/index.ts
packages-private/template-explorer/src/options.ts
packages/compiler-core/package.json
packages/compiler-core/src/ast.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/index.ts
packages/compiler-core/src/options.ts
packages/compiler-core/src/transforms/transformExpression.ts
packages/compiler-core/src/utils.ts
packages/compiler-dom/package.json
packages/compiler-dom/src/transforms/vOn.ts
packages/compiler-sfc/package.json
packages/compiler-sfc/src/compileScript.ts
packages/compiler-sfc/src/parse.ts
packages/compiler-sfc/src/script/context.ts
packages/compiler-ssr/package.json
packages/compiler-vapor/__tests__/abbreviation.spec.ts
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/_utils.ts
packages/compiler-vapor/__tests__/transforms/transformSlotOutlet.spec.ts
packages/compiler-vapor/src/generators/directive.ts
packages/compiler-vapor/src/generators/event.ts
packages/compiler-vapor/src/transforms/vBind.ts
packages/compiler-vapor/src/transforms/vModel.ts
packages/reactivity/package.json
packages/reactivity/src/effectScope.ts
packages/runtime-core/package.json
packages/runtime-core/src/apiCreateApp.ts
packages/runtime-core/src/compat/renderFn.ts
packages/runtime-core/src/compat/renderHelpers.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentPublicInstance.ts
packages/runtime-core/src/componentRenderUtils.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/renderer.ts
packages/runtime-core/src/warning.ts
packages/runtime-dom/package.json
packages/runtime-vapor/__tests__/_utils.ts
packages/runtime-vapor/__tests__/if.spec.ts
packages/runtime-vapor/src/apiWatch.ts
packages/runtime-vapor/src/directives.ts
packages/runtime-vapor/src/dom/templateRef.ts
packages/runtime-vapor/src/errorHandling.ts
packages/runtime-vapor/src/index.ts
packages/runtime-vapor/src/renderEffect.ts
packages/runtime-vapor/src/scheduler.ts
packages/server-renderer/package.json
packages/shared/package.json
packages/shared/src/general.ts
packages/vue-compat/package.json
packages/vue-vapor/__tests__/e2e/e2eUtils.ts
packages/vue/package.json
playground/src/main.ts
playground/tsconfig.json
pnpm-lock.yaml
pnpm-workspace.yaml
rollup.config.js
scripts/release.js
scripts/usage-size.js
scripts/utils.js
tsconfig.build.json
tsconfig.json
vitest.config.ts
vitest.e2e.config.ts

index e76a3538184236e70eae7e1b19b6a35d2857615f,7f8bf7b08caa7010e899a2fb79b4df5def930710..b7d8909697233916832469756d6e6c11f349bffb
@@@ -37,23 -38,6 +38,17 @@@ jobs
  
        - run: pnpm run size
  
-       - name: Upload Size Data
-         uses: actions/upload-artifact@v4
-         with:
-           name: size-data
-           path: temp/size
 +      - name: Download Previous Size Data
 +        uses: dawidd6/action-download-artifact@v2
 +        if: ${{ github.event_name == 'push' }}
 +        with:
 +          branch: main
 +          workflow: size-data.yml
 +          event: push
 +          name: size-data
 +          path: temp/size-prev
 +          if_no_artifact_found: warn
 +
        - name: Save PR number & base branch
          if: ${{github.event_name == 'pull_request'}}
          run: |
index 2717af4bb4d4127e73cb3c888e4be1a6185d8e3f,2e752e19107d607ecc2a4daf3fc9530eb19f03de..87abcf13ba6d0b1f85839d548a44603b359b630c
@@@ -120,9 -124,8 +124,9 @@@ export default tseslint.config
    // Private package, browser only + no syntax restrictions
    {
      files: [
-       'packages/template-explorer/**',
-       'packages/sfc-playground/**',
+       'packages-private/template-explorer/**',
+       'packages-private/sfc-playground/**',
 +      'playground/**',
      ],
      rules: {
        'no-restricted-globals': ['error', ...NodeGlobals],
diff --cc package.json
index 7594f7e6bdde1dc74e2dd2e2661fb3e6eeaf5104,9f5737565d0a0f4b0439d769fc7f7bd638fdcc8d..e745dbd580d079f508ce11810c0e326f19fc25c1
@@@ -1,45 -1,44 +1,45 @@@
  {
    "private": true,
-   "version": "3.5.0-beta.1",
-   "packageManager": "pnpm@9.6.0",
+   "version": "3.5.6",
+   "packageManager": "pnpm@9.10.0",
    "type": "module",
    "scripts": {
 -    "dev": "node scripts/dev.js",
 +    "dev": "node scripts/dev.js vue vue-vapor",
      "build": "node scripts/build.js",
-     "build-dts": "tsc -p tsconfig.build-browser.json && tsc -p tsconfig.build-node.json && rollup -c rollup.dts.config.js",
-     "clean": "rimraf packages/*/dist temp .eslintcache",
-     "size": "run-s \"size-*\" && tsx scripts/usage-size.ts",
+     "build-dts": "tsc -p tsconfig.build.json --noCheck && rollup -c rollup.dts.config.js",
+     "clean": "rimraf --glob packages/*/dist temp .eslintcache",
+     "size": "run-s \"size-*\" && node scripts/usage-size.js",
 -    "size-global": "node scripts/build.js vue runtime-dom -f global -p --size",
 -    "size-esm-runtime": "node scripts/build.js vue -f esm-bundler-runtime",
 -    "size-esm": "node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler",
 +    "size-global": "node scripts/build.js vue vue-vapor runtime-dom runtime-vapor compiler-dom compiler-vapor -f global -p --size",
 +    "size-esm-runtime": "node scripts/build.js vue vue-vapor -f esm-bundler-runtime",
 +    "size-esm": "node scripts/build.js runtime-shared runtime-dom runtime-vapor runtime-core reactivity shared -f esm-bundler",
      "check": "tsc --incremental --noEmit",
      "lint": "eslint --cache .",
      "format": "prettier --write --cache .",
      "format-check": "prettier --check --cache .",
      "test": "vitest",
-     "test-unit": "vitest -c vitest.unit.config.ts",
-     "test-e2e": "node scripts/build.js vue vue-vapor -f global -d && vitest -c vitest.e2e.config.ts",
+     "test-unit": "vitest --project unit",
 -    "test-e2e": "node scripts/build.js vue -f global -d && vitest --project e2e",
++    "test-e2e": "node scripts/build.js vue vue-vapor -f global -d && vitest --project e2e",
      "test-dts": "run-s build-dts test-dts-only",
-     "test-dts-only": "tsc -p packages/dts-built-test/tsconfig.json && tsc -p ./packages/dts-test/tsconfig.test.json",
-     "test-coverage": "vitest -c vitest.unit.config.ts --coverage",
+     "test-dts-only": "tsc -p packages-private/dts-built-test/tsconfig.json && tsc -p ./packages-private/dts-test/tsconfig.test.json",
+     "test-coverage": "vitest run --project unit --coverage",
      "test-bench": "vitest bench",
      "release": "node scripts/release.js",
      "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
      "dev-esm": "node scripts/dev.js -if esm-bundler-runtime",
 +    "dev-prepare-cjs": "node scripts/prepare-cjs.js || npm run build-all-cjs",
      "dev-compiler": "run-p \"dev template-explorer\" serve",
 -    "dev-sfc": "run-s dev-sfc-prepare dev-sfc-run",
 -    "dev-sfc-prepare": "node scripts/pre-dev-sfc.js || npm run build-all-cjs",
 +    "dev-sfc": "run-s dev-prepare-cjs dev-sfc-run",
-     "dev-sfc-serve": "vite packages/sfc-playground --host",
+     "dev-sfc-serve": "vite packages-private/sfc-playground --host",
      "dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if esm-bundler-runtime\" \"dev vue -ipf esm-browser-runtime\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve",
 +    "dev-vapor": "pnpm -C playground run dev",
      "serve": "serve",
-     "open": "open http://localhost:3000/packages/template-explorer/local.html",
+     "open": "open http://localhost:3000/packages-private/template-explorer/local.html",
      "build-sfc-playground": "run-s build-all-cjs build-runtime-esm build-browser-esm build-ssr-esm build-sfc-playground-self",
      "build-all-cjs": "node scripts/build.js vue runtime compiler reactivity shared -af cjs",
      "build-runtime-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler-runtime && node scripts/build.js vue -f esm-browser-runtime",
      "build-browser-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler && node scripts/build.js vue -f esm-browser",
 -    "build-ssr-esm": "node scripts/build.js compiler-sfc server-renderer -f esm-browser",
 +    "build-ssr-esm": "node scripts/build.js compiler-sfc server-renderer vue-vapor -f esm-browser",
-     "build-sfc-playground-self": "cd packages/sfc-playground && npm run build",
+     "build-sfc-playground-self": "cd packages-private/sfc-playground && npm run build",
      "preinstall": "npx only-allow pnpm",
      "postinstall": "simple-git-hooks"
    },
      "@rollup/plugin-json": "^6.1.0",
      "@rollup/plugin-node-resolve": "^15.2.3",
      "@rollup/plugin-replace": "5.0.4",
-     "@swc/core": "^1.7.6",
+     "@swc/core": "^1.7.26",
      "@types/hash-sum": "^1.0.2",
-     "@types/node": "^20.14.14",
+     "@types/node": "^20.16.5",
      "@types/semver": "^7.5.8",
      "@types/serve-handler": "^6.1.4",
-     "@vitest/coverage-istanbul": "^1.6.0",
-     "@vitest/ui": "^1.6.0",
+     "@vitest/coverage-v8": "^2.1.1",
++    "@vitest/ui": "^2.1.1",
      "@vue/consolidate": "1.0.0",
      "conventional-changelog-cli": "^5.0.0",
      "enquirer": "^2.4.1",
index 9447bff4575913fd2c1aef2aba918379c1850356,9ae0ecd9236ec9291b1469264f5a72b5ebd01401..e9e68c8688b0102fe472cedda1b3abcbfff13d75
@@@ -23,13 -13,14 +23,19 @@@ window.addEventListener('resize', setVH
  setVH()
  
  const useSSRMode = ref(false)
 +const useVaporMode = ref(true)
  
 -const { productionMode, vueVersion, importMap } = useVueImportMap({
+ const AUTO_SAVE_STORAGE_KEY = 'vue-sfc-playground-auto-save'
+ const initAutoSave: boolean = JSON.parse(
+   localStorage.getItem(AUTO_SAVE_STORAGE_KEY) ?? 'true',
+ )
+ const autoSave = ref(initAutoSave)
 +const {
 +  vueVersion,
 +  productionMode,
 +  importMap: vueImportMap,
 +} = useVueImportMap({
    runtimeDev: import.meta.env.PROD
      ? `${location.origin}/vue.runtime.esm-browser.js`
      : `${location.origin}/src/vue-dev-proxy`,
@@@ -159,10 -95,11 +165,15 @@@ function toggleSSR() 
    useSSRMode.value = !useSSRMode.value
  }
  
 +function toggleVapor() {
 +  useVaporMode.value = !useVaporMode.value
 +}
 +
+ function toggleAutoSave() {
+   autoSave.value = !autoSave.value
+   localStorage.setItem(AUTO_SAVE_STORAGE_KEY, String(autoSave.value))
+ }
  function reloadPage() {
    replRef.value?.reload()
  }
@@@ -185,11 -122,11 +196,13 @@@ onMounted(() => 
      :store="store"
      :prod="productionMode"
      :ssr="useSSRMode"
 +    :vapor="useVaporMode"
+     :autoSave="autoSave"
      @toggle-theme="toggleTheme"
      @toggle-prod="toggleProdMode"
      @toggle-ssr="toggleSSR"
+     @toggle-autosave="toggleAutoSave"
 +    @toggle-vapor="toggleVapor"
      @reload-page="reloadPage"
    />
    <Repl
index 3c7cb6e58d12a0402b6e55f99953aec0a8361529,2778724b0abba05aa702437905b8d4a7e453d40d..631d5df460200d997fa1aab47b6c8280c96550e9
@@@ -14,13 -14,13 +14,15 @@@ const props = defineProps<
    store: ReplStore
    prod: boolean
    ssr: boolean
 +  vapor: boolean
+   autoSave: boolean
  }>()
  const emit = defineEmits([
    'toggle-theme',
    'toggle-ssr',
    'toggle-prod',
 +  'toggle-vapor',
+   'toggle-autosave',
    'reload-page',
  ])
  
@@@ -209,8 -209,8 +219,9 @@@ h1 img 
  }
  
  .toggle-prod span,
- .toggle-ssr span {
 +.toggle-vapor span,
+ .toggle-ssr span,
+ .toggle-autosave span {
    font-size: 12px;
    border-radius: 4px;
    padding: 4px 6px;
index cafc65fee29989c6cb6260a7b485147707551885,0000000000000000000000000000000000000000..cafc65fee29989c6cb6260a7b485147707551885
mode 100644,000000..100644
--- /dev/null
index 377e17e9d4019666e3135ee39cc02e3ae5af99b4,0000000000000000000000000000000000000000..377e17e9d4019666e3135ee39cc02e3ae5af99b4
mode 100644,000000..100644
--- /dev/null
index a48413c6101d0a4a6c8f519f357b88b1a89a82c7,2e77f1970a7f3ac891ba7dcd958ecc27f9f645bd..62bac8cc6a9a417c0ff1709c9451d03dd82543e3
@@@ -49,12 -49,11 +49,12 @@@ function copyVuePlugin(): Plugin 
          })
        }
  
-       copyFile(`../vue/dist/vue.esm-browser.js`)
-       copyFile(`../vue/dist/vue.esm-browser.prod.js`)
-       copyFile(`../vue/dist/vue.runtime.esm-browser.js`)
-       copyFile(`../vue/dist/vue.runtime.esm-browser.prod.js`)
-       copyFile(`../server-renderer/dist/server-renderer.esm-browser.js`)
-       copyFile(`../vue-vapor/dist/vue-vapor.esm-browser.js`)
+       copyFile(`vue/dist/vue.esm-browser.js`)
+       copyFile(`vue/dist/vue.esm-browser.prod.js`)
+       copyFile(`vue/dist/vue.runtime.esm-browser.js`)
+       copyFile(`vue/dist/vue.runtime.esm-browser.prod.js`)
+       copyFile(`server-renderer/dist/server-renderer.esm-browser.js`)
++      copyFile(`vue-vapor/dist/vue-vapor.esm-browser.js`)
      },
    }
  }
index c082129db17ec10a824c055a3884e16705783eb1,a5ad38c1ad8d4fe8ecfa53b7615757b38b145ca3..df6cfe10f36f3430364d1063ee1abbda7d6dc045
@@@ -11,8 -11,7 +11,8 @@@
      "enableNonBrowserBranches": true
    },
    "dependencies": {
-     "monaco-editor": "^0.50.0",
-     "source-map-js": "^1.2.0"
 +    "@vue/compiler-vapor": "workspace:^",
+     "monaco-editor": "^0.51.0",
+     "source-map-js": "^1.2.1"
    }
  }
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 63e7650dce3d9ba609a19f132967006bb74aca9f,ec2d4685314c4648757611e775d6fc13ffd58108..93425f358ee8fa3b79b8d7fe38d25b7f664ce7e6
@@@ -44,8 -44,7 +44,8 @@@ import { parseExpression } from '@babel
  import { IS_REF, UNREF } from '../runtimeHelpers'
  import { BindingTypes } from '../options'
  
 -const isLiteralWhitelisted = /*@__PURE__*/ makeMap('true,false,null,this')
 +export const isLiteralWhitelisted: (key: string) => boolean =
-   /*#__PURE__*/ makeMap('true,false,null,this')
++  /*@__PURE__*/ makeMap('true,false,null,this')
  
  export const transformExpression: NodeTransform = (node, context) => {
    if (node.type === NodeTypes.INTERPOLATION) {
index 99f8d3ecfceb0359852c59c220e8d49808af917a,b49d70bb2fba1d207e9ef76ab5d35cefcaec91aa..b90a7018c8b192ffcd47ea6d898818f4c899b3d2
@@@ -154,15 -159,19 +159,19 @@@ export const isMemberExpressionBrowser 
  }
  
  export const isMemberExpressionNode: (
-   path: string,
+   exp: ExpressionNode,
 -  context: TransformContext,
 +  context: Pick<TransformContext, 'expressionPlugins'>,
  ) => boolean = __BROWSER__
    ? (NOOP as any)
-   : (path, context) => {
+   : (exp, context) => {
        try {
-         let ret: Expression = parseExpression(path, {
-           plugins: context.expressionPlugins,
-         })
+         let ret: Node =
+           exp.ast ||
+           parseExpression(getExpSource(exp), {
+             plugins: context.expressionPlugins
+               ? [...context.expressionPlugins, 'typescript']
+               : ['typescript'],
+           })
          ret = unwrapTSNode(ret) as Expression
          return (
            ret.type === 'MemberExpression' ||
      }
  
  export const isMemberExpression: (
-   path: string,
+   exp: ExpressionNode,
 -  context: TransformContext,
 +  context: Pick<TransformContext, 'expressionPlugins'>,
  ) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
  
 -  context: TransformContext,
+ const fnExpRE =
+   /^\s*(async\s*)?(\([^)]*?\)|[\w$_]+)\s*(:[^=]+)?=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/
+ export const isFnExpressionBrowser: (exp: ExpressionNode) => boolean = exp =>
+   fnExpRE.test(getExpSource(exp))
+ export const isFnExpressionNode: (
+   exp: ExpressionNode,
 -  context: TransformContext,
++  context: Pick<TransformContext, 'expressionPlugins'>,
+ ) => boolean = __BROWSER__
+   ? (NOOP as any)
+   : (exp, context) => {
+       try {
+         let ret: Node =
+           exp.ast ||
+           parseExpression(getExpSource(exp), {
+             plugins: context.expressionPlugins
+               ? [...context.expressionPlugins, 'typescript']
+               : ['typescript'],
+           })
+         // parser may parse the exp as statements when it contains semicolons
+         if (ret.type === 'Program') {
+           ret = ret.body[0]
+           if (ret.type === 'ExpressionStatement') {
+             ret = ret.expression
+           }
+         }
+         ret = unwrapTSNode(ret) as Expression
+         return (
+           ret.type === 'FunctionExpression' ||
+           ret.type === 'ArrowFunctionExpression'
+         )
+       } catch (e) {
+         return false
+       }
+     }
+ export const isFnExpression: (
+   exp: ExpressionNode,
++  context: Pick<TransformContext, 'expressionPlugins'>,
+ ) => boolean = __BROWSER__ ? isFnExpressionBrowser : isFnExpressionNode
  export function advancePositionWithClone(
    pos: Position,
    source: string,
Simple merge
index 1eff0a3894f36debdb96b54131f7a0146bac9e9e,1bb5763188bd0417c1cb17ed308f7a6b86c97fb8..723229cf34b42c6aeda6e34cc7f8c3690fa3c351
@@@ -14,10 -15,10 +15,10 @@@ import 
    isStaticExp,
  } from '@vue/compiler-core'
  import { V_ON_WITH_KEYS, V_ON_WITH_MODIFIERS } from '../runtimeHelpers'
 -import { capitalize, makeMap } from '@vue/shared'
 +import { capitalize, isString, makeMap } from '@vue/shared'
  
- const isEventOptionModifier = /*#__PURE__*/ makeMap(`passive,once,capture`)
- const isNonKeyModifier = /*#__PURE__*/ makeMap(
+ const isEventOptionModifier = /*@__PURE__*/ makeMap(`passive,once,capture`)
+ const isNonKeyModifier = /*@__PURE__*/ makeMap(
    // event propagation management
    `stop,prevent,self,` +
      // system modifiers + exact
      `middle`,
  )
  // left & right could be mouse or key modifiers based on event type
- const maybeKeyModifier = /*#__PURE__*/ makeMap('left,right')
- const isKeyboardEvent = /*#__PURE__*/ makeMap(
-   `onkeyup,onkeydown,onkeypress`,
-   true,
- )
+ const maybeKeyModifier = /*@__PURE__*/ makeMap('left,right')
+ const isKeyboardEvent = /*@__PURE__*/ makeMap(`onkeyup,onkeydown,onkeypress`)
  
 -const resolveModifiers = (
 -  key: ExpressionNode,
 +export const resolveModifiers = (
 +  key: ExpressionNode | string,
-   modifiers: string[],
+   modifiers: SimpleExpressionNode[],
 -  context: TransformContext,
 +  context: TransformContext | null,
    loc: SourceLocation,
 -) => {
 +): {
 +  keyModifiers: string[]
 +  nonKeyModifiers: string[]
 +  eventOptionModifiers: string[]
 +} => {
    const keyModifiers = []
    const nonKeyModifiers = []
    const eventOptionModifiers = []
        // e.g. .passive & .capture
        eventOptionModifiers.push(modifier)
      } else {
 +      const keyString = isString(key)
 +        ? key
 +        : isStaticExp(key)
 +          ? key.content
 +          : null
 +
        // runtimeModifiers: modifiers that needs runtime guards
        if (maybeKeyModifier(modifier)) {
 -        if (isStaticExp(key)) {
 -          if (
 -            isKeyboardEvent((key as SimpleExpressionNode).content.toLowerCase())
 -          ) {
 +        if (keyString) {
-           if (isKeyboardEvent(keyString)) {
++          if (isKeyboardEvent(keyString.toLowerCase())) {
              keyModifiers.push(modifier)
            } else {
              nonKeyModifiers.push(modifier)
Simple merge
index 31ce0087106ae134154ee6b685e7169f29a6f58c,fee05beed96eed34fb48b2cb61e93b2d1c4ba6bf..2bbc0e549fbd39d2d8e5b0ffb29329508e0c1bd9
@@@ -988,9 -979,8 +988,9 @@@ export function compileScript
        (definedOptions ? `\n  ...${definedOptions},` : '')
      ctx.s.prependLeft(
        startOffset,
-       `\n${genDefaultAs} /*#__PURE__*/${ctx.helper(
+       `\n${genDefaultAs} /*@__PURE__*/${ctx.helper(
          `defineComponent`,
 +        vapor,
        )}({${def}${runtimeOptions}\n  ${
          hasAwait ? `async ` : ``
        }setup(${args}) {\n${exposeCall}`,
Simple merge
Simple merge
index 2b52bd48ebf35f32b40aac1933d928ee6752c50c,0000000000000000000000000000000000000000..6159c6ca5fd15fb707c5f7cf1dff63c70088ed52
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,44 @@@
- const parser = new DOMParser()
 +/**
 + * @vitest-environment jsdom
 + */
 +
- function parseHTML(html: string) {
++const parser: DOMParser = new DOMParser()
 +
- function checkAbbr(template: string, abbrevation: string, expected: string) {
++function parseHTML(html: string): string {
 +  return parser.parseFromString(html, 'text/html').body.innerHTML
 +}
 +
++function checkAbbr(
++  template: string,
++  abbrevation: string,
++  expected: string,
++): void {
 +  // TODO do some optimzations to make sure template === abbrevation
 +  expect(parseHTML(abbrevation)).toBe(expected)
 +}
 +
 +test('template abbreviation', () => {
 +  checkAbbr('<div>hello</div>', '<div>hello', '<div>hello</div>')
 +  checkAbbr(
 +    '<div><div>hello</div></div>',
 +    '<div><div>hello',
 +    '<div><div>hello</div></div>',
 +  )
 +  checkAbbr(
 +    '<div><span>foo</span><span/></div>',
 +    '<div><span>foo</span><span>',
 +    '<div><span>foo</span><span></span></div>',
 +  )
 +  checkAbbr(
 +    '<div><hr/><div/></div>',
 +    '<div><hr><div>',
 +    '<div><hr><div></div></div>',
 +  )
 +  checkAbbr(
 +    '<div><div/><hr/></div>',
 +    '<div><div></div><hr>',
 +    '<div><div></div><hr></div>',
 +  )
 +
 +  checkAbbr('<span/>hello', '<span></span>hello', '<span></span>hello')
 +})
index 0bd8457636287c26ffcecc4f27c12bbb4308cef0,0000000000000000000000000000000000000000..2cbc5a1c9aef4dbf99a77cf25c824144ee2d613b
mode 100644,000000..100644
--- /dev/null
@@@ -1,348 -1,0 +1,352 @@@
-   _delegate(n0, "click", () => _ctx.a)
-   _delegate(n0, "click", () => _ctx.b)
 +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 +
 +exports[`compiler: element transform > component > do not resolve component from non-script-setup bindings 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Example = _resolveComponent("Example")
 +  const n0 = _createComponent(_component_Example, null, null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > generate multi root component 1`] = `
 +"import { createComponent as _createComponent, template as _template } from 'vue/vapor';
 +const t0 = _template("123")
 +
 +export function render(_ctx) {
 +  const n1 = t0()
 +  const n0 = _createComponent(_ctx.Comp)
 +  return [n0, n1]
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > generate single root component 1`] = `
 +"import { createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const n0 = _createComponent(_ctx.Comp, null, null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > import + resolve component 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, null, null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > resolve component from setup bindings (inline const) 1`] = `
 +"(() => {
 +  const n0 = _createComponent(Example, null, null, true)
 +  return n0
 +})()"
 +`;
 +
 +exports[`compiler: element transform > component > resolve component from setup bindings (inline) 1`] = `
 +"(() => {
 +  const n0 = _createComponent(_unref(Example), null, null, true)
 +  return n0
 +})()"
 +`;
 +
 +exports[`compiler: element transform > component > resolve component from setup bindings 1`] = `
 +"import { createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const n0 = _createComponent(_ctx.Example, null, null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > resolve namespaced component from props bindings (inline) 1`] = `
 +"(() => {
 +  const n0 = _createComponent(Foo.Example, null, null, true)
 +  return n0
 +})()"
 +`;
 +
 +exports[`compiler: element transform > component > resolve namespaced component from props bindings (non-inline) 1`] = `
 +"import { createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const n0 = _createComponent(_ctx.Foo.Example, null, null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > resolve namespaced component from setup bindings (inline const) 1`] = `
 +"(() => {
 +  const n0 = _createComponent(Foo.Example, null, null, true)
 +  return n0
 +})()"
 +`;
 +
 +exports[`compiler: element transform > component > resolve namespaced component from setup bindings 1`] = `
 +"import { createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const n0 = _createComponent(_ctx.Foo.Example, null, null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > should wrap as function if v-on expression is inline statement 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    { onBar: () => $event => (_ctx.handleBar($event)) }
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > static props 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    {
 +      id: () => ("foo"), 
 +      class: () => ("bar")
 +    }
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > v-bind="obj" 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    () => (_ctx.obj)
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > v-bind="obj" after static prop 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    { id: () => ("foo") }, 
 +    () => (_ctx.obj)
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > v-bind="obj" before static prop 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    () => (_ctx.obj), 
 +    { id: () => ("foo") }
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > v-bind="obj" between static props 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    { id: () => ("foo") }, 
 +    () => (_ctx.obj), 
 +    { class: () => ("bar") }
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component > v-on="obj" 1`] = `
 +"import { resolveComponent as _resolveComponent, toHandlers as _toHandlers, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    () => (_toHandlers(_ctx.obj))
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component with dynamic event arguments 1`] = `
 +"import { toHandlerKey as _toHandlerKey } from 'vue';
 +import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    () => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar }), 
 +    () => ({ [_toHandlerKey(_ctx.baz)]: () => _ctx.qux })
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > component with dynamic prop arguments 1`] = `
 +"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
 +
 +export function render(_ctx) {
 +  const _component_Foo = _resolveComponent("Foo")
 +  const n0 = _createComponent(_component_Foo, [
 +    () => ({ [_ctx.foo-_ctx.bar]: _ctx.bar }), 
 +    () => ({ [_ctx.baz]: _ctx.qux })
 +  ], null, true)
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > empty template 1`] = `
 +"
 +export function render(_ctx) {
 +  return null
 +}"
 +`;
 +
 +exports[`compiler: element transform > invalid html nesting 1`] = `
 +"import { insert as _insert, template as _template } from 'vue/vapor';
 +const t0 = _template("<div>123</div>")
 +const t1 = _template("<p></p>")
 +const t2 = _template("<form></form>")
 +
 +export function render(_ctx) {
 +  const n1 = t1()
 +  const n0 = t0()
 +  const n3 = t2()
 +  const n2 = t2()
 +  _insert(n0, n1)
 +  _insert(n2, n3)
 +  return [n1, n3]
 +}"
 +`;
 +
 +exports[`compiler: element transform > props + children 1`] = `
 +"import { template as _template } from 'vue/vapor';
 +const t0 = _template("<div id=\\"foo\\"><span></span></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > props merging: class 1`] = `
 +"import { renderEffect as _renderEffect, setClass as _setClass, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => _setClass(n0, ["foo", { bar: _ctx.isBar }]))
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > props merging: event handlers 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
++  _delegate(n0, "click", () => _ctx.a, {
++    keys: ["foo"]
++  })
++  _delegate(n0, "click", () => _ctx.b, {
++    keys: ["bar"]
++  })
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > props merging: style 1`] = `
 +"import { renderEffect as _renderEffect, setStyle as _setStyle, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => _setStyle(n0, ["color: green", { color: 'red' }]))
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > static props 1`] = `
 +"import { template as _template } from 'vue/vapor';
 +const t0 = _template("<div id=\\"foo\\" class=\\"bar\\"></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > v-bind="obj" 1`] = `
 +"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => _setDynamicProps(n0, _ctx.obj))
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > v-bind="obj" after static prop 1`] = `
 +"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => _setDynamicProps(n0, { id: "foo" }, _ctx.obj))
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > v-bind="obj" before static prop 1`] = `
 +"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => _setDynamicProps(n0, _ctx.obj, { id: "foo" }))
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > v-bind="obj" between static props 1`] = `
 +"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => _setDynamicProps(n0, { id: "foo" }, _ctx.obj, { class: "bar" }))
 +  return n0
 +}"
 +`;
 +
 +exports[`compiler: element transform > v-on="obj" 1`] = `
 +"import { renderEffect as _renderEffect, setDynamicEvents as _setDynamicEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => _setDynamicEvents(n0, _ctx.obj))
 +  return n0
 +}"
 +`;
index 80304b4ba65232710fcb92d3004766b6ea47759f,0000000000000000000000000000000000000000..18612957b5dd6eebc563ad9f4a86c89c429a4d00
mode 100644,000000..100644
--- /dev/null
@@@ -1,500 -1,0 +1,501 @@@
-     modifiers: ["right"]
 +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 +
 +exports[`v-on > complex member expression w/ prefixIdentifiers: true 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => _ctx.a['b' + _ctx.c])
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > dynamic arg 1`] = `
 +"import { renderEffect as _renderEffect, on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => {
 +    _on(n0, _ctx.event, () => _ctx.handler, {
 +      effect: true
 +    })
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > dynamic arg with complex exp prefixing 1`] = `
 +"import { renderEffect as _renderEffect, on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => {
 +    _on(n0, _ctx.event(_ctx.foo), () => _ctx.handler, {
 +      effect: true
 +    })
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > dynamic arg with prefixing 1`] = `
 +"import { renderEffect as _renderEffect, on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => {
 +    _on(n0, _ctx.event, () => _ctx.handler, {
 +      effect: true
 +    })
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > event modifier 1`] = `
 +"import { delegate as _delegate, on as _on, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<a></a>")
 +const t1 = _template("<form></form>")
 +const t2 = _template("<div></div>")
 +const t3 = _template("<input>")
 +_delegateEvents("click", "contextmenu", "mouseup", "keyup")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  const n1 = t1()
 +  const n2 = t0()
 +  const n3 = t2()
 +  const n4 = t2()
 +  const n5 = t0()
 +  const n6 = t2()
 +  const n7 = t3()
 +  const n8 = t3()
 +  const n9 = t3()
 +  const n10 = t3()
 +  const n11 = t3()
 +  const n12 = t3()
 +  const n13 = t3()
 +  const n14 = t3()
 +  const n15 = t3()
 +  const n16 = t3()
 +  const n17 = t3()
 +  const n18 = t3()
 +  const n19 = t3()
 +  const n20 = t3()
 +  const n21 = t3()
 +  _delegate(n0, "click", () => _ctx.handleEvent, {
 +    modifiers: ["stop"]
 +  })
 +  _on(n1, "submit", () => _ctx.handleEvent, {
 +    modifiers: ["prevent"]
 +  })
 +  _delegate(n2, "click", () => _ctx.handleEvent, {
 +    modifiers: ["stop", "prevent"]
 +  })
 +  _delegate(n3, "click", () => _ctx.handleEvent, {
 +    modifiers: ["self"]
 +  })
 +  _on(n4, "click", () => _ctx.handleEvent, {
 +    capture: true
 +  })
 +  _on(n5, "click", () => _ctx.handleEvent, {
 +    once: true
 +  })
 +  _on(n6, "scroll", () => _ctx.handleEvent, {
 +    passive: true
 +  })
 +  _delegate(n7, "contextmenu", () => _ctx.handleEvent, {
 +    modifiers: ["right"]
 +  })
 +  _delegate(n8, "click", () => _ctx.handleEvent, {
 +    modifiers: ["left"]
 +  })
 +  _delegate(n9, "mouseup", () => _ctx.handleEvent, {
 +    modifiers: ["middle"]
 +  })
 +  _delegate(n10, "contextmenu", () => _ctx.handleEvent, {
++    modifiers: ["right"], 
++    keys: ["enter"]
 +  })
 +  _delegate(n11, "keyup", () => _ctx.handleEvent, {
 +    keys: ["enter"]
 +  })
 +  _delegate(n12, "keyup", () => _ctx.handleEvent, {
 +    keys: ["tab"]
 +  })
 +  _delegate(n13, "keyup", () => _ctx.handleEvent, {
 +    keys: ["delete"]
 +  })
 +  _delegate(n14, "keyup", () => _ctx.handleEvent, {
 +    keys: ["esc"]
 +  })
 +  _delegate(n15, "keyup", () => _ctx.handleEvent, {
 +    keys: ["space"]
 +  })
 +  _delegate(n16, "keyup", () => _ctx.handleEvent, {
 +    keys: ["up"]
 +  })
 +  _delegate(n17, "keyup", () => _ctx.handleEvent, {
 +    keys: ["down"]
 +  })
 +  _delegate(n18, "keyup", () => _ctx.handleEvent, {
 +    keys: ["left"]
 +  })
 +  _delegate(n19, "keyup", () => _ctx.submit, {
 +    modifiers: ["middle"]
 +  })
 +  _delegate(n20, "keyup", () => _ctx.submit, {
 +    modifiers: ["middle", "self"]
 +  })
 +  _delegate(n21, "keyup", () => _ctx.handleEvent, {
 +    modifiers: ["self"], 
 +    keys: ["enter"]
 +  })
 +  return [n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21]
 +}"
 +`;
 +
 +exports[`v-on > function expression w/ prefixIdentifiers: true 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => e => _ctx.foo(e))
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > inline statement w/ prefixIdentifiers: true 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => $event => (_ctx.foo($event)))
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > multiple inline statements w/ prefixIdentifiers: true 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => $event => {_ctx.foo($event);_ctx.bar()})
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should NOT add a prefix to $event if the expression is a function expression 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => $event => {_ctx.i++;_ctx.foo($event)})
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should NOT wrap as function if expression is already function expression (with Typescript) 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => (e: any): any => _ctx.foo(e))
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should NOT wrap as function if expression is already function expression (with newlines) 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => 
 +      $event => {
 +        _ctx.foo($event)
 +      }
 +    )
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should NOT wrap as function if expression is already function expression 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => $event => _ctx.foo($event))
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should NOT wrap as function if expression is complex member expression 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => _ctx.a['b' + _ctx.c])
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should delegate event 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => _ctx.test)
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should handle multi-line statement 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => $event => {
 +_ctx.foo();
 +_ctx.bar()
 +})
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should handle multiple inline statement 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => $event => {_ctx.foo();_ctx.bar()})
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should not prefix member expression 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => _ctx.foo.bar)
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should not wrap keys guard if no key modifier is present 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("keyup")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "keyup", () => _ctx.test, {
 +    modifiers: ["exact"]
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should support multiple events and modifiers options w/ prefixIdentifiers: true 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click", "keyup")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => _ctx.test, {
 +    modifiers: ["stop"]
 +  })
 +  _delegate(n0, "keyup", () => _ctx.test, {
 +    keys: ["enter"]
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should support multiple modifiers and event options w/ prefixIdentifiers: true 1`] = `
 +"import { on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _on(n0, "click", () => _ctx.test, {
 +    modifiers: ["stop", "prevent"], 
 +    capture: true, 
 +    once: true
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should transform click.middle 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("mouseup")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "mouseup", () => _ctx.test, {
 +    modifiers: ["middle"]
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should transform click.middle 2`] = `
 +"import { renderEffect as _renderEffect, on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => {
 +    _on(n0, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), () => _ctx.test, {
 +      modifiers: ["middle"], 
 +      effect: true
 +    })
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should transform click.right 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("contextmenu")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "contextmenu", () => _ctx.test, {
 +    modifiers: ["right"]
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should transform click.right 2`] = `
 +"import { renderEffect as _renderEffect, on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => {
 +    _on(n0, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), () => _ctx.test, {
 +      modifiers: ["right"], 
 +      keys: ["right"], 
 +      effect: true
 +    })
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should wrap as function if expression is inline statement 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => $event => (_ctx.i++))
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should wrap both for dynamic key event w/ left/right modifiers 1`] = `
 +"import { renderEffect as _renderEffect, on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _renderEffect(() => {
 +    _on(n0, _ctx.e, () => _ctx.test, {
 +      modifiers: ["left"], 
 +      keys: ["left"], 
 +      effect: true
 +    })
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should wrap in unref if identifier is setup-maybe-ref w/ inline: true 1`] = `
 +"(() => {
 +  const n0 = t0()
 +  const n1 = t0()
 +  const n2 = t0()
 +  _delegate(n0, "click", () => $event => (x.value=_unref(y)))
 +  _delegate(n1, "click", () => $event => (x.value++))
 +  _delegate(n2, "click", () => $event => ({ x: x.value } = _unref(y)))
 +  return [n0, n1, n2]
 +})()"
 +`;
 +
 +exports[`v-on > should wrap keys guard for keyboard events or dynamic events 1`] = `
 +"import { on as _on, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _on(n0, "keydown", () => _ctx.test, {
 +    modifiers: ["stop", "ctrl"], 
 +    keys: ["a"], 
 +    capture: true
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > should wrap keys guard for static key event w/ left/right modifiers 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("keyup")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "keyup", () => _ctx.test, {
 +    keys: ["left"]
 +  })
 +  return n0
 +}"
 +`;
 +
 +exports[`v-on > simple expression 1`] = `
 +"import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
 +const t0 = _template("<div></div>")
 +_delegateEvents("click")
 +
 +export function render(_ctx) {
 +  const n0 = t0()
 +  _delegate(n0, "click", () => _ctx.handleClick)
 +  return n0
 +}"
 +`;
index 0ace066db77360b7a26475350f76059c1b87d0b6,0000000000000000000000000000000000000000..e66ae4e9f6599289d5d8b57b983b8d58e8948495
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,38 @@@
- import { type CompilerOptions, generate, parse, transform } from '../../src'
++import type { RootNode } from '@vue/compiler-dom'
++import {
++  type CompilerOptions,
++  type RootIRNode,
++  generate,
++  parse,
++  transform,
++} from '../../src'
 +
 +export function makeCompile(options: CompilerOptions = {}) {
-   return (template: string, overrideOptions: CompilerOptions = {}) => {
++  return (
++    template: string,
++    overrideOptions: CompilerOptions = {},
++  ): {
++    ast: RootNode
++    ir: RootIRNode
++    code: string
++    helpers: Set<string>
++    vaporHelpers: Set<string>
++  } => {
 +    const ast = parse(template, {
 +      prefixIdentifiers: true,
 +      ...options,
 +      ...overrideOptions,
 +    })
 +    const ir = transform(ast, {
 +      prefixIdentifiers: true,
 +      ...options,
 +      ...overrideOptions,
 +    })
 +    const { code, helpers, vaporHelpers } = generate(ir, {
 +      prefixIdentifiers: true,
 +      ...options,
 +      ...overrideOptions,
 +    })
 +    return { ast, ir, code, helpers, vaporHelpers }
 +  }
 +}
index 32b9a865d0b0824d83759ebef8df0eea4c0cdef3,0000000000000000000000000000000000000000..465fe19f234c3d753715ff93a4a3e7217248deab
mode 100644,000000..100644
--- /dev/null
@@@ -1,304 -1,0 +1,304 @@@
-     expect(ir.template[0]).toMatchObject('<div></div>')
 +import { ErrorCodes, NodeTypes } from '@vue/compiler-core'
 +import {
 +  IRNodeTypes,
 +  transformChildren,
 +  transformElement,
 +  transformSlotOutlet,
 +  transformText,
 +  transformVBind,
 +  transformVOn,
 +  transformVShow,
 +} from '../../src'
 +import { makeCompile } from './_utils'
 +
 +const compileWithSlotsOutlet = makeCompile({
 +  nodeTransforms: [
 +    transformText,
 +    transformSlotOutlet,
 +    transformElement,
 +    transformChildren,
 +  ],
 +  directiveTransforms: {
 +    bind: transformVBind,
 +    on: transformVOn,
 +    show: transformVShow,
 +  },
 +})
 +
 +describe('compiler: transform <slot> outlets', () => {
 +  test('default slot outlet', () => {
 +    const { ir, code, vaporHelpers } = compileWithSlotsOutlet(`<slot />`)
 +    expect(code).toMatchSnapshot()
 +    expect(vaporHelpers).toContain('createSlot')
 +    expect(ir.block.effect).toEqual([])
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: {
 +          type: NodeTypes.SIMPLE_EXPRESSION,
 +          content: 'default',
 +          isStatic: true,
 +        },
 +        props: [],
 +        fallback: undefined,
 +      },
 +    ])
 +  })
 +
 +  test('statically named slot outlet', () => {
 +    const { ir, code } = compileWithSlotsOutlet(`<slot name="foo" />`)
 +    expect(code).toMatchSnapshot()
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: {
 +          type: NodeTypes.SIMPLE_EXPRESSION,
 +          content: 'foo',
 +          isStatic: true,
 +        },
 +      },
 +    ])
 +  })
 +
 +  test('dynamically named slot outlet', () => {
 +    const { ir, code } = compileWithSlotsOutlet(`<slot :name="foo + bar" />`)
 +    expect(code).toMatchSnapshot()
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: {
 +          type: NodeTypes.SIMPLE_EXPRESSION,
 +          content: 'foo + bar',
 +          isStatic: false,
 +        },
 +      },
 +    ])
 +  })
 +
 +  test('dynamically named slot outlet with v-bind shorthand', () => {
 +    const { ir, code } = compileWithSlotsOutlet(`<slot :name />`)
 +    expect(code).toMatchSnapshot()
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: {
 +          type: NodeTypes.SIMPLE_EXPRESSION,
 +          content: 'name',
 +          isStatic: false,
 +        },
 +      },
 +    ])
 +  })
 +
 +  test('default slot outlet with props', () => {
 +    const { ir, code } = compileWithSlotsOutlet(
 +      `<slot foo="bar" :baz="qux" :foo-bar="foo-bar" />`,
 +    )
 +    expect(code).toMatchSnapshot()
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        name: { content: 'default' },
 +        props: [
 +          [
 +            { key: { content: 'foo' }, values: [{ content: 'bar' }] },
 +            { key: { content: 'baz' }, values: [{ content: 'qux' }] },
 +            { key: { content: 'fooBar' }, values: [{ content: 'foo-bar' }] },
 +          ],
 +        ],
 +      },
 +    ])
 +  })
 +
 +  test('statically named slot outlet with props', () => {
 +    const { ir, code } = compileWithSlotsOutlet(
 +      `<slot name="foo" foo="bar" :baz="qux" />`,
 +    )
 +    expect(code).toMatchSnapshot()
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        name: { content: 'foo' },
 +        props: [
 +          [
 +            { key: { content: 'foo' }, values: [{ content: 'bar' }] },
 +            { key: { content: 'baz' }, values: [{ content: 'qux' }] },
 +          ],
 +        ],
 +      },
 +    ])
 +  })
 +
 +  test('statically named slot outlet with v-bind="obj"', () => {
 +    const { ir, code } = compileWithSlotsOutlet(
 +      `<slot name="foo" foo="bar" v-bind="obj" :baz="qux" />`,
 +    )
 +    expect(code).toMatchSnapshot()
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        name: { content: 'foo' },
 +        props: [
 +          [{ key: { content: 'foo' }, values: [{ content: 'bar' }] }],
 +          { value: { content: 'obj', isStatic: false } },
 +          [{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
 +        ],
 +      },
 +    ])
 +  })
 +
 +  test('statically named slot outlet with v-on', () => {
 +    const { ir, code } = compileWithSlotsOutlet(
 +      `<slot @click="foo" v-on="bar" :baz="qux" />`,
 +    )
 +    expect(code).toMatchSnapshot()
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        props: [
 +          [{ key: { content: 'click' }, values: [{ content: 'foo' }] }],
 +          { value: { content: 'bar' }, handler: true },
 +          [{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
 +        ],
 +      },
 +    ])
 +  })
 +
 +  test('default slot outlet with fallback', () => {
 +    const { ir, code } = compileWithSlotsOutlet(`<slot><div/></slot>`)
 +    expect(code).toMatchSnapshot()
-     expect(ir.template[0]).toMatchObject('<div></div>')
++    expect(ir.template[0]).toBe('<div></div>')
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: { content: 'default' },
 +        fallback: {
 +          type: IRNodeTypes.BLOCK,
 +          dynamic: {
 +            children: [{ template: 0, id: 2 }],
 +          },
 +          returns: [2],
 +        },
 +      },
 +    ])
 +  })
 +
 +  test('named slot outlet with fallback', () => {
 +    const { ir, code } = compileWithSlotsOutlet(
 +      `<slot name="foo"><div/></slot>`,
 +    )
 +    expect(code).toMatchSnapshot()
-     expect(ir.template[0]).toMatchObject('<div></div>')
++    expect(ir.template[0]).toBe('<div></div>')
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: { content: 'foo' },
 +        fallback: {
 +          type: IRNodeTypes.BLOCK,
 +          dynamic: {
 +            children: [{ template: 0, id: 2 }],
 +          },
 +          returns: [2],
 +        },
 +      },
 +    ])
 +  })
 +
 +  test('default slot outlet with props & fallback', () => {
 +    const { ir, code } = compileWithSlotsOutlet(
 +      `<slot :foo="bar"><div/></slot>`,
 +    )
 +    expect(code).toMatchSnapshot()
-     expect(ir.template[0]).toMatchObject('<div></div>')
++    expect(ir.template[0]).toBe('<div></div>')
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: { content: 'default' },
 +        props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
 +        fallback: {
 +          type: IRNodeTypes.BLOCK,
 +          dynamic: {
 +            children: [{ template: 0, id: 2 }],
 +          },
 +          returns: [2],
 +        },
 +      },
 +    ])
 +  })
 +
 +  test('named slot outlet with props & fallback', () => {
 +    const { ir, code } = compileWithSlotsOutlet(
 +      `<slot name="foo" :foo="bar"><div/></slot>`,
 +    )
 +    expect(code).toMatchSnapshot()
++    expect(ir.template[0]).toBe('<div></div>')
 +    expect(ir.block.operation).toMatchObject([
 +      {
 +        type: IRNodeTypes.SLOT_OUTLET_NODE,
 +        id: 0,
 +        name: { content: 'foo' },
 +        props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
 +        fallback: {
 +          type: IRNodeTypes.BLOCK,
 +          dynamic: {
 +            children: [{ template: 0, id: 2 }],
 +          },
 +          returns: [2],
 +        },
 +      },
 +    ])
 +  })
 +
 +  test('error on unexpected custom directive on <slot>', () => {
 +    const onError = vi.fn()
 +    const source = `<slot v-foo />`
 +    const index = source.indexOf('v-foo')
 +    const { code } = compileWithSlotsOutlet(source, { onError })
 +    expect(code).toMatchSnapshot()
 +    expect(onError.mock.calls[0][0]).toMatchObject({
 +      code: ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
 +      loc: {
 +        start: {
 +          offset: index,
 +          line: 1,
 +          column: index + 1,
 +        },
 +        end: {
 +          offset: index + 5,
 +          line: 1,
 +          column: index + 6,
 +        },
 +      },
 +    })
 +  })
 +
 +  test('error on unexpected custom directive with v-show on <slot>', () => {
 +    const onError = vi.fn()
 +    const source = `<slot v-show="ok" />`
 +    const index = source.indexOf('v-show="ok"')
 +    const { code } = compileWithSlotsOutlet(source, { onError })
 +    expect(code).toMatchSnapshot()
 +    expect(onError.mock.calls[0][0]).toMatchObject({
 +      code: ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
 +      loc: {
 +        start: {
 +          offset: index,
 +          line: 1,
 +          column: index + 1,
 +        },
 +        end: {
 +          offset: index + 11,
 +          line: 1,
 +          column: index + 12,
 +        },
 +      },
 +    })
 +  })
 +})
index c434c736def6f8560c6a6bebb13d7d736201de63,0000000000000000000000000000000000000000..02852dc07cce9ce4037531836a14edb4d454461e
mode 100644,000000..100644
--- /dev/null
@@@ -1,101 -1,0 +1,101 @@@
-       genDirectiveModifiers(dir.modifiers),
 +import {
 +  createSimpleExpression,
 +  isSimpleIdentifier,
 +  toValidAssetId,
 +} from '@vue/compiler-dom'
 +import { extend } from '@vue/shared'
 +import { genExpression } from './expression'
 +import type { CodegenContext } from '../generate'
 +import {
 +  type CodeFragment,
 +  type CodeFragmentDelimiters,
 +  DELIMITERS_ARRAY,
 +  NEWLINE,
 +  genCall,
 +  genMulti,
 +} from './utils'
 +import {
 +  IRNodeTypes,
 +  type OperationNode,
 +  type WithDirectiveIRNode,
 +} from '../ir'
 +
 +export function genDirectivesForElement(
 +  id: number,
 +  context: CodegenContext,
 +): CodeFragment[] {
 +  const dirs = filterDirectives(id, context.block.operation)
 +  return dirs.length ? genWithDirective(dirs, context) : []
 +}
 +
 +export function genWithDirective(
 +  opers: WithDirectiveIRNode[],
 +  context: CodegenContext,
 +): CodeFragment[] {
 +  const { vaporHelper } = context
 +
 +  const element = `n${opers[0].element}`
 +  const directiveItems = opers.map(genDirective)
 +  const directives = genMulti(DELIMITERS_ARRAY, ...directiveItems)
 +
 +  return [
 +    NEWLINE,
 +    ...genCall(vaporHelper('withDirectives'), element, directives),
 +  ]
 +
 +  function genDirective({
 +    dir,
 +    name,
 +    builtin,
 +    asset,
 +  }: WithDirectiveIRNode): CodeFragment[] {
 +    const directive = genDirective()
 +    const value = dir.exp && ['() => ', ...genExpression(dir.exp, context)]
 +    const argument = dir.arg && genExpression(dir.arg, context)
 +    const modifiers = !!dir.modifiers.length && [
 +      '{ ',
++      genDirectiveModifiers(dir.modifiers.map(m => m.content)),
 +      ' }',
 +    ]
 +
 +    return genMulti(
 +      DELIMITERS_ARRAY.concat('void 0') as CodeFragmentDelimiters,
 +      directive,
 +      value,
 +      argument,
 +      modifiers,
 +    )
 +
 +    function genDirective() {
 +      if (builtin) {
 +        return vaporHelper(name as any)
 +      } else if (asset) {
 +        return toValidAssetId(name, 'directive')
 +      } else {
 +        return genExpression(
 +          extend(createSimpleExpression(name, false), { ast: null }),
 +          context,
 +        )
 +      }
 +    }
 +  }
 +}
 +
 +export function genDirectiveModifiers(modifiers: string[]): string {
 +  return modifiers
 +    .map(
 +      value =>
 +        `${isSimpleIdentifier(value) ? value : JSON.stringify(value)}: true`,
 +    )
 +    .join(', ')
 +}
 +
 +function filterDirectives(
 +  id: number,
 +  operations: OperationNode[],
 +): WithDirectiveIRNode[] {
 +  return operations.filter(
 +    (oper): oper is WithDirectiveIRNode =>
 +      oper.type === IRNodeTypes.WITH_DIRECTIVE && oper.element === id,
 +  )
 +}
index 8393e940ce8ce9070c8fca228d12774661b7bfdd,0000000000000000000000000000000000000000..3be9ea4d601397f69c89b6d0791ed1ab4f9ef265
mode 100644,000000..100644
--- /dev/null
@@@ -1,115 -1,0 +1,117 @@@
-   fnExpRE,
 +import {
 +  type SimpleExpressionNode,
-     const isMemberExp = isMemberExpression(value.content, context.options)
-     const isInlineStatement = !(isMemberExp || fnExpRE.test(value.content))
++  isFnExpression,
 +  isMemberExpression,
 +} from '@vue/compiler-dom'
 +import type { CodegenContext } from '../generate'
 +import type { SetDynamicEventsIRNode, SetEventIRNode } from '../ir'
 +import { genExpression } from './expression'
 +import {
 +  type CodeFragment,
 +  DELIMITERS_OBJECT_NEWLINE,
 +  NEWLINE,
 +  genCall,
 +  genMulti,
 +} from './utils'
 +
 +export function genSetEvent(
 +  oper: SetEventIRNode,
 +  context: CodegenContext,
 +): CodeFragment[] {
 +  const { vaporHelper } = context
 +  const { element, key, keyOverride, value, modifiers, delegate, effect } = oper
 +
 +  const name = genName()
 +  const handler = genEventHandler(context, value)
 +  const eventOptions = genEventOptions()
 +
 +  if (delegate) {
 +    // key is static
 +    context.delegates.add(key.content)
 +  }
 +
 +  return [
 +    NEWLINE,
 +    ...genCall(
 +      vaporHelper(delegate ? 'delegate' : 'on'),
 +      `n${element}`,
 +      name,
 +      handler,
 +      eventOptions,
 +    ),
 +  ]
 +
 +  function genName(): CodeFragment[] {
 +    const expr = genExpression(key, context)
 +    if (keyOverride) {
 +      // TODO unit test
 +      const find = JSON.stringify(keyOverride[0])
 +      const replacement = JSON.stringify(keyOverride[1])
 +      const wrapped: CodeFragment[] = ['(', ...expr, ')']
 +      return [...wrapped, ` === ${find} ? ${replacement} : `, ...wrapped]
 +    } else {
 +      return genExpression(key, context)
 +    }
 +  }
 +
 +  function genEventOptions(): CodeFragment[] | undefined {
 +    let { options, keys, nonKeys } = modifiers
 +    if (!options.length && !nonKeys.length && !keys.length && !effect) return
 +
 +    return genMulti(
 +      DELIMITERS_OBJECT_NEWLINE,
 +      !!nonKeys.length && ['modifiers: ', genArrayExpression(nonKeys)],
 +      !!keys.length && ['keys: ', genArrayExpression(keys)],
 +      effect && ['effect: true'],
 +      ...options.map((option): CodeFragment[] => [`${option}: true`]),
 +    )
 +  }
 +}
 +
 +export function genSetDynamicEvents(
 +  oper: SetDynamicEventsIRNode,
 +  context: CodegenContext,
 +): CodeFragment[] {
 +  const { vaporHelper } = context
 +  return [
 +    NEWLINE,
 +    ...genCall(
 +      vaporHelper('setDynamicEvents'),
 +      `n${oper.element}`,
 +      genExpression(oper.event, context),
 +    ),
 +  ]
 +}
 +
 +function genArrayExpression(elements: string[]) {
 +  return `[${elements.map(it => JSON.stringify(it)).join(', ')}]`
 +}
 +
 +export function genEventHandler(
 +  context: CodegenContext,
 +  value: SimpleExpressionNode | undefined,
 +): CodeFragment[] {
 +  if (value && value.content.trim()) {
++    const isMemberExp = isMemberExpression(value, context.options)
++    const isInlineStatement = !(
++      isMemberExp || isFnExpression(value, context.options)
++    )
 +
 +    if (isInlineStatement) {
 +      const expr = context.withId(() => genExpression(value, context), {
 +        $event: null,
 +      })
 +      const hasMultipleStatements = value.content.includes(`;`)
 +      return [
 +        '() => $event => ',
 +        hasMultipleStatements ? '{' : '(',
 +        ...expr,
 +        hasMultipleStatements ? '}' : ')',
 +      ]
 +    } else {
 +      return ['() => ', ...genExpression(value, context)]
 +    }
 +  }
 +
 +  return ['() => {}']
 +}
index 3d7b4a8392368047c45c57a58d2c260697618f87,0000000000000000000000000000000000000000..02a41015b0df444606827b20d11e0cc7d4184ebf
mode 100644,000000..100644
--- /dev/null
@@@ -1,78 -1,0 +1,79 @@@
-   if (modifiers.includes('camel')) {
 +import {
 +  ErrorCodes,
 +  NodeTypes,
 +  type SimpleExpressionNode,
 +  createCompilerError,
 +  createSimpleExpression,
 +} from '@vue/compiler-dom'
 +import { camelize, extend } from '@vue/shared'
 +import type { DirectiveTransform, TransformContext } from '../transform'
 +import { resolveExpression } from '../utils'
 +import { isReservedProp } from './transformElement'
 +
 +// same-name shorthand - :arg is expanded to :arg="arg"
 +export function normalizeBindShorthand(
 +  arg: SimpleExpressionNode,
 +  context: TransformContext,
 +): SimpleExpressionNode {
 +  if (arg.type !== NodeTypes.SIMPLE_EXPRESSION || !arg.isStatic) {
 +    // only simple expression is allowed for same-name shorthand
 +    context.options.onError(
 +      createCompilerError(
 +        ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
 +        arg.loc,
 +      ),
 +    )
 +    return createSimpleExpression('', true, arg.loc)
 +  }
 +
 +  const propName = camelize(arg.content)
 +  const exp = createSimpleExpression(propName, false, arg.loc)
 +  exp.ast = null
 +  return exp
 +}
 +
 +export const transformVBind: DirectiveTransform = (dir, node, context) => {
 +  const { loc, modifiers } = dir
 +  let { exp } = dir
 +  let arg = dir.arg!
++  const modifiersString = modifiers.map(s => s.content)
 +
 +  if (!exp) exp = normalizeBindShorthand(arg, context)
 +  if (!exp.content.trim()) {
 +    if (!__BROWSER__) {
 +      // #10280 only error against empty expression in non-browser build
 +      // because :foo in in-DOM templates will be parsed into :foo="" by the
 +      // browser
 +      context.options.onError(
 +        createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
 +      )
 +    }
 +    exp = createSimpleExpression('', true, loc)
 +  }
 +
 +  exp = resolveExpression(exp)
 +  arg = resolveExpression(arg)
 +
 +  if (arg.isStatic && isReservedProp(arg.content)) return
 +
 +  let camel = false
-     modifier: modifiers.includes('prop')
++  if (modifiersString.includes('camel')) {
 +    if (arg.isStatic) {
 +      arg = extend({}, arg, { content: camelize(arg.content) })
 +    } else {
 +      camel = true
 +    }
 +  }
 +
 +  return {
 +    key: arg,
 +    value: exp,
 +    loc,
 +    runtimeCamelize: camel,
-       : modifiers.includes('attr')
++    modifier: modifiersString.includes('prop')
 +      ? '.'
++      : modifiersString.includes('attr')
 +        ? '^'
 +        : undefined,
 +  }
 +}
index 5f46aa7860d445f15a3614c7e996a3d6fbbd2963,0000000000000000000000000000000000000000..e3bbe6e1c50cffaedf0076105525faa7c56b971a
mode 100644,000000..100644
--- /dev/null
@@@ -1,170 -1,0 +1,170 @@@
-     (!isMemberExpression(expString, context.options) && !maybeRef)
 +import {
 +  BindingTypes,
 +  DOMErrorCodes,
 +  ElementTypes,
 +  ErrorCodes,
 +  NodeTypes,
 +  createCompilerError,
 +  createDOMCompilerError,
 +  createSimpleExpression,
 +  findDir,
 +  findProp,
 +  hasDynamicKeyVBind,
 +  isMemberExpression,
 +  isStaticArgOf,
 +} from '@vue/compiler-dom'
 +import type { DirectiveTransform } from '../transform'
 +import { IRNodeTypes, type VaporHelper } from '../ir'
 +
 +export const transformVModel: DirectiveTransform = (dir, node, context) => {
 +  const { exp, arg } = dir
 +  if (!exp) {
 +    context.options.onError(
 +      createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION, dir.loc),
 +    )
 +    return
 +  }
 +
 +  // we assume v-model directives are always parsed
 +  // (not artificially created by a transform)
 +  const rawExp = exp.loc.source
 +
 +  // in SFC <script setup> inline mode, the exp may have been transformed into
 +  // _unref(exp)
 +  const bindingType = context.options.bindingMetadata[rawExp]
 +
 +  // check props
 +  if (
 +    bindingType === BindingTypes.PROPS ||
 +    bindingType === BindingTypes.PROPS_ALIASED
 +  ) {
 +    context.options.onError(
 +      createCompilerError(ErrorCodes.X_V_MODEL_ON_PROPS, exp.loc),
 +    )
 +    return
 +  }
 +
 +  const expString = exp.content
 +  const maybeRef =
 +    !__BROWSER__ &&
 +    context.options.inline &&
 +    (bindingType === BindingTypes.SETUP_LET ||
 +      bindingType === BindingTypes.SETUP_REF ||
 +      bindingType === BindingTypes.SETUP_MAYBE_REF)
 +  if (
 +    !expString.trim() ||
-       modelModifiers: dir.modifiers,
++    (!isMemberExpression(exp, context.options) && !maybeRef)
 +  ) {
 +    context.options.onError(
 +      createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc),
 +    )
 +    return
 +  }
 +
 +  const isComponent = node.tagType === ElementTypes.COMPONENT
 +  if (isComponent) {
 +    return {
 +      key: arg ? arg : createSimpleExpression('modelValue', true),
 +      value: exp,
 +      model: true,
++      modelModifiers: dir.modifiers.map(m => m.content),
 +    }
 +  }
 +
 +  if (dir.arg)
 +    context.options.onError(
 +      createDOMCompilerError(
 +        DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
 +        dir.arg.loc,
 +      ),
 +    )
 +  const { tag } = node
 +  const isCustomElement = context.options.isCustomElement(tag)
 +  let runtimeDirective: VaporHelper | undefined = 'vModelText'
 +  if (
 +    tag === 'input' ||
 +    tag === 'textarea' ||
 +    tag === 'select' ||
 +    isCustomElement
 +  ) {
 +    if (tag === 'input' || isCustomElement) {
 +      const type = findProp(node, 'type')
 +      if (type) {
 +        if (type.type === NodeTypes.DIRECTIVE) {
 +          // :type="foo"
 +          runtimeDirective = 'vModelDynamic'
 +        } else if (type.value) {
 +          switch (type.value.content) {
 +            case 'radio':
 +              runtimeDirective = 'vModelRadio'
 +              break
 +            case 'checkbox':
 +              runtimeDirective = 'vModelCheckbox'
 +              break
 +            case 'file':
 +              runtimeDirective = undefined
 +              context.options.onError(
 +                createDOMCompilerError(
 +                  DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT,
 +                  dir.loc,
 +                ),
 +              )
 +              break
 +            default:
 +              // text type
 +              __DEV__ && checkDuplicatedValue()
 +              break
 +          }
 +        }
 +      } else if (hasDynamicKeyVBind(node)) {
 +        // element has bindings with dynamic keys, which can possibly contain
 +        // "type".
 +        runtimeDirective = 'vModelDynamic'
 +      } else {
 +        // text type
 +        __DEV__ && checkDuplicatedValue()
 +      }
 +    } else if (tag === 'select') {
 +      runtimeDirective = 'vModelSelect'
 +    } else {
 +      // textarea
 +      __DEV__ && checkDuplicatedValue()
 +    }
 +  } else {
 +    context.options.onError(
 +      createDOMCompilerError(
 +        DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
 +        dir.loc,
 +      ),
 +    )
 +  }
 +
 +  context.registerOperation({
 +    type: IRNodeTypes.SET_MODEL_VALUE,
 +    element: context.reference(),
 +    key: arg || createSimpleExpression('modelValue', true),
 +    value: exp,
 +    isComponent,
 +  })
 +
 +  if (runtimeDirective)
 +    context.registerOperation({
 +      type: IRNodeTypes.WITH_DIRECTIVE,
 +      element: context.reference(),
 +      dir,
 +      name: runtimeDirective,
 +      builtin: true,
 +    })
 +
 +  function checkDuplicatedValue() {
 +    const value = findDir(node, 'bind')
 +    if (value && isStaticArgOf(value.arg, 'value')) {
 +      context.options.onError(
 +        createDOMCompilerError(
 +          DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE,
 +          value.loc,
 +        ),
 +      )
 +    }
 +  }
 +}
Simple merge
Simple merge
index 08bef754be23a9ad580ac95c95643cea8279fa06,a1ce1de4eb995b1de4a09f456dc2b2a84da8cb40..672cf3d89083f212aefbc23f7e3d8b6a47151e94
@@@ -95,7 -94,10 +95,8 @@@ import type { BaseTransitionProps } fro
  import type { DefineComponent } from './apiDefineComponent'
  import { markAsyncBoundary } from './helpers/useId'
  import { isAsyncWrapper } from './apiAsyncComponent'
+ import type { RendererElement } from './renderer'
  
 -export type Data = Record<string, unknown>
 -
  /**
   * Public utility type for extracting the instance type of a component.
   * Works with all valid component definition types. This is intended to replace
Simple merge
index 3321018baf46c17d50ad85f5d0c32651c2bb3f13,90cc22f547032c5a830be2fdda6bc1b96fceeeb3..efa761cd2b2de2368ec4168dc139a8afa112c5d7
@@@ -38,10 -39,9 +38,10 @@@ import 
    isArray,
    isReservedProp,
  } from '@vue/shared'
 +import type { Data } from '@vue/runtime-shared'
  import {
-   type SchedulerFactory,
    type SchedulerJob,
+   SchedulerJobFlags,
    type SchedulerJobs,
    flushPostFlushCbs,
    flushPreFlushCbs,
Simple merge
Simple merge
index 87336f27bbeab534b257c4e7bd1d70b8cf7982dc,0000000000000000000000000000000000000000..7748405aa48862334ad1c3d34da1d7ba2188d071
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,88 @@@
- export function makeRender<Component = ObjectComponent | SetupFn>(
-   initHost = () => {
 +import {
 +  type App,
++  type Component,
 +  type ComponentInternalInstance,
 +  type ObjectComponent,
 +  type SetupFn,
 +  createVaporApp,
 +  defineComponent,
 +} from '../src'
 +import type { RawProps } from '../src/componentProps'
 +
- ) {
++export interface RenderContext {
++  component: Component
++  host: HTMLElement
++  instance: ComponentInternalInstance | undefined
++  app: App
++  create: (props?: RawProps) => RenderContext
++  mount: (container?: string | ParentNode) => RenderContext
++  render: (props?: RawProps, container?: string | ParentNode) => RenderContext
++  resetHost: () => HTMLDivElement
++  html: () => string
++}
++
++export function makeRender<C = ObjectComponent | SetupFn>(
++  initHost = (): HTMLDivElement => {
 +    const host = document.createElement('div')
 +    host.setAttribute('id', 'host')
 +    document.body.appendChild(host)
 +    return host
 +  },
-   function define(comp: Component) {
++): (comp: C) => RenderContext {
 +  let host: HTMLElement
 +  function resetHost() {
 +    return (host = initHost())
 +  }
 +
 +  beforeEach(() => {
 +    resetHost()
 +  })
 +  afterEach(() => {
 +    host.remove()
 +  })
 +
++  function define(comp: C) {
 +    const component = defineComponent(comp as any)
 +    let instance: ComponentInternalInstance | undefined
 +    let app: App
 +
 +    function render(
 +      props: RawProps = {},
 +      container: string | ParentNode = host,
 +    ) {
 +      create(props)
 +      return mount(container)
 +    }
 +
 +    function create(props: RawProps = {}) {
 +      app?.unmount()
 +      app = createVaporApp(component, props)
 +      return res()
 +    }
 +
 +    function mount(container: string | ParentNode = host) {
 +      instance = app.mount(container)
 +      return res()
 +    }
 +
 +    function html() {
 +      return host.innerHTML
 +    }
 +
 +    const res = () => ({
 +      component,
 +      host,
 +      instance,
 +      app,
 +      create,
 +      mount,
 +      render,
 +      resetHost,
 +      html,
 +    })
 +
 +    return res()
 +  }
 +
 +  return define
 +}
index a596b3fe84d5c10d7e5940cfe08a611e160fc3b5,0000000000000000000000000000000000000000..f8bdb4f529927af5448f0f30e09a92a7abc62e55
mode 100644,000000..100644
--- /dev/null
@@@ -1,245 -1,0 +1,245 @@@
-     let spyIfFn: Mock<any, any>
-     let spyElseFn: Mock<any, any>
 +import {
 +  children,
 +  createIf,
 +  insert,
 +  nextTick,
 +  ref,
 +  renderEffect,
 +  setText,
 +  template,
 +  withDirectives,
 +} from '../src'
 +import type { Mock } from 'vitest'
 +import { makeRender } from './_utils'
 +import { unmountComponent } from '../src/apiRender'
 +
 +const define = makeRender()
 +
 +describe('createIf', () => {
 +  test('basic', async () => {
 +    // mock this template:
 +    //  <div>
 +    //    <p v-if="counter">{{counter}}</p>
 +    //    <p v-else>zero</p>
 +    //  </div>
 +
++    let spyIfFn: Mock<any>
++    let spyElseFn: Mock<any>
 +    const count = ref(0)
 +
 +    const spyConditionFn = vi.fn(() => count.value)
 +
 +    // templates can be reused through caching.
 +    const t0 = template('<div></div>')
 +    const t1 = template('<p></p>')
 +    const t2 = template('<p>zero</p>')
 +
 +    const { host } = define(() => {
 +      const n0 = t0()
 +
 +      insert(
 +        createIf(
 +          spyConditionFn,
 +          // v-if
 +          (spyIfFn ||= vi.fn(() => {
 +            const n2 = t1()
 +            renderEffect(() => {
 +              setText(n2, count.value)
 +            })
 +            return n2
 +          })),
 +          // v-else
 +          (spyElseFn ||= vi.fn(() => {
 +            const n4 = t2()
 +            return n4
 +          })),
 +        ),
 +        n0 as any as ParentNode,
 +      )
 +      return n0
 +    }).render()
 +
 +    expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>')
 +    expect(spyConditionFn).toHaveBeenCalledTimes(1)
 +    expect(spyIfFn!).toHaveBeenCalledTimes(0)
 +    expect(spyElseFn!).toHaveBeenCalledTimes(1)
 +
 +    count.value++
 +    await nextTick()
 +    expect(host.innerHTML).toBe('<div><p>1</p><!--if--></div>')
 +    expect(spyConditionFn).toHaveBeenCalledTimes(2)
 +    expect(spyIfFn!).toHaveBeenCalledTimes(1)
 +    expect(spyElseFn!).toHaveBeenCalledTimes(1)
 +
 +    count.value++
 +    await nextTick()
 +    expect(host.innerHTML).toBe('<div><p>2</p><!--if--></div>')
 +    expect(spyConditionFn).toHaveBeenCalledTimes(3)
 +    expect(spyIfFn!).toHaveBeenCalledTimes(1)
 +    expect(spyElseFn!).toHaveBeenCalledTimes(1)
 +
 +    count.value = 0
 +    await nextTick()
 +    expect(host.innerHTML).toBe('<div><p>zero</p><!--if--></div>')
 +    expect(spyConditionFn).toHaveBeenCalledTimes(4)
 +    expect(spyIfFn!).toHaveBeenCalledTimes(1)
 +    expect(spyElseFn!).toHaveBeenCalledTimes(2)
 +  })
 +
 +  test('should handle nested template', async () => {
 +    // mock this template:
 +    //  <template v-if="ok1">
 +    //    Hello <template v-if="ok2">Vapor</template>
 +    //  </template>
 +
 +    const ok1 = ref(true)
 +    const ok2 = ref(true)
 +
 +    const t0 = template('Vapor')
 +    const t1 = template('Hello ')
 +    const { host } = define(() => {
 +      const n1 = createIf(
 +        () => ok1.value,
 +        () => {
 +          const n2 = t1()
 +          const n3 = createIf(
 +            () => ok2.value,
 +            () => {
 +              const n4 = t0()
 +              return n4
 +            },
 +          )
 +          return [n2, n3]
 +        },
 +      )
 +      return n1
 +    }).render()
 +
 +    expect(host.innerHTML).toBe('Hello Vapor<!--if--><!--if-->')
 +
 +    ok1.value = false
 +    await nextTick()
 +    expect(host.innerHTML).toBe('<!--if-->')
 +
 +    ok1.value = true
 +    await nextTick()
 +    expect(host.innerHTML).toBe('Hello Vapor<!--if--><!--if-->')
 +
 +    ok2.value = false
 +    await nextTick()
 +    expect(host.innerHTML).toBe('Hello <!--if--><!--if-->')
 +
 +    ok1.value = false
 +    await nextTick()
 +    expect(host.innerHTML).toBe('<!--if-->')
 +  })
 +
 +  test('should work with directive hooks', async () => {
 +    const calls: string[] = []
 +    const show1 = ref(true)
 +    const show2 = ref(true)
 +    const update = ref(0)
 +
 +    const spyConditionFn1 = vi.fn(() => show1.value)
 +    const spyConditionFn2 = vi.fn(() => show2.value)
 +
 +    const vDirective: any = {
 +      created: (el: any, { value }: any) => calls.push(`${value} created`),
 +      beforeMount: (el: any, { value }: any) =>
 +        calls.push(`${value} beforeMount`),
 +      mounted: (el: any, { value }: any) => calls.push(`${value} mounted`),
 +      beforeUpdate: (el: any, { value }: any) =>
 +        calls.push(`${value} beforeUpdate`),
 +      updated: (el: any, { value }: any) => calls.push(`${value} updated`),
 +      beforeUnmount: (el: any, { value }: any) =>
 +        calls.push(`${value} beforeUnmount`),
 +      unmounted: (el: any, { value }: any) => calls.push(`${value} unmounted`),
 +    }
 +
 +    const t0 = template('<p></p>')
 +    const { instance } = define(() => {
 +      const n1 = createIf(
 +        spyConditionFn1,
 +        () => {
 +          const n2 = t0()
 +          withDirectives(children(n2, 0), [
 +            [vDirective, () => (update.value, '1')],
 +          ])
 +          return n2
 +        },
 +        () =>
 +          createIf(
 +            spyConditionFn2,
 +            () => {
 +              const n2 = t0()
 +              withDirectives(children(n2, 0), [[vDirective, () => '2']])
 +              return n2
 +            },
 +            () => {
 +              const n2 = t0()
 +              withDirectives(children(n2, 0), [[vDirective, () => '3']])
 +              return n2
 +            },
 +          ),
 +      )
 +      return [n1]
 +    }).render()
 +
 +    await nextTick()
 +    expect(calls).toEqual(['1 created', '1 beforeMount', '1 mounted'])
 +    calls.length = 0
 +    expect(spyConditionFn1).toHaveBeenCalledTimes(1)
 +    expect(spyConditionFn2).toHaveBeenCalledTimes(0)
 +
 +    show1.value = false
 +    await nextTick()
 +    expect(calls).toEqual([
 +      '1 beforeUnmount',
 +      '2 created',
 +      '2 beforeMount',
 +      '1 unmounted',
 +      '2 mounted',
 +    ])
 +    calls.length = 0
 +    expect(spyConditionFn1).toHaveBeenCalledTimes(2)
 +    expect(spyConditionFn2).toHaveBeenCalledTimes(1)
 +
 +    show2.value = false
 +    await nextTick()
 +    expect(calls).toEqual([
 +      '2 beforeUnmount',
 +      '3 created',
 +      '3 beforeMount',
 +      '2 unmounted',
 +      '3 mounted',
 +    ])
 +    calls.length = 0
 +    expect(spyConditionFn1).toHaveBeenCalledTimes(2)
 +    expect(spyConditionFn2).toHaveBeenCalledTimes(2)
 +
 +    show1.value = true
 +    await nextTick()
 +    expect(calls).toEqual([
 +      '3 beforeUnmount',
 +      '1 created',
 +      '1 beforeMount',
 +      '3 unmounted',
 +      '1 mounted',
 +    ])
 +    calls.length = 0
 +    expect(spyConditionFn1).toHaveBeenCalledTimes(3)
 +    expect(spyConditionFn2).toHaveBeenCalledTimes(2)
 +
 +    update.value++
 +    await nextTick()
 +    expect(calls).toEqual(['1 beforeUpdate', '1 updated'])
 +    calls.length = 0
 +    expect(spyConditionFn1).toHaveBeenCalledTimes(3)
 +    expect(spyConditionFn2).toHaveBeenCalledTimes(2)
 +
 +    unmountComponent(instance!)
 +    expect(calls).toEqual(['1 beforeUnmount', '1 unmounted'])
 +    expect(spyConditionFn1).toHaveBeenCalledTimes(3)
 +    expect(spyConditionFn2).toHaveBeenCalledTimes(2)
 +  })
 +})
index 45442529734f52083c4b15d47e465e1dededa2b4,0000000000000000000000000000000000000000..758ae91296f8b0f20d034403861178c312fac8cb
mode 100644,000000..100644
--- /dev/null
@@@ -1,219 -1,0 +1,230 @@@
-   type BaseWatchErrorCodes,
-   type BaseWatchOptions,
 +import {
-   baseWatch,
-   getCurrentScope,
++  type WatchOptions as BaseWatchOptions,
 +  type ComputedRef,
 +  type DebuggerOptions,
 +  type Ref,
- import { EMPTY_OBJ, extend, isFunction, remove } from '@vue/shared'
++  watch as baseWatch,
 +} from '@vue/reactivity'
-   type SchedulerFactory,
-   createVaporPostScheduler,
-   createVaporPreScheduler,
-   createVaporSyncScheduler,
++import { EMPTY_OBJ, extend, isFunction } from '@vue/shared'
 +import { currentInstance } from './component'
 +import {
- import { handleError as handleErrorWithInstance } from './errorHandling'
++  type SchedulerJob,
++  VaporSchedulerJobFlags,
++  queueJob,
++  queuePostFlushCb,
 +} from './scheduler'
- function getScheduler(flush: WatchOptionsBase['flush']): SchedulerFactory {
-   if (flush === 'post') {
-     return createVaporPostScheduler
-   }
-   if (flush === 'sync') {
-     return createVaporSyncScheduler
-   }
-   // default: 'pre'
-   return createVaporPreScheduler
- }
++import { callWithAsyncErrorHandling } from './errorHandling'
 +import { warn } from './warning'
 +
 +export type WatchEffect = (onCleanup: OnCleanup) => void
 +
 +export type WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T)
 +
 +export type WatchCallback<V = any, OV = any> = (
 +  value: V,
 +  oldValue: OV,
 +  onCleanup: OnCleanup,
 +) => any
 +
 +type MapSources<T, Immediate> = {
 +  [K in keyof T]: T[K] extends WatchSource<infer V>
 +    ? Immediate extends true
 +      ? V | undefined
 +      : V
 +    : T[K] extends object
 +      ? Immediate extends true
 +        ? T[K] | undefined
 +        : T[K]
 +      : never
 +}
 +
 +type OnCleanup = (cleanupFn: () => void) => void
 +
 +export interface WatchOptionsBase extends DebuggerOptions {
 +  flush?: 'pre' | 'post' | 'sync'
 +}
 +
 +export interface WatchOptions<Immediate = boolean> extends WatchOptionsBase {
 +  immediate?: Immediate
 +  deep?: boolean
 +  once?: boolean
 +}
 +
 +export type WatchStopHandle = () => void
 +
 +// Simple effect.
 +export function watchEffect(
 +  effect: WatchEffect,
 +  options?: WatchOptionsBase,
 +): WatchStopHandle {
 +  return doWatch(effect, null, options)
 +}
 +
 +export function watchPostEffect(
 +  effect: WatchEffect,
 +  options?: DebuggerOptions,
 +): WatchStopHandle {
 +  return doWatch(
 +    effect,
 +    null,
 +    __DEV__ ? extend({}, options as any, { flush: 'post' }) : { flush: 'post' },
 +  )
 +}
 +
 +export function watchSyncEffect(
 +  effect: WatchEffect,
 +  options?: DebuggerOptions,
 +): WatchStopHandle {
 +  return doWatch(
 +    effect,
 +    null,
 +    __DEV__ ? extend({}, options as any, { flush: 'sync' }) : { flush: 'sync' },
 +  )
 +}
 +
 +type MultiWatchSources = (WatchSource<unknown> | object)[]
 +
 +// overload: single source + cb
 +export function watch<T, Immediate extends Readonly<boolean> = false>(
 +  source: WatchSource<T>,
 +  cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
 +  options?: WatchOptions<Immediate>,
 +): WatchStopHandle
 +
 +// overload: array of multiple sources + cb
 +export function watch<
 +  T extends MultiWatchSources,
 +  Immediate extends Readonly<boolean> = false,
 +>(
 +  sources: [...T],
 +  cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
 +  options?: WatchOptions<Immediate>,
 +): WatchStopHandle
 +
 +// overload: multiple sources w/ `as const`
 +// watch([foo, bar] as const, () => {})
 +// somehow [...T] breaks when the type is readonly
 +export function watch<
 +  T extends Readonly<MultiWatchSources>,
 +  Immediate extends Readonly<boolean> = false,
 +>(
 +  source: T,
 +  cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
 +  options?: WatchOptions<Immediate>,
 +): WatchStopHandle
 +
 +// overload: watching reactive object w/ cb
 +export function watch<
 +  T extends object,
 +  Immediate extends Readonly<boolean> = false,
 +>(
 +  source: T,
 +  cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
 +  options?: WatchOptions<Immediate>,
 +): WatchStopHandle
 +
 +// implementation
 +export function watch<T = any, Immediate extends Readonly<boolean> = false>(
 +  source: T | WatchSource<T>,
 +  cb: any,
 +  options?: WatchOptions<Immediate>,
 +): WatchStopHandle {
 +  if (__DEV__ && !isFunction(cb)) {
 +    warn(
 +      `\`watch(fn, options?)\` signature has been moved to a separate API. ` +
 +        `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` +
 +        `supports \`watch(source, cb, options?) signature.`,
 +    )
 +  }
 +  return doWatch(source as any, cb, options)
 +}
 +
-   const extendOptions: BaseWatchOptions = {}
 +function doWatch(
 +  source: WatchSource | WatchSource[] | WatchEffect | object,
 +  cb: WatchCallback | null,
 +  options: WatchOptions = EMPTY_OBJ,
 +): WatchStopHandle {
 +  const { immediate, deep, flush, once } = options
 +
 +  if (__DEV__ && !cb) {
 +    if (immediate !== undefined) {
 +      warn(
 +        `watch() "immediate" option is only respected when using the ` +
 +          `watch(source, callback, options?) signature.`,
 +      )
 +    }
 +    if (deep !== undefined) {
 +      warn(
 +        `watch() "deep" option is only respected when using the ` +
 +          `watch(source, callback, options?) signature.`,
 +      )
 +    }
 +    if (once !== undefined) {
 +      warn(
 +        `watch() "once" option is only respected when using the ` +
 +          `watch(source, callback, options?) signature.`,
 +      )
 +    }
 +  }
 +
-   if (__DEV__) extendOptions.onWarn = warn
++  const baseWatchOptions: BaseWatchOptions = extend({}, options)
 +
-   extendOptions.onError = (err: unknown, type: BaseWatchErrorCodes) =>
-     handleErrorWithInstance(err, instance, type)
-   extendOptions.scheduler = getScheduler(flush)(instance)
++  if (__DEV__) baseWatchOptions.onWarn = warn
 +
 +  let ssrCleanup: (() => void)[] | undefined
 +  // TODO: SSR
 +  // if (__SSR__ && isInSSRComponentSetup) {
 +  //   if (flush === 'sync') {
 +  //     const ctx = useSSRContext()!
 +  //     ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = [])
 +  //   } else if (!cb || immediate) {
 +  //     // immediately watch or watchEffect
 +  //     extendOptions.once = true
 +  //   } else {
 +  //     // watch(source, cb)
 +  //     return NOOP
 +  //   }
 +  // }
 +
 +  const instance = currentInstance
++  baseWatchOptions.call = (fn, type, args) =>
++    callWithAsyncErrorHandling(fn, instance, type, args)
 +
-   const effect = baseWatch(source, cb, extend({}, options, extendOptions))
-   const scope = getCurrentScope()
-   const unwatch = () => {
-     effect!.stop()
-     if (scope) {
-       remove(scope.effects, effect)
++  // scheduler
++  let isPre = false
++  if (flush === 'post') {
++    baseWatchOptions.scheduler = job => {
++      queuePostFlushCb(job)
++    }
++  } else if (flush !== 'sync') {
++    // default: 'pre'
++    isPre = true
++    baseWatchOptions.scheduler = (job, isFirstRun) => {
++      if (isFirstRun) {
++        job()
++      } else {
++        queueJob(job)
++      }
++    }
++  }
 +
-   if (__SSR__ && ssrCleanup) ssrCleanup.push(unwatch)
-   return unwatch
++  baseWatchOptions.augmentJob = (job: SchedulerJob) => {
++    // important: mark the job as a watcher callback so that scheduler knows
++    // it is allowed to self-trigger (#1727)
++    if (cb) {
++      job.flags! |= VaporSchedulerJobFlags.ALLOW_RECURSE
++    }
++    if (isPre) {
++      job.flags! |= VaporSchedulerJobFlags.PRE
++      if (instance) {
++        job.id = instance.uid
++        ;(job as SchedulerJob).i = instance
++      }
 +    }
 +  }
 +
++  const watchHandle = baseWatch(source, cb, baseWatchOptions)
++
++  if (__SSR__ && ssrCleanup) ssrCleanup.push(watchHandle)
++  return watchHandle
 +}
index 43aab42f6cb7c7ce46451c78a3823c57aad47990,0000000000000000000000000000000000000000..ae0de07ee5e99e0b6df79e960ce47baffe0408db
mode 100644,000000..100644
--- /dev/null
@@@ -1,266 -1,0 +1,265 @@@
-   type SchedulerJob,
 +import { invokeArrayFns, isBuiltInDirective, isFunction } from '@vue/shared'
 +import {
 +  type ComponentInternalInstance,
 +  currentInstance,
 +  isVaporComponent,
 +  setCurrentInstance,
 +} from './component'
 +import {
 +  EffectFlags,
 +  ReactiveEffect,
- import { queueJob, queuePostFlushCb } from './scheduler'
 +  getCurrentScope,
 +  pauseTracking,
 +  resetTracking,
 +  traverse,
 +} from '@vue/reactivity'
 +import {
 +  VaporErrorCodes,
 +  callWithAsyncErrorHandling,
 +  callWithErrorHandling,
 +} from './errorHandling'
++import { type SchedulerJob, queueJob, queuePostFlushCb } from './scheduler'
 +import { warn } from './warning'
 +import { type BlockEffectScope, isRenderEffectScope } from './blockEffectScope'
 +import { normalizeBlock } from './dom/element'
 +
 +export type DirectiveModifiers<M extends string = string> = Record<M, boolean>
 +
 +export interface DirectiveBinding<T = any, V = any, M extends string = string> {
 +  instance: ComponentInternalInstance
 +  source?: () => V
 +  value: V
 +  oldValue: V | null
 +  arg?: string
 +  modifiers?: DirectiveModifiers<M>
 +  dir: ObjectDirective<T, V, M>
 +}
 +
 +export type DirectiveBindingsMap = Map<Node, DirectiveBinding[]>
 +
 +export type DirectiveHook<
 +  T = any | null,
 +  V = any,
 +  M extends string = string,
 +> = (node: T, binding: DirectiveBinding<T, V, M>) => void
 +
 +// create node -> `created` -> node operation -> `beforeMount` -> node mounted -> `mounted`
 +// effect update -> `beforeUpdate` -> node updated -> `updated`
 +// `beforeUnmount`-> node unmount -> `unmounted`
 +export type DirectiveHookName =
 +  | 'created'
 +  | 'beforeMount'
 +  | 'mounted'
 +  | 'beforeUpdate'
 +  | 'updated'
 +  | 'beforeUnmount'
 +  | 'unmounted'
 +export type ObjectDirective<T = any, V = any, M extends string = string> = {
 +  [K in DirectiveHookName]?: DirectiveHook<T, V, M> | undefined
 +} & {
 +  /** Watch value deeply */
 +  deep?: boolean | number
 +}
 +
 +export type FunctionDirective<
 +  T = any,
 +  V = any,
 +  M extends string = string,
 +> = DirectiveHook<T, V, M>
 +
 +export type Directive<T = any, V = any, M extends string = string> =
 +  | ObjectDirective<T, V, M>
 +  | FunctionDirective<T, V, M>
 +
 +export function validateDirectiveName(name: string): void {
 +  if (isBuiltInDirective(name)) {
 +    warn('Do not use built-in directive ids as custom directive id: ' + name)
 +  }
 +}
 +
 +export type DirectiveArguments = Array<
 +  | [Directive | undefined]
 +  | [Directive | undefined, () => any]
 +  | [Directive | undefined, () => any, argument: string]
 +  | [
 +      Directive | undefined,
 +      value: () => any,
 +      argument: string,
 +      modifiers: DirectiveModifiers,
 +    ]
 +>
 +
 +export function withDirectives<T extends ComponentInternalInstance | Node>(
 +  nodeOrComponent: T,
 +  directives: DirectiveArguments,
 +): T {
 +  if (!currentInstance) {
 +    __DEV__ && warn(`withDirectives can only be used inside render functions.`)
 +    return nodeOrComponent
 +  }
 +
 +  let node: Node
 +  if (isVaporComponent(nodeOrComponent)) {
 +    const root = getComponentNode(nodeOrComponent)
 +    if (!root) return nodeOrComponent
 +    node = root
 +  } else {
 +    node = nodeOrComponent
 +  }
 +
 +  let bindings: DirectiveBinding[]
 +  const instance = currentInstance!
 +  const parentScope = getCurrentScope() as BlockEffectScope
 +
 +  if (__DEV__ && !isRenderEffectScope(parentScope)) {
 +    warn(`Directives should be used inside of RenderEffectScope.`)
 +  }
 +
 +  const directivesMap = (parentScope.dirs ||= new Map())
 +  if (!(bindings = directivesMap.get(node))) {
 +    directivesMap.set(node, (bindings = []))
 +  }
 +
 +  for (const directive of directives) {
 +    let [dir, source, arg, modifiers] = directive
 +    if (!dir) continue
 +    if (isFunction(dir)) {
 +      dir = {
 +        mounted: dir,
 +        updated: dir,
 +      } satisfies ObjectDirective
 +    }
 +
 +    const binding: DirectiveBinding = {
 +      dir,
 +      instance,
 +      value: null, // set later
 +      oldValue: undefined,
 +      arg,
 +      modifiers,
 +    }
 +
 +    if (source) {
 +      if (dir.deep) {
 +        const deep = dir.deep === true ? undefined : dir.deep
 +        const baseSource = source
 +        source = () => traverse(baseSource(), deep)
 +      }
 +
 +      const effect = new ReactiveEffect(() =>
 +        callWithErrorHandling(
 +          source!,
 +          instance,
 +          VaporErrorCodes.RENDER_FUNCTION,
 +        ),
 +      )
 +      const triggerRenderingUpdate = createRenderingUpdateTrigger(
 +        instance,
 +        effect,
 +      )
 +      effect.scheduler = () => queueJob(triggerRenderingUpdate)
 +
 +      binding.source = effect.run.bind(effect)
 +    }
 +
 +    bindings.push(binding)
 +
 +    callDirectiveHook(node, binding, instance, 'created')
 +  }
 +
 +  return nodeOrComponent
 +}
 +
 +function getComponentNode(component: ComponentInternalInstance) {
 +  if (!component.block) return
 +
 +  const nodes = normalizeBlock(component.block)
 +  if (nodes.length !== 1) {
 +    warn(
 +      `Runtime directive used on component with non-element root node. ` +
 +        `The directives will not function as intended.`,
 +    )
 +    return
 +  }
 +
 +  return nodes[0]
 +}
 +
 +export function invokeDirectiveHook(
 +  instance: ComponentInternalInstance | null,
 +  name: DirectiveHookName,
 +  scope: BlockEffectScope,
 +): void {
 +  const { dirs } = scope
 +  if (name === 'mounted') scope.im = true
 +  if (!dirs) return
 +  const iterator = dirs.entries()
 +  for (const [node, bindings] of iterator) {
 +    for (const binding of bindings) {
 +      callDirectiveHook(node, binding, instance, name)
 +    }
 +  }
 +}
 +
 +function callDirectiveHook(
 +  node: Node,
 +  binding: DirectiveBinding,
 +  instance: ComponentInternalInstance | null,
 +  name: DirectiveHookName,
 +) {
 +  if (name === 'beforeUpdate') binding.oldValue = binding.value
 +  const { dir } = binding
 +  const hook = dir[name]
 +  if (!hook) return
 +
 +  const newValue = binding.source ? binding.source() : undefined
 +  binding.value = newValue
 +  // disable tracking inside all lifecycle hooks
 +  // since they can potentially be called inside effects.
 +  pauseTracking()
 +  callWithAsyncErrorHandling(hook, instance, VaporErrorCodes.DIRECTIVE_HOOK, [
 +    node,
 +    binding,
 +  ])
 +  resetTracking()
 +}
 +
 +export function createRenderingUpdateTrigger(
 +  instance: ComponentInternalInstance,
 +  effect: ReactiveEffect,
 +): SchedulerJob {
 +  job.id = instance.uid
 +  return job
 +  function job() {
 +    if (!(effect.flags & EffectFlags.ACTIVE) || !effect.dirty) {
 +      return
 +    }
 +
 +    if (instance.isMounted && !instance.isUpdating) {
 +      instance.isUpdating = true
 +      const reset = setCurrentInstance(instance)
 +
 +      const { bu, u, scope } = instance
 +      const { dirs } = scope
 +      // beforeUpdate hook
 +      if (bu) {
 +        invokeArrayFns(bu)
 +      }
 +      invokeDirectiveHook(instance, 'beforeUpdate', scope)
 +
 +      queuePostFlushCb(() => {
 +        instance.isUpdating = false
 +        const reset = setCurrentInstance(instance)
 +        if (dirs) {
 +          invokeDirectiveHook(instance, 'updated', scope)
 +        }
 +        // updated hook
 +        if (u) {
 +          queuePostFlushCb(u)
 +        }
 +        reset()
 +      })
 +      reset()
 +    }
 +  }
 +}
index 32c64ab0b33285251c8a833202c9cbad90398168,0000000000000000000000000000000000000000..bb1a947bb1ac3596c342c9aefbfceae09f5fec2f
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,133 @@@
- import {
-   type Ref,
-   type SchedulerJob,
-   isRef,
-   onScopeDispose,
- } from '@vue/reactivity'
++import { type Ref, isRef, onScopeDispose } from '@vue/reactivity'
 +import {
 +  type ComponentInternalInstance,
 +  currentInstance,
 +  isVaporComponent,
 +} from '../component'
 +import { VaporErrorCodes, callWithErrorHandling } from '../errorHandling'
 +import {
 +  EMPTY_OBJ,
 +  hasOwn,
 +  isArray,
 +  isFunction,
 +  isString,
 +  remove,
 +} from '@vue/shared'
 +import { warn } from '../warning'
- import { queuePostFlushCb } from '../scheduler'
++import { type SchedulerJob, queuePostFlushCb } from '../scheduler'
 +
 +export type NodeRef = string | Ref | ((ref: Element) => void)
 +export type RefEl = Element | ComponentInternalInstance
 +
 +/**
 + * Function for handling a template ref
 + */
 +export function setRef(
 +  el: RefEl,
 +  ref: NodeRef,
 +  oldRef?: NodeRef,
 +  refFor = false,
 +): NodeRef | undefined {
 +  if (!currentInstance) return
 +  const { setupState, isUnmounted } = currentInstance
 +
 +  if (isUnmounted) {
 +    return
 +  }
 +
 +  const refValue = isVaporComponent(el) ? el.exposed || el : el
 +
 +  const refs =
 +    currentInstance.refs === EMPTY_OBJ
 +      ? (currentInstance.refs = {})
 +      : currentInstance.refs
 +
 +  // dynamic ref changed. unset old ref
 +  if (oldRef != null && oldRef !== ref) {
 +    if (isString(oldRef)) {
 +      refs[oldRef] = null
 +      if (hasOwn(setupState, oldRef)) {
 +        setupState[oldRef] = null
 +      }
 +    } else if (isRef(oldRef)) {
 +      oldRef.value = null
 +    }
 +  }
 +
 +  if (isFunction(ref)) {
 +    const invokeRefSetter = (value?: Element | Record<string, any>) => {
 +      callWithErrorHandling(
 +        ref,
 +        currentInstance,
 +        VaporErrorCodes.FUNCTION_REF,
 +        [value, refs],
 +      )
 +    }
 +
 +    invokeRefSetter(refValue)
 +    onScopeDispose(() => invokeRefSetter())
 +  } else {
 +    const _isString = isString(ref)
 +    const _isRef = isRef(ref)
 +    let existing: unknown
 +
 +    if (_isString || _isRef) {
 +      const doSet: SchedulerJob = () => {
 +        if (refFor) {
 +          existing = _isString
 +            ? hasOwn(setupState, ref)
 +              ? setupState[ref]
 +              : refs[ref]
 +            : ref.value
 +
 +          if (!isArray(existing)) {
 +            existing = [refValue]
 +            if (_isString) {
 +              refs[ref] = existing
 +              if (hasOwn(setupState, ref)) {
 +                setupState[ref] = refs[ref]
 +                // if setupState[ref] is a reactivity ref,
 +                // the existing will also become reactivity too
 +                // need to get the Proxy object by resetting
 +                existing = setupState[ref]
 +              }
 +            } else {
 +              ref.value = existing
 +            }
 +          } else if (!existing.includes(refValue)) {
 +            existing.push(refValue)
 +          }
 +        } else if (_isString) {
 +          refs[ref] = refValue
 +          if (hasOwn(setupState, ref)) {
 +            setupState[ref] = refValue
 +          }
 +        } else if (_isRef) {
 +          ref.value = refValue
 +        } else if (__DEV__) {
 +          warn('Invalid template ref type:', ref, `(${typeof ref})`)
 +        }
 +      }
 +      doSet.id = -1
 +      queuePostFlushCb(doSet)
 +
 +      onScopeDispose(() => {
 +        queuePostFlushCb(() => {
 +          if (isArray(existing)) {
 +            remove(existing, refValue)
 +          } else if (_isString) {
 +            refs[ref] = null
 +            if (hasOwn(setupState, ref)) {
 +              setupState[ref] = null
 +            }
 +          } else if (_isRef) {
 +            ref.value = null
 +          }
 +        })
 +      })
 +    } else if (__DEV__) {
 +      warn('Invalid template ref type:', ref, `(${typeof ref})`)
 +    }
 +  }
 +  return ref
 +}
index 1234b6e6c57125cfac42344610b5c009a460e822,0000000000000000000000000000000000000000..7057454872dd9e85d089ee0c83de026297a362c7
mode 100644,000000..100644
--- /dev/null
@@@ -1,169 -1,0 +1,162 @@@
- import {
-   BaseWatchErrorCodes,
-   pauseTracking,
-   resetTracking,
- } from '@vue/reactivity'
 +// These codes originate from a file of the same name in runtime-core,
 +// duplicated during Vapor's early development to ensure its independence.
 +// The ultimate aim is to uncouple this replicated code and
 +// facilitate its shared use between two runtimes.
 +
 +import type { ComponentInternalInstance } from './component'
 +import { isFunction, isPromise } from '@vue/shared'
 +import { warn } from './warning'
 +import { VaporLifecycleHooks } from './enums'
- export type ErrorTypes =
-   | VaporLifecycleHooks
-   | VaporErrorCodes
-   | BaseWatchErrorCodes
++import { WatchErrorCodes, pauseTracking, resetTracking } from '@vue/reactivity'
 +
 +// contexts where user provided function may be executed, in addition to
 +// lifecycle hooks.
 +export enum VaporErrorCodes {
 +  SETUP_FUNCTION,
 +  RENDER_FUNCTION,
 +  // The error codes for the watch have been transferred to the reactivity
 +  // package along with baseWatch to maintain code compatibility. Hence,
 +  // it is essential to keep these values unchanged.
 +  // WATCH_GETTER,
 +  // WATCH_CALLBACK,
 +  // WATCH_CLEANUP,
 +  NATIVE_EVENT_HANDLER = 5,
 +  COMPONENT_EVENT_HANDLER,
 +  VNODE_HOOK,
 +  DIRECTIVE_HOOK,
 +  TRANSITION_HOOK,
 +  APP_ERROR_HANDLER,
 +  APP_WARN_HANDLER,
 +  FUNCTION_REF,
 +  ASYNC_COMPONENT_LOADER,
 +  SCHEDULER,
 +}
 +
-   [BaseWatchErrorCodes.WATCH_GETTER]: 'watcher getter',
-   [BaseWatchErrorCodes.WATCH_CALLBACK]: 'watcher callback',
-   [BaseWatchErrorCodes.WATCH_CLEANUP]: 'watcher cleanup function',
++export type ErrorTypes = VaporLifecycleHooks | VaporErrorCodes | WatchErrorCodes
 +
 +export const ErrorTypeStrings: Record<ErrorTypes, string> = {
 +  // [VaporLifecycleHooks.SERVER_PREFETCH]: 'serverPrefetch hook',
 +  [VaporLifecycleHooks.BEFORE_MOUNT]: 'beforeMount hook',
 +  [VaporLifecycleHooks.MOUNTED]: 'mounted hook',
 +  [VaporLifecycleHooks.BEFORE_UPDATE]: 'beforeUpdate hook',
 +  [VaporLifecycleHooks.UPDATED]: 'updated',
 +  [VaporLifecycleHooks.BEFORE_UNMOUNT]: 'beforeUnmount hook',
 +  [VaporLifecycleHooks.UNMOUNTED]: 'unmounted hook',
 +  [VaporLifecycleHooks.ACTIVATED]: 'activated hook',
 +  [VaporLifecycleHooks.DEACTIVATED]: 'deactivated hook',
 +  [VaporLifecycleHooks.ERROR_CAPTURED]: 'errorCaptured hook',
 +  [VaporLifecycleHooks.RENDER_TRACKED]: 'renderTracked hook',
 +  [VaporLifecycleHooks.RENDER_TRIGGERED]: 'renderTriggered hook',
 +  [VaporErrorCodes.SETUP_FUNCTION]: 'setup function',
 +  [VaporErrorCodes.RENDER_FUNCTION]: 'render function',
++  [WatchErrorCodes.WATCH_GETTER]: 'watcher getter',
++  [WatchErrorCodes.WATCH_CALLBACK]: 'watcher callback',
++  [WatchErrorCodes.WATCH_CLEANUP]: 'watcher cleanup function',
 +  [VaporErrorCodes.NATIVE_EVENT_HANDLER]: 'native event handler',
 +  [VaporErrorCodes.COMPONENT_EVENT_HANDLER]: 'component event handler',
 +  [VaporErrorCodes.VNODE_HOOK]: 'vnode hook',
 +  [VaporErrorCodes.DIRECTIVE_HOOK]: 'directive hook',
 +  [VaporErrorCodes.TRANSITION_HOOK]: 'transition hook',
 +  [VaporErrorCodes.APP_ERROR_HANDLER]: 'app errorHandler',
 +  [VaporErrorCodes.APP_WARN_HANDLER]: 'app warnHandler',
 +  [VaporErrorCodes.FUNCTION_REF]: 'ref function',
 +  [VaporErrorCodes.ASYNC_COMPONENT_LOADER]: 'async component loader',
 +  [VaporErrorCodes.SCHEDULER]:
 +    'scheduler flush. This is likely a Vue internals bug. ' +
 +    'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core',
 +}
 +
 +export function callWithErrorHandling(
 +  fn: Function,
 +  instance: ComponentInternalInstance | null,
 +  type: ErrorTypes,
 +  args?: unknown[],
 +): any {
 +  let res
 +  try {
 +    res = args ? fn(...args) : fn()
 +  } catch (err) {
 +    handleError(err, instance, type)
 +  }
 +  return res
 +}
 +
 +export function callWithAsyncErrorHandling<F extends Function | Function[]>(
 +  fn: F,
 +  instance: ComponentInternalInstance | null,
 +  type: ErrorTypes,
 +  args?: unknown[],
 +): F extends Function ? any : any[] {
 +  if (isFunction(fn)) {
 +    const res = callWithErrorHandling(fn, instance, type, args)
 +    if (res && isPromise(res)) {
 +      res.catch(err => {
 +        handleError(err, instance, type)
 +      })
 +    }
 +    return res
 +  }
 +
 +  const values = []
 +  for (let i = 0; i < fn.length; i++) {
 +    values.push(callWithAsyncErrorHandling(fn[i], instance, type, args))
 +  }
 +  return values
 +}
 +
 +export function handleError(
 +  err: unknown,
 +  instance: ComponentInternalInstance | null,
 +  type: ErrorTypes,
 +  throwInDev = true,
 +): void {
 +  if (instance) {
 +    let cur = instance.parent
 +    // in production the hook receives only the error code
 +    const errorInfo = __DEV__
 +      ? ErrorTypeStrings[type]
 +      : `https://vuejs.org/errors/#runtime-${type}`
 +    while (cur) {
 +      const errorCapturedHooks = 'ec' in cur ? cur.ec : null
 +      if (errorCapturedHooks) {
 +        for (let i = 0; i < errorCapturedHooks.length; i++) {
 +          if (errorCapturedHooks[i](err, instance, errorInfo) === false) {
 +            return
 +          }
 +        }
 +      }
 +      cur = cur.parent
 +    }
 +
 +    // app-level handling
 +    const appErrorHandler = instance.appContext.config.errorHandler
 +    if (appErrorHandler) {
 +      pauseTracking()
 +      callWithErrorHandling(
 +        appErrorHandler,
 +        null,
 +        VaporErrorCodes.APP_ERROR_HANDLER,
 +        [err, instance, errorInfo],
 +      )
 +      resetTracking()
 +      return
 +    }
 +  }
 +  logError(err, type, throwInDev)
 +}
 +
 +function logError(err: unknown, type: ErrorTypes, throwInDev = true) {
 +  if (__DEV__) {
 +    const info = ErrorTypeStrings[type]
 +    warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`)
 +    // crash in dev by default so it's more noticeable
 +    if (throwInDev) {
 +      throw err
 +    } else if (!__TEST__) {
 +      console.error(err)
 +    }
 +  } else {
 +    // recover in prod to reduce the impact on end-user
 +    console.error(err)
 +  }
 +}
index 9157d456ba8ec9451d861fcb09720ba13707e23d,0000000000000000000000000000000000000000..35677da6926c2fba5fefb89b963691fe8363f5ed
mode 100644,000000..100644
--- /dev/null
@@@ -1,162 -1,0 +1,162 @@@
-   type Component,
 +// Core API ------------------------------------------------------------------
 +
 +export const version: string = __VERSION__
 +export {
 +  // core
 +  type Ref,
 +  type DebuggerEvent,
 +  TrackOpTypes,
 +  TriggerOpTypes,
 +  reactive,
 +  ref,
 +  readonly,
 +  computed,
 +  // utilities
 +  unref,
 +  proxyRefs,
 +  isRef,
 +  toRef,
 +  toValue,
 +  toRefs,
 +  isProxy,
 +  isReactive,
 +  isReadonly,
 +  isShallow,
 +  // advanced
 +  customRef,
 +  triggerRef,
 +  shallowRef,
 +  shallowReactive,
 +  shallowReadonly,
 +  markRaw,
 +  toRaw,
 +  // effect
 +  stop,
 +  ReactiveEffect,
 +  onEffectCleanup,
 +  // effect scope
 +  effectScope,
 +  EffectScope,
 +  getCurrentScope,
 +  onScopeDispose,
 +  // baseWatch
 +  onWatcherCleanup,
 +  getCurrentWatcher,
 +} from '@vue/reactivity'
 +
 +import { NOOP } from '@vue/shared'
 +import { warn as _warn } from './warning'
 +export const warn = (__DEV__ ? _warn : NOOP) as typeof _warn
 +
 +export { nextTick } from './scheduler'
 +export {
 +  getCurrentInstance,
 +  type ComponentInternalInstance,
++  type Component as Component,
 +  type ObjectComponent,
 +  type FunctionalComponent,
 +  type SetupFn,
 +} from './component'
 +export { createSlot } from './componentSlots'
 +export { renderEffect } from './renderEffect'
 +export {
 +  watch,
 +  watchEffect,
 +  watchPostEffect,
 +  watchSyncEffect,
 +  type WatchEffect,
 +  type WatchOptions,
 +  type WatchOptionsBase,
 +  type WatchCallback,
 +  type WatchSource,
 +  type WatchStopHandle,
 +} from './apiWatch'
 +export {
 +  withDirectives,
 +  type Directive,
 +  type DirectiveBinding,
 +  type DirectiveHook,
 +  type ObjectDirective,
 +  type FunctionDirective,
 +  type DirectiveArguments,
 +  type DirectiveModifiers,
 +} from './directives'
 +
 +export { template, children, next } from './dom/template'
 +export { insert, prepend, remove, createTextNode } from './dom/element'
 +export { setStyle } from './dom/style'
 +export {
 +  setText,
 +  setHtml,
 +  setClass,
 +  setAttr,
 +  setDOMProp,
 +  setDynamicProp,
 +  setDynamicProps,
 +} from './dom/prop'
 +export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
 +export { setRef } from './dom/templateRef'
 +
 +export { defineComponent } from './apiDefineComponent'
 +export {
 +  type InjectionKey,
 +  inject,
 +  provide,
 +  hasInjectionContext,
 +} from './apiInject'
 +export {
 +  onBeforeMount,
 +  onMounted,
 +  onBeforeUpdate,
 +  onUpdated,
 +  onBeforeUnmount,
 +  onUnmounted,
 +  // onActivated,
 +  // onDeactivated,
 +  onRenderTracked,
 +  onRenderTriggered,
 +  onErrorCaptured,
 +  // onServerPrefetch,
 +} from './apiLifecycle'
 +export { useAttrs, useSlots } from './apiSetupHelpers'
 +export {
 +  createVaporApp,
 +  type App,
 +  type AppConfig,
 +  type AppContext,
 +  type Plugin,
 +  type ObjectPlugin,
 +  type FunctionPlugin,
 +} from './apiCreateVaporApp'
 +export { createIf } from './apiCreateIf'
 +export { createFor, createForSlots } from './apiCreateFor'
 +export { createComponent } from './apiCreateComponent'
 +
 +export { resolveComponent, resolveDirective } from './helpers/resolveAssets'
 +export { toHandlers } from './helpers/toHandlers'
 +
 +export { withDestructure } from './destructure'
 +
 +// **Internal** DOM-only runtime directive helpers
 +export {
 +  vModelText,
 +  vModelCheckbox,
 +  vModelRadio,
 +  vModelSelect,
 +  vModelDynamic,
 +} from './directives/vModel'
 +export { vShow } from './directives/vShow'
 +
 +// For devtools
 +import {
 +  type DevtoolsHook,
 +  devtools as _devtools,
 +  setDevtoolsHook as _setDevtoolsHook,
 +} from './devtools'
 +
 +export const devtools = (
 +  __DEV__ || __ESM_BUNDLER__ ? _devtools : undefined
 +) as DevtoolsHook
 +export const setDevtoolsHook = (
 +  __DEV__ || __ESM_BUNDLER__ ? _setDevtoolsHook : NOOP
 +) as typeof _setDevtoolsHook
index 372ca74be4552b3f6e46d2cea5dd5cf9e0d42df9,0000000000000000000000000000000000000000..e95e9df30083191c5251eadcfa2eb7025668697a
mode 100644,000000..100644
--- /dev/null
@@@ -1,104 -1,0 +1,103 @@@
- import {
-   EffectFlags,
-   ReactiveEffect,
-   type SchedulerJob,
-   SchedulerJobFlags,
-   getCurrentScope,
- } from '@vue/reactivity'
++import { EffectFlags, ReactiveEffect, getCurrentScope } from '@vue/reactivity'
 +import { invokeArrayFns } from '@vue/shared'
 +import {
 +  type ComponentInternalInstance,
 +  getCurrentInstance,
 +  setCurrentInstance,
 +} from './component'
- import { queueJob, queuePostFlushCb } from './scheduler'
++import {
++  type SchedulerJob,
++  VaporSchedulerJobFlags,
++  queueJob,
++  queuePostFlushCb,
++} from './scheduler'
 +import { VaporErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
 +import { invokeDirectiveHook } from './directives'
 +
 +export function renderEffect(cb: () => void): void {
 +  const instance = getCurrentInstance()
 +  const scope = getCurrentScope()
 +
 +  if (scope) {
 +    const baseCb = cb
 +    cb = () => scope.run(baseCb)
 +  }
 +
 +  if (instance) {
 +    const baseCb = cb
 +    cb = () => {
 +      const reset = setCurrentInstance(instance)
 +      baseCb()
 +      reset()
 +    }
 +    job.id = instance.uid
 +  }
 +
 +  const effect = new ReactiveEffect(() =>
 +    callWithAsyncErrorHandling(cb, instance, VaporErrorCodes.RENDER_FUNCTION),
 +  )
 +
 +  effect.scheduler = () => queueJob(job)
 +  if (__DEV__ && instance) {
 +    effect.onTrack = instance.rtc
 +      ? e => invokeArrayFns(instance.rtc!, e)
 +      : void 0
 +    effect.onTrigger = instance.rtg
 +      ? e => invokeArrayFns(instance.rtg!, e)
 +      : void 0
 +  }
 +  effect.run()
 +
 +  function job() {
 +    if (!(effect.flags & EffectFlags.ACTIVE) || !effect.dirty) {
 +      return
 +    }
 +
 +    const reset = instance && setCurrentInstance(instance)
 +
 +    if (instance && instance.isMounted && !instance.isUpdating) {
 +      instance.isUpdating = true
 +
 +      const { bu, u, scope } = instance
 +      const { dirs } = scope
 +      // beforeUpdate hook
 +      if (bu) {
 +        invokeArrayFns(bu)
 +      }
 +      if (dirs) {
 +        invokeDirectiveHook(instance, 'beforeUpdate', scope)
 +      }
 +
 +      effect.run()
 +
 +      queuePostFlushCb(() => {
 +        instance.isUpdating = false
 +        const reset = setCurrentInstance(instance)
 +        if (dirs) {
 +          invokeDirectiveHook(instance, 'updated', scope)
 +        }
 +        // updated hook
 +        if (u) {
 +          queuePostFlushCb(u)
 +        }
 +        reset()
 +      })
 +    } else {
 +      effect.run()
 +    }
 +
 +    reset && reset()
 +  }
 +}
 +
 +export function firstEffect(
 +  instance: ComponentInternalInstance,
 +  fn: () => void,
 +): void {
 +  const effect = new ReactiveEffect(fn)
 +  const job: SchedulerJob = () => effect.run()
-   job.flags! |= SchedulerJobFlags.PRE
++  job.flags! |= VaporSchedulerJobFlags.PRE
 +  job.id = instance.uid
 +  effect.scheduler = () => queueJob(job)
 +  effect.run()
 +}
index 85b2be363d97c7fadab64431387ba3eafffad702,0000000000000000000000000000000000000000..5b3a1e93ad6e70af0c305f62e89853c71bd0b6da
mode 100644,000000..100644
--- /dev/null
@@@ -1,224 -1,0 +1,225 @@@
- import {
-   EffectFlags,
-   type SchedulerJob,
-   SchedulerJobFlags,
-   type WatchScheduler,
- } from '@vue/reactivity'
++import type { WatchScheduler } from '@vue/reactivity'
 +import type { ComponentInternalInstance } from './component'
 +import { isArray } from '@vue/shared'
 +
++export enum VaporSchedulerJobFlags {
++  QUEUED = 1 << 0,
++  PRE = 1 << 1,
++  /**
++   * Indicates whether the effect is allowed to recursively trigger itself
++   * when managed by the scheduler.
++   *
++   * By default, a job cannot trigger itself because some built-in method calls,
++   * e.g. Array.prototype.push actually performs reads as well (#1740) which
++   * can lead to confusing infinite loops.
++   * The allowed cases are component update functions and watch callbacks.
++   * Component update functions may update child component props, which in turn
++   * trigger flush: "pre" watch callbacks that mutates state that the parent
++   * relies on (#1801). Watch callbacks doesn't track its dependencies so if it
++   * triggers itself again, it's likely intentional and it is the user's
++   * responsibility to perform recursive state mutation that eventually
++   * stabilizes (#1727).
++   */
++  ALLOW_RECURSE = 1 << 2,
++  DISPOSED = 1 << 3,
++}
++
++export interface SchedulerJob extends Function {
++  id?: number
++  /**
++   * flags can technically be undefined, but it can still be used in bitwise
++   * operations just like 0.
++   */
++  flags?: VaporSchedulerJobFlags
++  /**
++   * Attached by renderer.ts when setting up a component's render effect
++   * Used to obtain component information when reporting max recursive updates.
++   */
++  i?: ComponentInternalInstance
++}
++
 +export type SchedulerJobs = SchedulerJob | SchedulerJob[]
 +export type QueueEffect = (
 +  cb: SchedulerJobs,
 +  suspense: ComponentInternalInstance | null,
 +) => void
 +
 +let isFlushing = false
 +let isFlushPending = false
 +
 +// TODO: The queues in Vapor need to be merged with the queues in Core.
 +//       this is a temporary solution, the ultimate goal is to support
 +//       the mixed use of vapor components and default components.
 +const queue: SchedulerJob[] = []
 +let flushIndex = 0
 +
 +// TODO: The queues in Vapor need to be merged with the queues in Core.
 +//       this is a temporary solution, the ultimate goal is to support
 +//       the mixed use of vapor components and default components.
 +const pendingPostFlushCbs: SchedulerJob[] = []
 +let activePostFlushCbs: SchedulerJob[] | null = null
 +let postFlushIndex = 0
 +
 +const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise<any>
 +let currentFlushPromise: Promise<void> | null = null
 +
 +export function queueJob(job: SchedulerJob): void {
 +  let lastOne: SchedulerJob | undefined
-   if (!(job.flags! & SchedulerJobFlags.QUEUED)) {
++  if (!(job.flags! & VaporSchedulerJobFlags.QUEUED)) {
 +    if (job.id == null) {
 +      queue.push(job)
 +    } else if (
 +      // fast path when the job id is larger than the tail
-       !(job.flags! & SchedulerJobFlags.PRE) &&
++      !(job.flags! & VaporSchedulerJobFlags.PRE) &&
 +      job.id >= (((lastOne = queue[queue.length - 1]) && lastOne.id) || 0)
 +    ) {
 +      queue.push(job)
 +    } else {
 +      queue.splice(findInsertionIndex(job.id), 0, job)
 +    }
 +
-     if (!(job.flags! & SchedulerJobFlags.ALLOW_RECURSE)) {
-       job.flags! |= SchedulerJobFlags.QUEUED
++    if (!(job.flags! & VaporSchedulerJobFlags.ALLOW_RECURSE)) {
++      job.flags! |= VaporSchedulerJobFlags.QUEUED
 +    }
 +    queueFlush()
 +  }
 +}
 +
 +export function queuePostFlushCb(cb: SchedulerJobs): void {
 +  if (!isArray(cb)) {
-     if (!(cb.flags! & SchedulerJobFlags.QUEUED)) {
++    if (!(cb.flags! & VaporSchedulerJobFlags.QUEUED)) {
 +      pendingPostFlushCbs.push(cb)
-       if (!(cb.flags! & SchedulerJobFlags.ALLOW_RECURSE)) {
-         cb.flags! |= SchedulerJobFlags.QUEUED
++      if (!(cb.flags! & VaporSchedulerJobFlags.ALLOW_RECURSE)) {
++        cb.flags! |= VaporSchedulerJobFlags.QUEUED
 +      }
 +    }
 +  } else {
 +    // if cb is an array, it is a component lifecycle hook which can only be
 +    // triggered by a job, which is already deduped in the main queue, so
 +    // we can skip duplicate check here to improve perf
 +    pendingPostFlushCbs.push(...cb)
 +  }
 +  queueFlush()
 +}
 +
 +function queueFlush() {
 +  if (!isFlushing && !isFlushPending) {
 +    isFlushPending = true
 +    currentFlushPromise = resolvedPromise.then(flushJobs)
 +  }
 +}
 +
 +export function flushPostFlushCbs(): void {
 +  if (!pendingPostFlushCbs.length) return
 +
 +  const deduped = [...new Set(pendingPostFlushCbs)]
 +  pendingPostFlushCbs.length = 0
 +
 +  // #1947 already has active queue, nested flushPostFlushCbs call
 +  if (activePostFlushCbs) {
 +    activePostFlushCbs.push(...deduped)
 +    return
 +  }
 +
 +  activePostFlushCbs = deduped
 +
 +  activePostFlushCbs.sort((a, b) => getId(a) - getId(b))
 +
 +  for (
 +    postFlushIndex = 0;
 +    postFlushIndex < activePostFlushCbs.length;
 +    postFlushIndex++
 +  ) {
 +    activePostFlushCbs[postFlushIndex]()
-     activePostFlushCbs[postFlushIndex].flags! &= ~SchedulerJobFlags.QUEUED
++    activePostFlushCbs[postFlushIndex].flags! &= ~VaporSchedulerJobFlags.QUEUED
 +  }
 +  activePostFlushCbs = null
 +  postFlushIndex = 0
 +}
 +
 +// TODO: dev mode and checkRecursiveUpdates
 +function flushJobs() {
 +  isFlushPending = false
 +  isFlushing = true
 +
 +  // Sort queue before flush.
 +  // This ensures that:
 +  // 1. Components are updated from parent to child. (because parent is always
 +  //    created before the child so its render effect will have smaller
 +  //    priority number)
 +  // 2. If a component is unmounted during a parent component's update,
 +  //    its update can be skipped.
 +  queue.sort(comparator)
 +
 +  try {
 +    for (let i = 0; i < queue!.length; i++) {
 +      queue[i]()
-       queue[i].flags! &= ~SchedulerJobFlags.QUEUED
++      queue[i].flags! &= ~VaporSchedulerJobFlags.QUEUED
 +    }
 +  } finally {
 +    flushIndex = 0
 +    queue.length = 0
 +
 +    flushPostFlushCbs()
 +
 +    isFlushing = false
 +    currentFlushPromise = null
 +    // some postFlushCb queued jobs!
 +    // keep flushing until it drains.
 +    if (queue.length || pendingPostFlushCbs.length) {
 +      flushJobs()
 +    }
 +  }
 +}
 +
 +export function nextTick<T = void, R = void>(
 +  this: T,
 +  fn?: (this: T) => R,
 +): Promise<Awaited<R>> {
 +  const p = currentFlushPromise || resolvedPromise
 +  return fn ? p.then(this ? fn.bind(this) : fn) : p
 +}
 +
 +// #2768
 +// Use binary-search to find a suitable position in the queue,
 +// so that the queue maintains the increasing order of job's id,
 +// which can prevent the job from being skipped and also can avoid repeated patching.
 +function findInsertionIndex(id: number) {
 +  // the start index should be `flushIndex + 1`
 +  let start = flushIndex + 1
 +  let end = queue.length
 +
 +  while (start < end) {
 +    const middle = (start + end) >>> 1
 +    const middleJob = queue[middle]
 +    const middleJobId = getId(middleJob)
 +    if (
 +      middleJobId < id ||
-       (middleJobId === id && middleJob.flags! & SchedulerJobFlags.PRE)
++      (middleJobId === id && middleJob.flags! & VaporSchedulerJobFlags.PRE)
 +    ) {
 +      start = middle + 1
 +    } else {
 +      end = middle
 +    }
 +  }
 +
 +  return start
 +}
 +
 +const getId = (job: SchedulerJob): number =>
 +  job.id == null ? Infinity : job.id
 +
 +const comparator = (a: SchedulerJob, b: SchedulerJob): number => {
 +  const diff = getId(a) - getId(b)
 +  if (diff === 0) {
-     const isAPre = a.flags! & SchedulerJobFlags.PRE
-     const isBPre = b.flags! & SchedulerJobFlags.PRE
++    const isAPre = a.flags! & VaporSchedulerJobFlags.PRE
++    const isBPre = b.flags! & VaporSchedulerJobFlags.PRE
 +    if (isAPre && !isBPre) return -1
 +    if (isBPre && !isAPre) return 1
 +  }
 +  return diff
 +}
 +
 +export type SchedulerFactory = (
 +  instance: ComponentInternalInstance | null,
 +) => WatchScheduler
- export const createVaporSyncScheduler: SchedulerFactory =
-   instance => (job, effect, immediateFirstRun, hasCb) => {
-     if (immediateFirstRun) {
-       effect.flags |= EffectFlags.NO_BATCH
-       if (!hasCb) effect.run()
-     } else {
-       job()
-     }
-   }
- export const createVaporPreScheduler: SchedulerFactory =
-   instance => (job, effect, immediateFirstRun, hasCb) => {
-     if (!immediateFirstRun) {
-       job.flags! |= SchedulerJobFlags.PRE
-       if (instance) job.id = instance.uid
-       queueJob(job)
-     } else if (!hasCb) {
-       effect.run()
-     }
-   }
- export const createVaporPostScheduler: SchedulerFactory =
-   instance => (job, effect, immediateFirstRun, hasCb) => {
-     if (!immediateFirstRun) {
-       queuePostFlushCb(job)
-     } else if (!hasCb) {
-       queuePostFlushCb(effect.run.bind(effect))
-     }
-   }
Simple merge
Simple merge
index af318cd8d08c72eeebb06ca3b2f0de63303c6b1f,552b447064cc25e4b43e2dc5b4e1920241aaa16f..6ec7311f6341e3b87659fa3daf7998ea72c4b9b7
@@@ -95,11 -88,8 +95,11 @@@ export const isReservedProp: (key: stri
      'onVnodeBeforeUnmount,onVnodeUnmounted',
  )
  
 +export const isBuiltInTag: (key: string) => boolean =
 +  /*#__PURE__*/ makeMap('slot,component')
 +
  export const isBuiltInDirective: (key: string) => boolean =
-   /*#__PURE__*/ makeMap(
+   /*@__PURE__*/ makeMap(
      'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo',
    )
  
Simple merge
index 6e98ffc1de323979c49ba91e19628b1cb6690a8a,0000000000000000000000000000000000000000..8512dcaae474198681a085beebdfdf2d50f407b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,181 -1,0 +1,209 @@@
- export const E2E_TIMEOUT = 30 * 1000
 +import puppeteer, {
 +  type Browser,
 +  type ClickOptions,
 +  type Page,
 +  type PuppeteerLaunchOptions,
 +} from 'puppeteer'
 +
- export const timeout = (n: number) => new Promise(r => setTimeout(r, n))
++export const E2E_TIMEOUT: number = 30 * 1000
 +
 +const puppeteerOptions: PuppeteerLaunchOptions = {
 +  args: process.env.CI ? ['--no-sandbox', '--disable-setuid-sandbox'] : [],
 +  headless: true,
 +}
 +
 +const maxTries = 30
- ) {
++export const timeout = (n: number): Promise<any> =>
++  new Promise(r => setTimeout(r, n))
 +
 +export async function expectByPolling(
 +  poll: () => Promise<any>,
 +  expected: string,
- export function setupPuppeteer() {
++): Promise<void> {
 +  for (let tries = 0; tries < maxTries; tries++) {
 +    const actual = (await poll()) || ''
 +    if (actual.indexOf(expected) > -1 || tries === maxTries - 1) {
 +      expect(actual).toMatch(expected)
 +      break
 +    } else {
 +      await timeout(50)
 +    }
 +  }
 +}
 +
-     browser = await puppeteer.launch(puppeteerOptions)
++interface PuppeteerUtils {
++  page: () => Page
++  click(selector: string, options?: ClickOptions): Promise<void>
++  count(selector: string): Promise<number>
++  text(selector: string): Promise<string | null>
++  value(selector: string): Promise<string>
++  html(selector: string): Promise<string>
++  classList(selector: string): Promise<string[]>
++  children(selector: string): Promise<any[]>
++  isVisible(selector: string): Promise<boolean>
++  isChecked(selector: string): Promise<boolean>
++  isFocused(selector: string): Promise<boolean>
++  setValue(selector: string, value: string): Promise<any>
++  typeValue(selector: string, value: string): Promise<any>
++  enterValue(selector: string, value: string): Promise<any>
++  clearValue(selector: string): Promise<any>
++  timeout(time: number): Promise<any>
++  nextFrame(): Promise<any>
++}
++
++export function setupPuppeteer(args?: string[]): PuppeteerUtils {
 +  let browser: Browser
 +  let page: Page
 +
++  const resolvedOptions = args
++    ? {
++        ...puppeteerOptions,
++        args: [...puppeteerOptions.args!, ...args],
++      }
++    : puppeteerOptions
++
 +  beforeAll(async () => {
-         console.error(
-           `Error from Puppeteer-loaded page:\n`,
-           err.remoteObject().description,
-         )
++    browser = await puppeteer.launch(resolvedOptions)
 +  }, 20000)
 +
 +  beforeEach(async () => {
 +    page = await browser.newPage()
 +
 +    await page.evaluateOnNewDocument(() => {
 +      localStorage.clear()
 +    })
 +
 +    page.on('console', e => {
 +      if (e.type() === 'error') {
 +        const err = e.args()[0]
-   async function click(selector: string, options?: ClickOptions) {
++        console.error(`Error from Puppeteer-loaded page:\n`, err.remoteObject())
 +      }
 +    })
 +  })
 +
 +  afterEach(async () => {
 +    await page.close()
 +  })
 +
 +  afterAll(async () => {
 +    await browser.close()
 +  })
 +
-   async function count(selector: string) {
++  async function click(
++    selector: string,
++    options?: ClickOptions,
++  ): Promise<void> {
 +    await page.click(selector, options)
 +  }
 +
-   async function text(selector: string) {
-     return await page.$eval(selector, node => node.textContent)
++  async function count(selector: string): Promise<number> {
 +    return (await page.$$(selector)).length
 +  }
 +
-   async function value(selector: string) {
-     return await page.$eval(selector, node => (node as HTMLInputElement).value)
++  async function text(selector: string): Promise<string | null> {
++    return page.$eval(selector, node => node.textContent)
 +  }
 +
-   async function html(selector: string) {
-     return await page.$eval(selector, node => node.innerHTML)
++  async function value(selector: string): Promise<string> {
++    return page.$eval(selector, node => (node as HTMLInputElement).value)
 +  }
 +
-   async function classList(selector: string) {
-     return await page.$eval(selector, (node: any) => [...node.classList])
++  async function html(selector: string): Promise<string> {
++    return page.$eval(selector, node => node.innerHTML)
 +  }
 +
-   async function children(selector: string) {
-     return await page.$eval(selector, (node: any) => [...node.children])
++  async function classList(selector: string): Promise<string[]> {
++    return page.$eval(selector, (node: any) => [...node.classList])
 +  }
 +
-   async function isVisible(selector: string) {
++  async function children(selector: string): Promise<any[]> {
++    return page.$eval(selector, (node: any) => [...node.children])
 +  }
 +
++  async function isVisible(selector: string): Promise<boolean> {
 +    const display = await page.$eval(selector, node => {
 +      return window.getComputedStyle(node).display
 +    })
 +    return display !== 'none'
 +  }
 +
 +  async function isChecked(selector: string) {
 +    return await page.$eval(
 +      selector,
 +      node => (node as HTMLInputElement).checked,
 +    )
 +  }
 +
 +  async function isFocused(selector: string) {
 +    return await page.$eval(selector, node => node === document.activeElement)
 +  }
 +
 +  async function setValue(selector: string, value: string) {
 +    await page.$eval(
 +      selector,
 +      (node, value) => {
 +        ;(node as HTMLInputElement).value = value as string
 +        node.dispatchEvent(new Event('input'))
 +      },
 +      value,
 +    )
 +  }
 +
 +  async function typeValue(selector: string, value: string) {
 +    const el = (await page.$(selector))!
 +    await el.evaluate(node => ((node as HTMLInputElement).value = ''))
 +    await el.type(value)
 +  }
 +
 +  async function enterValue(selector: string, value: string) {
 +    const el = (await page.$(selector))!
 +    await el.evaluate(node => ((node as HTMLInputElement).value = ''))
 +    await el.type(value)
 +    await el.press('Enter')
 +  }
 +
 +  async function clearValue(selector: string) {
 +    return await page.$eval(
 +      selector,
 +      node => ((node as HTMLInputElement).value = ''),
 +    )
 +  }
 +
 +  function timeout(time: number) {
 +    return page.evaluate(time => {
 +      return new Promise(r => {
 +        setTimeout(r, time)
 +      })
 +    }, time)
 +  }
 +
 +  function nextFrame() {
 +    return page.evaluate(() => {
 +      return new Promise(resolve => {
 +        requestAnimationFrame(() => {
 +          requestAnimationFrame(resolve)
 +        })
 +      })
 +    })
 +  }
 +
 +  return {
 +    page: () => page,
 +    click,
 +    count,
 +    text,
 +    value,
 +    html,
 +    classList,
 +    children,
 +    isVisible,
 +    isChecked,
 +    isFocused,
 +    setValue,
 +    typeValue,
 +    enterValue,
 +    clearValue,
 +    timeout,
 +    nextFrame,
 +  }
 +}
Simple merge
index 58677200c78986f9ffa18e833538b0b3fe5f0398,0000000000000000000000000000000000000000..c65d9c2ec395b1502999f7a473ecc08f10902ded
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,18 @@@
++/// <reference types="vite/client" />
++
 +import { createVaporApp } from 'vue/vapor'
 +import { createApp } from 'vue'
 +import './style.css'
 +
 +const modules = import.meta.glob<any>('./**/*.(vue|js)')
 +const mod = (modules['.' + location.pathname] || modules['./App.vue'])()
 +
 +mod.then(({ default: mod }) => {
 +  const app = (mod.vapor ? createVaporApp : createApp)(mod)
 +  app.mount('#app')
 +
 +  // @ts-expect-error
 +  globalThis.unmount = () => {
 +    app.unmount()
 +  }
 +})
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f09c7e5406e4913e1429a94f05acd5389cb751b7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++{
++  "extends": "../tsconfig.json",
++  "compilerOptions": {
++    "isolatedDeclarations": false,
++    "allowJs": true
++  },
++  "include": ["**/*"]
++}
diff --cc pnpm-lock.yaml
index 090e8773c292858e34f3b57e8201ad701d98d66e,5b9eba0248ee3fb928915458b0e1a2d93ad2f63d..61f275c0f559f3e7980aa082754a769c68841395
@@@ -20,7 -23,7 +23,7 @@@ catalogs
        version: 0.30.11
      source-map-js:
        specifier: ^1.2.0
--      version: 1.2.0
++      version: 1.2.1
      vite:
        specifier: ^5.4.0
        version: 5.4.0
@@@ -65,12 -68,9 +68,12 @@@ importers
        '@types/serve-handler':
          specifier: ^6.1.4
          version: 6.1.4
-       '@vitest/coverage-istanbul':
-         specifier: ^1.6.0
-         version: 1.6.0(vitest@1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6))
+       '@vitest/coverage-v8':
+         specifier: ^2.1.1
 -        version: 2.1.1(vitest@2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0))
++        version: 2.1.1(vitest@2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6))
 +      '@vitest/ui':
-         specifier: ^1.6.0
-         version: 1.6.0(vitest@1.6.0)
++        specifier: ^2.1.1
++        version: 2.1.1(vitest@2.1.1)
        '@vue/consolidate':
          specifier: 1.0.0
          version: 1.0.0
          specifier: ^2.4.1
          version: 2.4.1
        esbuild:
-         specifier: ^0.23.0
-         version: 0.23.0
+         specifier: ^0.23.1
+         version: 0.23.1
        esbuild-plugin-polyfill-node:
          specifier: ^0.3.0
-         version: 0.3.0(esbuild@0.23.0)
+         version: 0.3.0(esbuild@0.23.1)
        eslint:
-         specifier: ^9.8.0
-         version: 9.8.0
+         specifier: ^9.10.0
+         version: 9.10.0
        eslint-plugin-import-x:
-         specifier: ^3.1.0
-         version: 3.1.0(eslint@9.8.0)(typescript@5.5.4)
+         specifier: ^4.2.1
+         version: 4.2.1(eslint@9.10.0)(typescript@5.6.2)
        eslint-plugin-vitest:
          specifier: ^0.5.4
-         version: 0.5.4(eslint@9.8.0)(typescript@5.5.4)(vitest@1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6))
 -        version: 0.5.4(eslint@9.10.0)(typescript@5.6.2)(vitest@2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0))
++        version: 0.5.4(eslint@9.10.0)(typescript@5.6.2)(vitest@2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6))
        estree-walker:
          specifier: 'catalog:'
          version: 2.0.2
          specifier: ^2.4.3
          version: 2.4.3
        tslib:
-         specifier: ^2.6.3
-         version: 2.6.3
-       tsx:
-         specifier: ^4.16.5
-         version: 4.17.0
+         specifier: ^2.7.0
+         version: 2.7.0
        typescript:
-         specifier: ~5.5.4
-         version: 5.5.4
+         specifier: ~5.6.2
+         version: 5.6.2
        typescript-eslint:
-         specifier: ^8.0.0
-         version: 8.0.1(eslint@9.8.0)(typescript@5.5.4)
+         specifier: ^8.5.0
+         version: 8.5.0(eslint@9.10.0)(typescript@5.6.2)
        vite:
          specifier: 'catalog:'
-         version: 5.4.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
 -        version: 5.4.0(@types/node@20.16.5)(sass@1.78.0)
++        version: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
        vitest:
-         specifier: ^1.6.0
-         version: 1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6)
+         specifier: ^2.1.1
 -        version: 2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0)
++        version: 2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6)
 +
 +  benchmark:
 +    dependencies:
 +      '@vitejs/plugin-vue':
 +        specifier: npm:@vue-vapor/vite-plugin-vue@0.0.0-alpha.6
-         version: '@vue-vapor/vite-plugin-vue@0.0.0-alpha.6(vite@5.3.3(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6))(vue@3.5.0-beta.1(typescript@5.5.4))'
++        version: '@vue-vapor/vite-plugin-vue@0.0.0-alpha.6(vite@5.3.3(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))(vue@3.5.6(typescript@5.6.2))'
 +      connect:
 +        specifier: ^3.7.0
 +        version: 3.7.0
 +      sirv:
 +        specifier: ^2.0.4
 +        version: 2.0.4
 +      vite:
 +        specifier: ^5.0.12
-         version: 5.3.3(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
++        version: 5.3.3(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
 +    devDependencies:
 +      '@types/connect':
 +        specifier: ^3.4.38
 +        version: 3.4.38
 +      terser:
 +        specifier: ^5.31.6
 +        version: 5.31.6
  
 -        version: 5.1.2(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0))(vue@packages+vue)
+   packages-private/dts-built-test:
+     dependencies:
+       '@vue/reactivity':
+         specifier: workspace:*
+         version: link:../../packages/reactivity
+       '@vue/shared':
+         specifier: workspace:*
+         version: link:../../packages/shared
+       vue:
+         specifier: workspace:*
+         version: link:../../packages/vue
+   packages-private/dts-test:
+     dependencies:
+       dts-built-test:
+         specifier: workspace:*
+         version: link:../dts-built-test
+       vue:
+         specifier: workspace:*
+         version: link:../../packages/vue
+   packages-private/sfc-playground:
+     dependencies:
+       '@vue/repl':
+         specifier: ^4.4.2
+         version: 4.4.2
+       file-saver:
+         specifier: ^2.0.5
+         version: 2.0.5
+       jszip:
+         specifier: ^3.10.1
+         version: 3.10.1
+       vue:
+         specifier: workspace:*
+         version: link:../../packages/vue
+     devDependencies:
+       '@vitejs/plugin-vue':
+         specifier: 'catalog:'
 -        version: 5.4.0(@types/node@20.16.5)(sass@1.78.0)
++        version: 5.1.2(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))(vue@packages+vue)
+       vite:
+         specifier: 'catalog:'
 -        version: 5.1.2(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0))(vue@packages+vue)
++        version: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
+   packages-private/template-explorer:
+     dependencies:
++      '@vue/compiler-vapor':
++        specifier: workspace:^
++        version: link:../../packages/compiler-vapor
+       monaco-editor:
+         specifier: ^0.51.0
+         version: 0.51.0
+       source-map-js:
+         specifier: ^1.2.1
+         version: 1.2.1
+   packages-private/vite-debug:
+     devDependencies:
+       '@vitejs/plugin-vue':
+         specifier: 'catalog:'
 -        version: 5.4.0(@types/node@20.16.5)(sass@1.78.0)
++        version: 5.1.2(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))(vue@packages+vue)
+       vite:
+         specifier: 'catalog:'
++        version: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
+       vue:
+         specifier: workspace:*
+         version: link:../../packages/vue
    packages/compiler-core:
      dependencies:
        '@babel/parser':
          version: 2.0.2
        source-map-js:
          specifier: 'catalog:'
--        version: 1.2.0
++        version: 1.2.1
      devDependencies:
        '@babel/types':
          specifier: 'catalog:'
          specifier: 'catalog:'
          version: 0.30.11
        postcss:
-         specifier: ^8.4.40
-         version: 8.4.41
+         specifier: ^8.4.47
+         version: 8.4.47
        source-map-js:
          specifier: 'catalog:'
--        version: 1.2.0
++        version: 1.2.1
      devDependencies:
        '@babel/types':
          specifier: 'catalog:'
          specifier: workspace:*
          version: link:../shared
  
-   packages/dts-built-test:
-     dependencies:
-       '@vue/reactivity':
-         specifier: workspace:*
-         version: link:../reactivity
-       '@vue/shared':
-         specifier: workspace:*
-         version: link:../shared
-       vue:
-         specifier: workspace:*
-         version: link:../vue
-   packages/dts-test:
-     dependencies:
-       '@vue/dts-built-test':
-         specifier: workspace:*
-         version: link:../dts-built-test
-       vue:
-         specifier: workspace:*
-         version: link:../vue
 +  packages/compiler-vapor:
 +    dependencies:
 +      '@vue/compiler-dom':
 +        specifier: workspace:*
 +        version: link:../compiler-dom
 +      '@vue/shared':
 +        specifier: workspace:*
 +        version: link:../shared
 +      source-map-js:
 +        specifier: ^1.0.2
 +        version: 1.2.0
 +
    packages/reactivity:
      dependencies:
        '@vue/shared':
          version: 2.0.2
        source-map-js:
          specifier: 'catalog:'
--        version: 1.2.0
++        version: 1.2.1
        vue:
          specifier: workspace:*
          version: link:../vue
  
-         version: '@vue-vapor/vite-plugin-vue@0.0.0-alpha.4(vite@5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6))(vue@packages+vue)'
 +  packages/vue-vapor:
 +    dependencies:
 +      '@vue/compiler-vapor':
 +        specifier: workspace:*
 +        version: link:../compiler-vapor
 +      '@vue/runtime-vapor':
 +        specifier: workspace:*
 +        version: link:../runtime-vapor
 +
 +  playground:
 +    dependencies:
 +      '@vueuse/core':
 +        specifier: ^10.7.2
 +        version: 10.9.0(vue@packages+vue)
 +      vue:
 +        specifier: workspace:*
 +        version: link:../packages/vue
 +    devDependencies:
 +      '@vitejs/plugin-vue':
 +        specifier: npm:@vue-vapor/vite-plugin-vue@0.0.0-alpha.4
-         version: 5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
++        version: '@vue-vapor/vite-plugin-vue@0.0.0-alpha.4(vite@5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))(vue@packages+vue)'
 +      vite:
 +        specifier: ^5.0.12
-         version: 0.2.1(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)(vite@5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6))
++        version: 5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
 +      vite-hyper-config:
 +        specifier: ^0.2.1
-         version: 0.7.42(rollup@4.20.0)(vite@5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6))
++        version: 0.2.1(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)(vite@5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))
 +      vite-plugin-inspect:
 +        specifier: ^0.7.42
++        version: 0.7.42(rollup@4.21.3)(vite@5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))
 +
  packages:
  
    '@ampproject/remapping@2.3.0':
      resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
      engines: {node: '>=14'}
  
-   '@puppeteer/browsers@2.3.0':
-     resolution: {integrity: sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA==}
 +  '@polka/url@1.0.0-next.25':
 +    resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==}
 +
+   '@puppeteer/browsers@2.4.0':
+     resolution: {integrity: sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==}
      engines: {node: '>=18'}
      hasBin: true
  
      resolution: {integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==}
      cpu: [arm]
      os: [linux]
 -    libc: [glibc]
  
 -    libc: [glibc]
+   '@rollup/rollup-linux-arm-gnueabihf@4.21.3':
+     resolution: {integrity: sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==}
+     cpu: [arm]
+     os: [linux]
    '@rollup/rollup-linux-arm-musleabihf@4.20.0':
      resolution: {integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==}
      cpu: [arm]
      os: [linux]
 -    libc: [musl]
  
 -    libc: [musl]
+   '@rollup/rollup-linux-arm-musleabihf@4.21.3':
+     resolution: {integrity: sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==}
+     cpu: [arm]
+     os: [linux]
    '@rollup/rollup-linux-arm64-gnu@4.20.0':
      resolution: {integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==}
      cpu: [arm64]
      os: [linux]
 -    libc: [glibc]
  
 -    libc: [glibc]
+   '@rollup/rollup-linux-arm64-gnu@4.21.3':
+     resolution: {integrity: sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==}
+     cpu: [arm64]
+     os: [linux]
    '@rollup/rollup-linux-arm64-musl@4.20.0':
      resolution: {integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==}
      cpu: [arm64]
      os: [linux]
 -    libc: [musl]
  
 -    libc: [musl]
+   '@rollup/rollup-linux-arm64-musl@4.21.3':
+     resolution: {integrity: sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==}
+     cpu: [arm64]
+     os: [linux]
    '@rollup/rollup-linux-powerpc64le-gnu@4.20.0':
      resolution: {integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==}
      cpu: [ppc64]
      os: [linux]
 -    libc: [glibc]
  
 -    libc: [glibc]
+   '@rollup/rollup-linux-powerpc64le-gnu@4.21.3':
+     resolution: {integrity: sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==}
+     cpu: [ppc64]
+     os: [linux]
    '@rollup/rollup-linux-riscv64-gnu@4.20.0':
      resolution: {integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==}
      cpu: [riscv64]
      os: [linux]
 -    libc: [glibc]
  
 -    libc: [glibc]
+   '@rollup/rollup-linux-riscv64-gnu@4.21.3':
+     resolution: {integrity: sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==}
+     cpu: [riscv64]
+     os: [linux]
    '@rollup/rollup-linux-s390x-gnu@4.20.0':
      resolution: {integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==}
      cpu: [s390x]
      os: [linux]
 -    libc: [glibc]
  
 -    libc: [glibc]
+   '@rollup/rollup-linux-s390x-gnu@4.21.3':
+     resolution: {integrity: sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==}
+     cpu: [s390x]
+     os: [linux]
    '@rollup/rollup-linux-x64-gnu@4.20.0':
      resolution: {integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==}
      cpu: [x64]
      os: [linux]
 -    libc: [glibc]
  
 -    libc: [glibc]
+   '@rollup/rollup-linux-x64-gnu@4.21.3':
+     resolution: {integrity: sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==}
+     cpu: [x64]
+     os: [linux]
    '@rollup/rollup-linux-x64-musl@4.20.0':
      resolution: {integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==}
      cpu: [x64]
      os: [linux]
 -    libc: [musl]
  
 -    libc: [musl]
+   '@rollup/rollup-linux-x64-musl@4.21.3':
+     resolution: {integrity: sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==}
+     cpu: [x64]
+     os: [linux]
    '@rollup/rollup-win32-arm64-msvc@4.20.0':
      resolution: {integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==}
      cpu: [arm64]
      engines: {node: '>=10'}
      cpu: [arm64]
      os: [linux]
 -    libc: [glibc]
  
-   '@swc/core-linux-arm64-musl@1.7.6':
-     resolution: {integrity: sha512-QI8QGL0HGT42tj7F1A+YAzhGkJjUcvvTfI1e2m704W0Enl2/UIK9v5D1zvQzYwusRyKuaQfbeBRYDh0NcLOGLg==}
+   '@swc/core-linux-arm64-musl@1.7.26':
+     resolution: {integrity: sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==}
      engines: {node: '>=10'}
      cpu: [arm64]
      os: [linux]
 -    libc: [musl]
  
-   '@swc/core-linux-x64-gnu@1.7.6':
-     resolution: {integrity: sha512-61AYVzhjuNQAVIKKWOJu3H0/pFD28RYJGxnGg3YMhvRLRyuWNyY5Nyyj2WkKcz/ON+g38Arlz00NT1LDIViRLg==}
+   '@swc/core-linux-x64-gnu@1.7.26':
+     resolution: {integrity: sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==}
      engines: {node: '>=10'}
      cpu: [x64]
      os: [linux]
 -    libc: [glibc]
  
-   '@swc/core-linux-x64-musl@1.7.6':
-     resolution: {integrity: sha512-hQFznpfLK8XajfAAN9Cjs0w/aVmO7iu9VZvInyrTCRcPqxV5O+rvrhRxKvC1LRMZXr5M6JRSRtepp5w+TK4kAw==}
+   '@swc/core-linux-x64-musl@1.7.26':
+     resolution: {integrity: sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==}
      engines: {node: '>=10'}
      cpu: [x64]
      os: [linux]
 -    libc: [musl]
  
-   '@swc/core-win32-arm64-msvc@1.7.6':
-     resolution: {integrity: sha512-Aqsd9afykVMuekzjm4X4TDqwxmG4CrzoOSFe0hZrn9SMio72l5eAPnMtYoe5LsIqtjV8MNprLfXaNbjHjTegmA==}
+   '@swc/core-win32-arm64-msvc@1.7.26':
+     resolution: {integrity: sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==}
      engines: {node: '>=10'}
      cpu: [arm64]
      os: [win32]
        vite: ^5.0.0
        vue: ^3.2.25
  
-   '@vitest/coverage-istanbul@1.6.0':
-     resolution: {integrity: sha512-h/BwpXehkkS0qsNCS00QxiupAqVkNi0WT19BR0dQvlge5oHghoSVLx63fABYFoKxVb7Ue7+k6V2KokmQ1zdMpg==}
+   '@vitest/coverage-v8@2.1.1':
+     resolution: {integrity: sha512-md/A7A3c42oTT8JUHSqjP5uKTWJejzUW4jalpvs+rZ27gsURsMU8DEb+8Jf8C6Kj2gwfSHJqobDNBuoqlm0cFw==}
      peerDependencies:
-       vitest: 1.6.0
+       '@vitest/browser': 2.1.1
+       vitest: 2.1.1
+     peerDependenciesMeta:
+       '@vitest/browser':
+         optional: true
  
-   '@vitest/expect@1.6.0':
-     resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==}
+   '@vitest/expect@2.1.1':
+     resolution: {integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==}
  
-   '@vitest/runner@1.6.0':
-     resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==}
+   '@vitest/mocker@2.1.1':
+     resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==}
+     peerDependencies:
+       '@vitest/spy': 2.1.1
+       msw: ^2.3.5
+       vite: ^5.0.0
+     peerDependenciesMeta:
+       msw:
+         optional: true
+       vite:
+         optional: true
+   '@vitest/pretty-format@2.1.1':
+     resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==}
  
-   '@vitest/snapshot@1.6.0':
-     resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==}
+   '@vitest/runner@2.1.1':
+     resolution: {integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==}
  
-   '@vitest/spy@1.6.0':
-     resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==}
+   '@vitest/snapshot@2.1.1':
+     resolution: {integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==}
  
-   '@vitest/ui@1.6.0':
-     resolution: {integrity: sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA==}
+   '@vitest/spy@2.1.1':
+     resolution: {integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==}
++  '@vitest/ui@2.1.1':
++    resolution: {integrity: sha512-IIxo2LkQDA+1TZdPLYPclzsXukBWd5dX2CKpGqH8CCt8Wh0ZuDn4+vuQ9qlppEju6/igDGzjWF/zyorfsf+nHg==}
 +    peerDependencies:
-       vitest: 1.6.0
++      vitest: 2.1.1
 +
-   '@vitest/utils@1.6.0':
-     resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==}
+   '@vitest/utils@2.1.1':
+     resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==}
  
-   '@vue/compiler-core@3.5.0-beta.1':
-     resolution: {integrity: sha512-MLP2yH21NFnVn+WhUsrRFR+wwXuBWHQ4YmXou1zVaXSfwqwGonf0KC7FBbXz3RbqPH0v2yksWpZFJYnTY++yNQ==}
 +  '@vue-vapor/vite-plugin-vue@0.0.0-alpha.4':
 +    resolution: {integrity: sha512-18LGTnk07uKIWZtYjpyH71PZWIMrwBwiVqjG8bCS5Q7ebISdTUP2N3Lx1vfQNSoGeBV8rxfekfu7XGXRTjJ9gQ==}
 +    engines: {node: ^18.0.0 || >=20.0.0}
 +    peerDependencies:
 +      vite: ^5.0.0
 +      vue: '*'
 +
 +  '@vue-vapor/vite-plugin-vue@0.0.0-alpha.6':
 +    resolution: {integrity: sha512-V2aTQ7bkDXsoPvYIkTA54m3ypUXDIVpTFspn+ycuYcMfIY37cZ0ny6jm/afNY6k1DiaQ9JfAMBXAKzTBpu2B9A==}
 +    engines: {node: ^18.0.0 || >=20.0.0}
 +    peerDependencies:
 +      vite: ^5.0.0
 +      vue: '*'
 +
-   '@vue/compiler-dom@3.5.0-beta.1':
-     resolution: {integrity: sha512-DAC/58eo5XlYdrUXRIf3eWDMbKWM1I85bQfIRIqt7vCE2a2yGmx2LIyI/BEio4uI1Sdf/g16kOzk3BDmFkr1GA==}
++  '@vue/compiler-core@3.5.6':
++    resolution: {integrity: sha512-r+gNu6K4lrvaQLQGmf+1gc41p3FO2OUJyWmNqaIITaJU6YFiV5PtQSFZt8jfztYyARwqhoCayjprC7KMvT3nRA==}
 +
-   '@vue/compiler-sfc@3.5.0-beta.1':
-     resolution: {integrity: sha512-0139cGju9//Wpm90rtwDy6+/1s61Ba04Mn8+X1Xgo6D9xR3h7yLmgHU7OvG9Mh3LwtlB0sQIUeYZMvF995r4ww==}
++  '@vue/compiler-dom@3.5.6':
++    resolution: {integrity: sha512-xRXqxDrIqK8v8sSScpistyYH0qYqxakpsIvqMD2e5sV/PXQ1mTwtXp4k42yHK06KXxKSmitop9e45Ui/3BrTEw==}
 +
-   '@vue/compiler-ssr@3.5.0-beta.1':
-     resolution: {integrity: sha512-aC58zZiLS//lqH6DdOPicv5crn8uSkBMilpGR1lKISViI09n5Gz0Ov0c35lYiVk9WifshTXU+BPQut3huKYySA==}
++  '@vue/compiler-sfc@3.5.6':
++    resolution: {integrity: sha512-pjWJ8Kj9TDHlbF5LywjVso+BIxCY5wVOLhkEXRhuCHDxPFIeX1zaFefKs8RYoHvkSMqRWt93a0f2gNJVJixHwg==}
 +
++  '@vue/compiler-ssr@3.5.6':
++    resolution: {integrity: sha512-VpWbaZrEOCqnmqjE83xdwegtr5qO/2OPUC6veWgvNqTJ3bYysz6vY3VqMuOijubuUYPRpG3OOKIh9TD0Stxb9A==}
 +
    '@vue/consolidate@1.0.0':
      resolution: {integrity: sha512-oTyUE+QHIzLw2PpV14GD/c7EohDyP64xCniWTcqcEmTd699eFqTIwOmtDYjcO1j3QgdXoJEoWv1/cCdLrRoOfg==}
      engines: {node: '>= 0.12.0'}
  
-   '@vue/reactivity@3.5.0-beta.1':
-     resolution: {integrity: sha512-3dBZPdQxGcVCgeJv9KlGuK8a++PUj+OAJ8U89h+77SHMDAKXpLLjnpL+VfreAl37Z39ye4AJyfeYvaXV7fdlcA==}
++  '@vue/reactivity@3.5.6':
++    resolution: {integrity: sha512-shZ+KtBoHna5GyUxWfoFVBCVd7k56m6lGhk5e+J9AKjheHF6yob5eukssHRI+rzvHBiU1sWs/1ZhNbLExc5oYQ==}
 +
-   '@vue/repl@4.3.1':
-     resolution: {integrity: sha512-yzUuLhR+MqOGBDES+xbnm27SfPIEv7XKwhFWWpQhL7HUbXj77GVu+x50Q56JhCWWKTUJzk9MOvAn7bSgdvB5og==}
+   '@vue/repl@4.4.2':
+     resolution: {integrity: sha512-MEAsBK/YzMFGINOBzqM40XTeIYAUsg7CqvXvD5zi0rhYEQrPfEUIdexmMjdm7kVKsKmcvIHxrFK2DFC35m9kHw==}
  
-   '@vue/runtime-core@3.5.0-beta.1':
-     resolution: {integrity: sha512-j+ivXaIRSZbJJGf9ZZpcf+4vqM3DC3AMgmoRrQ8DJExYIU6mvpkSNUfPRBw3QROoD7BjcuImRN6Ia2QxnlwDfw==}
++  '@vue/runtime-core@3.5.6':
++    resolution: {integrity: sha512-FpFULR6+c2lI+m1fIGONLDqPQO34jxV8g6A4wBOgne8eSRHP6PQL27+kWFIx5wNhhjkO7B4rgtsHAmWv7qKvbg==}
 +
-   '@vue/runtime-dom@3.5.0-beta.1':
-     resolution: {integrity: sha512-16xac1YVuQtSsIQsY+94fHlg9QsQOxIZrr66kcHXYN9bSA8SqrTmA6JpfdwQfp+xQMVyRt+xb/K1c8plec9rxQ==}
++  '@vue/runtime-dom@3.5.6':
++    resolution: {integrity: sha512-SDPseWre45G38ENH2zXRAHL1dw/rr5qp91lS4lt/nHvMr0MhsbCbihGAWLXNB/6VfFOJe2O+RBRkXU+CJF7/sw==}
 +
-   '@vue/server-renderer@3.5.0-beta.1':
-     resolution: {integrity: sha512-siDsHX84Yb9nF5H2Xp5h8mb/qXftNbgFiEN2Dr9N1RUaPXcz9Ai4grbMg6yTVm8aoC4gCXBgDVms+QRqSX3Xdg==}
++  '@vue/server-renderer@3.5.6':
++    resolution: {integrity: sha512-zivnxQnOnwEXVaT9CstJ64rZFXMS5ZkKxCjDQKiMSvUhXRzFLWZVbaBiNF4HGDqGNNsTgmjcCSmU6TB/0OOxLA==}
 +    peerDependencies:
-       vue: 3.5.0-beta.1
++      vue: 3.5.6
 +
-   '@vue/shared@3.5.0-beta.1':
-     resolution: {integrity: sha512-RbjXOkVFA+92CWL8HLexUKIl3yUH0PGuzfjDtaNmr4WRP8vlA7xOyRm4iX+jl/KCbZb9JjC0r8yYWqNiMdeSJQ==}
++  '@vue/shared@3.5.6':
++    resolution: {integrity: sha512-eidH0HInnL39z6wAt6SFIwBrvGOpDWsDxlw3rCgo1B+CQ1781WzQUSU3YjxgdkcJo9Q8S6LmXTkvI+cLHGkQfA==}
 +
 +  '@vueuse/core@10.9.0':
 +    resolution: {integrity: sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==}
 +
 +  '@vueuse/metadata@10.9.0':
 +    resolution: {integrity: sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==}
 +
 +  '@vueuse/shared@10.9.0':
 +    resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
 +
    '@zeit/schemas@2.36.0':
      resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==}
  
    concat-map@0.0.1:
      resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
  
-   confbox@0.1.7:
-     resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==}
 +  connect@3.7.0:
 +    resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
 +    engines: {node: '>= 0.10.0'}
 +
    constantinople@4.0.1:
      resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==}
  
    eastasianwidth@0.2.0:
      resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
  
-   electron-to-chromium@1.5.5:
-     resolution: {integrity: sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==}
 +  ee-first@1.1.1:
 +    resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
 +
    emoji-regex@10.3.0:
      resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
  
    fd-slicer@1.1.0:
      resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
  
++  fdir@6.3.0:
++    resolution: {integrity: sha512-QOnuT+BOtivR77wYvCWHfGt9s4Pz1VIMbD463vegT5MLqNXy8rYFT/lPVEqf/bhYeT6qmqrNHhsX+rWwe3rOCQ==}
++    peerDependencies:
++      picomatch: ^3 || ^4
++    peerDependenciesMeta:
++      picomatch:
++        optional: true
++
 +  fflate@0.8.2:
 +    resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
 +
    file-entry-cache@8.0.0:
      resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
      engines: {node: '>=16.0.0'}
    mitt@3.0.1:
      resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
  
-   mlly@1.7.1:
-     resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==}
-   monaco-editor@0.50.0:
-     resolution: {integrity: sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==}
+   monaco-editor@0.51.0:
+     resolution: {integrity: sha512-xaGwVV1fq343cM7aOYB6lVE4Ugf0UyimdD/x5PWcWBMKENwectaEu77FAN7c5sFiyumqeJdX1RPTh1ocioyDjw==}
  
 +  mrmime@2.0.0:
 +    resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==}
 +    engines: {node: '>=10'}
 +
    ms@2.0.0:
      resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
  
      resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
      engines: {node: '>=8.6'}
  
++  picomatch@4.0.2:
++    resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
++    engines: {node: '>=12'}
++
    pidtree@0.6.0:
      resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
      engines: {node: '>=0.10'}
      resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
      engines: {node: '>=0.10.0'}
  
+   source-map-js@1.2.1:
+     resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+     engines: {node: '>=0.10.0'}
 +  source-map-support@0.5.21:
 +    resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
 +
    source-map@0.6.1:
      resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
      engines: {node: '>=0.10.0'}
      resolution: {integrity: sha512-bX655WZI/F7EoTDw9JvQURqAXiPHi8o8+yFxPF2lWYyz1aHnmMRuXWqL6YB6GmeO0o4DIYWHLgGNi/X64T+X4Q==}
      engines: {node: '>=14.18'}
  
-   test-exclude@6.0.0:
-     resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
-     engines: {node: '>=8'}
 +  terser@5.31.6:
 +    resolution: {integrity: sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==}
 +    engines: {node: '>=10'}
 +    hasBin: true
 +
+   test-exclude@7.0.1:
+     resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
+     engines: {node: '>=18'}
  
    text-decoder@1.1.1:
      resolution: {integrity: sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==}
    tinybench@2.9.0:
      resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
  
-   tinypool@0.8.4:
-     resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==}
+   tinyexec@0.3.0:
+     resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==}
++  tinyglobby@0.2.6:
++    resolution: {integrity: sha512-NbBoFBpqfcgd1tCiO8Lkfdk+xrA7mlLR9zgvZcZWQQwU63XAfUePyd6wZBaU93Hqw347lHnwFzttAkemHzzz4g==}
++    engines: {node: '>=12.0.0'}
++
+   tinypool@1.0.0:
+     resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==}
+     engines: {node: ^18.0.0 || >=20.0.0}
+   tinyrainbow@1.2.0:
+     resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
      engines: {node: '>=14.0.0'}
  
-   tinyspy@2.2.1:
-     resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
+   tinyspy@3.0.0:
+     resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==}
      engines: {node: '>=14.0.0'}
  
 +  titleize@3.0.0:
 +    resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
 +    engines: {node: '>=12'}
 +
    to-fast-properties@2.0.0:
      resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
      engines: {node: '>=4'}
      resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
      engines: {node: '>= 10.0.0'}
  
-   update-browserslist-db@1.1.0:
-     resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
-     hasBin: true
-     peerDependencies:
-       browserslist: '>= 4.21.0'
 +  unpipe@1.0.0:
 +    resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
 +    engines: {node: '>= 0.8'}
 +
 +  untildify@4.0.0:
 +    resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
 +    engines: {node: '>=8'}
 +
    update-check@1.5.4:
      resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==}
  
      resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
      engines: {node: '>= 0.8'}
  
-   vite-node@1.6.0:
-     resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==}
 +  vite-hyper-config@0.2.1:
 +    resolution: {integrity: sha512-ItRIpzWp0XMh/Sn1H0GCWnQIUcBjnSaZy/EbOpJcRr9H/KTBHUSTCEOigE9K0KTN01Z0GDi/8WgVT9+RPL932A==}
 +    engines: {node: '>=18.0.0'}
 +    peerDependencies:
 +      vite: ^4.0.0 || ^5.0.0
 +
 +  vite-node@1.5.0:
 +    resolution: {integrity: sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==}
 +    engines: {node: ^18.0.0 || >=20.0.0}
 +    hasBin: true
 +
+   vite-node@2.1.1:
+     resolution: {integrity: sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==}
      engines: {node: ^18.0.0 || >=20.0.0}
      hasBin: true
  
        terser:
          optional: true
  
 -  vitest@2.1.1:
 -    resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==}
 +  vite@5.3.3:
 +    resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
 +    engines: {node: ^18.0.0 || >=20.0.0}
 +    hasBin: true
 +    peerDependencies:
 +      '@types/node': ^18.0.0 || >=20.0.0
 +      less: '*'
 +      lightningcss: ^1.21.0
 +      sass: '*'
 +      stylus: '*'
 +      sugarss: '*'
 +      terser: ^5.4.0
 +    peerDependenciesMeta:
 +      '@types/node':
 +        optional: true
 +      less:
 +        optional: true
 +      lightningcss:
 +        optional: true
 +      sass:
 +        optional: true
 +      stylus:
 +        optional: true
 +      sugarss:
 +        optional: true
 +      terser:
 +        optional: true
 +
 +  vite@5.4.0:
 +    resolution: {integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==}
 +    engines: {node: ^18.0.0 || >=20.0.0}
 +    hasBin: true
 +    peerDependencies:
 +      '@types/node': ^18.0.0 || >=20.0.0
 +      less: '*'
 +      lightningcss: ^1.21.0
 +      sass: '*'
 +      sass-embedded: '*'
 +      stylus: '*'
 +      sugarss: '*'
 +      terser: ^5.4.0
 +    peerDependenciesMeta:
 +      '@types/node':
 +        optional: true
 +      less:
 +        optional: true
 +      lightningcss:
 +        optional: true
 +      sass:
 +        optional: true
 +      sass-embedded:
 +        optional: true
 +      stylus:
 +        optional: true
 +      sugarss:
 +        optional: true
 +      terser:
 +        optional: true
 +
-   vitest@1.6.0:
-     resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==}
++  vitest@2.1.1:
++    resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==}
      engines: {node: ^18.0.0 || >=20.0.0}
      hasBin: true
      peerDependencies:
      resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
      engines: {node: '>=0.10.0'}
  
-   vue@3.5.0-beta.1:
-     resolution: {integrity: sha512-17ZEyGr4411DWSNM9E0nNzQ4IPCkFPeDffTL17IFF+vCwinn9o5VyJmHexa2qKiwoLJ4Ib+3IGo+eAEgafW+fA==}
 +  vue-demi@0.14.7:
 +    resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
 +    engines: {node: '>=12'}
 +    hasBin: true
 +    peerDependencies:
 +      '@vue/composition-api': ^1.0.0-rc.1
 +      vue: ^3.0.0-0 || ^2.6.0
 +    peerDependenciesMeta:
 +      '@vue/composition-api':
 +        optional: true
 +
++  vue@3.5.6:
++    resolution: {integrity: sha512-zv+20E2VIYbcJOzJPUWp03NOGFhMmpCKOfSxVTmCYyYFFko48H9tmuQFzYj7tu4qX1AeXlp9DmhIP89/sSxxhw==}
 +    peerDependencies:
 +      typescript: '*'
 +    peerDependenciesMeta:
 +      typescript:
 +        optional: true
 +
    w3c-xmlserializer@5.0.0:
      resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
      engines: {node: '>=18'}
@@@ -4190,204 -3562,138 +4094,204 @@@ snapshots
    '@esbuild/aix-ppc64@0.21.5':
      optional: true
  
-   '@esbuild/aix-ppc64@0.23.0':
+   '@esbuild/aix-ppc64@0.23.1':
      optional: true
  
 +  '@esbuild/android-arm64@0.20.2':
 +    optional: true
 +
    '@esbuild/android-arm64@0.21.5':
      optional: true
  
-   '@esbuild/android-arm64@0.23.0':
+   '@esbuild/android-arm64@0.23.1':
      optional: true
  
 +  '@esbuild/android-arm@0.20.2':
 +    optional: true
 +
    '@esbuild/android-arm@0.21.5':
      optional: true
  
-   '@esbuild/android-arm@0.23.0':
+   '@esbuild/android-arm@0.23.1':
      optional: true
  
 +  '@esbuild/android-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/android-x64@0.21.5':
      optional: true
  
-   '@esbuild/android-x64@0.23.0':
+   '@esbuild/android-x64@0.23.1':
      optional: true
  
 +  '@esbuild/darwin-arm64@0.20.2':
 +    optional: true
 +
    '@esbuild/darwin-arm64@0.21.5':
      optional: true
  
-   '@esbuild/darwin-arm64@0.23.0':
+   '@esbuild/darwin-arm64@0.23.1':
      optional: true
  
 +  '@esbuild/darwin-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/darwin-x64@0.21.5':
      optional: true
  
-   '@esbuild/darwin-x64@0.23.0':
+   '@esbuild/darwin-x64@0.23.1':
      optional: true
  
 +  '@esbuild/freebsd-arm64@0.20.2':
 +    optional: true
 +
    '@esbuild/freebsd-arm64@0.21.5':
      optional: true
  
-   '@esbuild/freebsd-arm64@0.23.0':
+   '@esbuild/freebsd-arm64@0.23.1':
      optional: true
  
 +  '@esbuild/freebsd-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/freebsd-x64@0.21.5':
      optional: true
  
-   '@esbuild/freebsd-x64@0.23.0':
+   '@esbuild/freebsd-x64@0.23.1':
      optional: true
  
 +  '@esbuild/linux-arm64@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-arm64@0.21.5':
      optional: true
  
-   '@esbuild/linux-arm64@0.23.0':
+   '@esbuild/linux-arm64@0.23.1':
      optional: true
  
 +  '@esbuild/linux-arm@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-arm@0.21.5':
      optional: true
  
-   '@esbuild/linux-arm@0.23.0':
+   '@esbuild/linux-arm@0.23.1':
      optional: true
  
 +  '@esbuild/linux-ia32@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-ia32@0.21.5':
      optional: true
  
-   '@esbuild/linux-ia32@0.23.0':
+   '@esbuild/linux-ia32@0.23.1':
      optional: true
  
 +  '@esbuild/linux-loong64@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-loong64@0.21.5':
      optional: true
  
-   '@esbuild/linux-loong64@0.23.0':
+   '@esbuild/linux-loong64@0.23.1':
      optional: true
  
 +  '@esbuild/linux-mips64el@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-mips64el@0.21.5':
      optional: true
  
-   '@esbuild/linux-mips64el@0.23.0':
+   '@esbuild/linux-mips64el@0.23.1':
      optional: true
  
 +  '@esbuild/linux-ppc64@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-ppc64@0.21.5':
      optional: true
  
-   '@esbuild/linux-ppc64@0.23.0':
+   '@esbuild/linux-ppc64@0.23.1':
      optional: true
  
 +  '@esbuild/linux-riscv64@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-riscv64@0.21.5':
      optional: true
  
-   '@esbuild/linux-riscv64@0.23.0':
+   '@esbuild/linux-riscv64@0.23.1':
      optional: true
  
 +  '@esbuild/linux-s390x@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-s390x@0.21.5':
      optional: true
  
-   '@esbuild/linux-s390x@0.23.0':
+   '@esbuild/linux-s390x@0.23.1':
      optional: true
  
 +  '@esbuild/linux-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/linux-x64@0.21.5':
      optional: true
  
-   '@esbuild/linux-x64@0.23.0':
+   '@esbuild/linux-x64@0.23.1':
      optional: true
  
 +  '@esbuild/netbsd-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/netbsd-x64@0.21.5':
      optional: true
  
-   '@esbuild/netbsd-x64@0.23.0':
+   '@esbuild/netbsd-x64@0.23.1':
      optional: true
  
-   '@esbuild/openbsd-arm64@0.23.0':
+   '@esbuild/openbsd-arm64@0.23.1':
      optional: true
  
 +  '@esbuild/openbsd-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/openbsd-x64@0.21.5':
      optional: true
  
-   '@esbuild/openbsd-x64@0.23.0':
+   '@esbuild/openbsd-x64@0.23.1':
      optional: true
  
 +  '@esbuild/sunos-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/sunos-x64@0.21.5':
      optional: true
  
-   '@esbuild/sunos-x64@0.23.0':
+   '@esbuild/sunos-x64@0.23.1':
      optional: true
  
 +  '@esbuild/win32-arm64@0.20.2':
 +    optional: true
 +
    '@esbuild/win32-arm64@0.21.5':
      optional: true
  
-   '@esbuild/win32-arm64@0.23.0':
+   '@esbuild/win32-arm64@0.23.1':
      optional: true
  
 +  '@esbuild/win32-ia32@0.20.2':
 +    optional: true
 +
    '@esbuild/win32-ia32@0.21.5':
      optional: true
  
-   '@esbuild/win32-ia32@0.23.0':
+   '@esbuild/win32-ia32@0.23.1':
      optional: true
  
 +  '@esbuild/win32-x64@0.20.2':
 +    optional: true
 +
    '@esbuild/win32-x64@0.21.5':
      optional: true
  
    '@pkgjs/parseargs@0.11.0':
      optional: true
  
-   '@puppeteer/browsers@2.3.0':
 +  '@polka/url@1.0.0-next.25': {}
 +
+   '@puppeteer/browsers@2.4.0':
      dependencies:
        debug: 4.3.6
        extract-zip: 2.0.1
  
    '@tootallnate/quickjs-emscripten@0.23.0': {}
  
-       '@types/node': 20.14.14
 +  '@types/connect@3.4.38':
 +    dependencies:
++      '@types/node': 20.16.5
 +
    '@types/estree@1.0.5': {}
  
    '@types/hash-sum@1.0.2': {}
  
    '@types/trusted-types@2.0.7': {}
  
 +  '@types/web-bluetooth@0.0.20': {}
 +
    '@types/yauzl@2.10.3':
      dependencies:
-       '@types/node': 20.14.14
+       '@types/node': 20.16.5
      optional: true
  
-   '@typescript-eslint/eslint-plugin@8.0.1(@typescript-eslint/parser@8.0.1(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)':
+   '@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2)':
      dependencies:
        '@eslint-community/regexpp': 4.11.0
-       '@typescript-eslint/parser': 8.0.1(eslint@9.8.0)(typescript@5.5.4)
-       '@typescript-eslint/scope-manager': 8.0.1
-       '@typescript-eslint/type-utils': 8.0.1(eslint@9.8.0)(typescript@5.5.4)
-       '@typescript-eslint/utils': 8.0.1(eslint@9.8.0)(typescript@5.5.4)
-       '@typescript-eslint/visitor-keys': 8.0.1
-       eslint: 9.8.0
+       '@typescript-eslint/parser': 8.5.0(eslint@9.10.0)(typescript@5.6.2)
+       '@typescript-eslint/scope-manager': 8.5.0
+       '@typescript-eslint/type-utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2)
+       '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2)
+       '@typescript-eslint/visitor-keys': 8.5.0
+       eslint: 9.10.0
        graphemer: 1.4.0
        ignore: 5.3.1
        natural-compare: 1.4.0
        '@typescript-eslint/types': 7.18.0
        eslint-visitor-keys: 3.4.3
  
-   '@typescript-eslint/visitor-keys@8.0.1':
+   '@typescript-eslint/visitor-keys@8.5.0':
      dependencies:
-       '@typescript-eslint/types': 8.0.1
+       '@typescript-eslint/types': 8.5.0
        eslint-visitor-keys: 3.4.3
  
-   '@vitejs/plugin-vue@5.1.2(vite@5.4.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6))(vue@packages+vue)':
 -  '@vitejs/plugin-vue@5.1.2(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0))(vue@packages+vue)':
++  '@vitejs/plugin-vue@5.1.2(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))(vue@packages+vue)':
      dependencies:
-       vite: 5.4.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
 -      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)
++      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
        vue: link:packages/vue
  
-   '@vitest/coverage-istanbul@1.6.0(vitest@1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6))':
 -  '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0))':
++  '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6))':
      dependencies:
+       '@ampproject/remapping': 2.3.0
+       '@bcoe/v8-coverage': 0.2.3
        debug: 4.3.6
        istanbul-lib-coverage: 3.2.2
-       istanbul-lib-instrument: 6.0.3
        istanbul-lib-report: 3.0.1
        istanbul-lib-source-maps: 5.0.6
        istanbul-reports: 3.1.7
+       magic-string: 0.30.11
        magicast: 0.3.4
-       picocolors: 1.0.1
-       test-exclude: 6.0.0
-       vitest: 1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6)
+       std-env: 3.7.0
+       test-exclude: 7.0.1
+       tinyrainbow: 1.2.0
 -      vitest: 2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0)
++      vitest: 2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6)
      transitivePeerDependencies:
        - supports-color
  
-   '@vitest/expect@1.6.0':
+   '@vitest/expect@2.1.1':
      dependencies:
-       '@vitest/spy': 1.6.0
-       '@vitest/utils': 1.6.0
-       chai: 4.5.0
+       '@vitest/spy': 2.1.1
+       '@vitest/utils': 2.1.1
+       chai: 5.1.1
+       tinyrainbow: 1.2.0
  
-   '@vitest/runner@1.6.0':
 -  '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0))':
++  '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))':
      dependencies:
-       '@vitest/utils': 1.6.0
-       p-limit: 5.0.0
+       '@vitest/spy': 2.1.1
+       estree-walker: 3.0.3
+       magic-string: 0.30.11
+     optionalDependencies:
 -      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)
++      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
+   '@vitest/pretty-format@2.1.1':
+     dependencies:
+       tinyrainbow: 1.2.0
+   '@vitest/runner@2.1.1':
+     dependencies:
+       '@vitest/utils': 2.1.1
        pathe: 1.1.2
  
-   '@vitest/snapshot@1.6.0':
+   '@vitest/snapshot@2.1.1':
      dependencies:
+       '@vitest/pretty-format': 2.1.1
        magic-string: 0.30.11
        pathe: 1.1.2
-       pretty-format: 29.7.0
  
-   '@vitest/spy@1.6.0':
+   '@vitest/spy@2.1.1':
      dependencies:
-       tinyspy: 2.2.1
+       tinyspy: 3.0.0
  
-   '@vitest/ui@1.6.0(vitest@1.6.0)':
++  '@vitest/ui@2.1.1(vitest@2.1.1)':
 +    dependencies:
-       '@vitest/utils': 1.6.0
-       fast-glob: 3.3.2
++      '@vitest/utils': 2.1.1
 +      fflate: 0.8.2
 +      flatted: 3.3.1
 +      pathe: 1.1.2
-       picocolors: 1.0.1
 +      sirv: 2.0.4
-       vitest: 1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6)
++      tinyglobby: 0.2.6
++      tinyrainbow: 1.2.0
++      vitest: 2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6)
 +
-   '@vitest/utils@1.6.0':
+   '@vitest/utils@2.1.1':
      dependencies:
-       diff-sequences: 29.6.3
-       estree-walker: 3.0.3
-       loupe: 2.3.7
-       pretty-format: 29.7.0
+       '@vitest/pretty-format': 2.1.1
+       loupe: 3.1.1
+       tinyrainbow: 1.2.0
  
-   '@vue-vapor/vite-plugin-vue@0.0.0-alpha.4(vite@5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6))(vue@packages+vue)':
++  '@vue-vapor/vite-plugin-vue@0.0.0-alpha.4(vite@5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))(vue@packages+vue)':
 +    dependencies:
-       vite: 5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
++      vite: 5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
 +      vue: link:packages/vue
 +
-   '@vue-vapor/vite-plugin-vue@0.0.0-alpha.6(vite@5.3.3(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6))(vue@3.5.0-beta.1(typescript@5.5.4))':
++  '@vue-vapor/vite-plugin-vue@0.0.0-alpha.6(vite@5.3.3(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))(vue@3.5.6(typescript@5.6.2))':
 +    dependencies:
-       vite: 5.3.3(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
-       vue: 3.5.0-beta.1(typescript@5.5.4)
++      vite: 5.3.3(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
++      vue: 3.5.6(typescript@5.6.2)
 +
-   '@vue/compiler-core@3.5.0-beta.1':
++  '@vue/compiler-core@3.5.6':
 +    dependencies:
 +      '@babel/parser': 7.25.3
-       '@vue/shared': 3.5.0-beta.1
-       entities: 5.0.0
++      '@vue/shared': 3.5.6
++      entities: 4.5.0
 +      estree-walker: 2.0.2
-       source-map-js: 1.2.0
++      source-map-js: 1.2.1
 +
-   '@vue/compiler-dom@3.5.0-beta.1':
++  '@vue/compiler-dom@3.5.6':
 +    dependencies:
-       '@vue/compiler-core': 3.5.0-beta.1
-       '@vue/shared': 3.5.0-beta.1
++      '@vue/compiler-core': 3.5.6
++      '@vue/shared': 3.5.6
 +
-   '@vue/compiler-sfc@3.5.0-beta.1':
++  '@vue/compiler-sfc@3.5.6':
 +    dependencies:
 +      '@babel/parser': 7.25.3
-       '@vue/compiler-core': 3.5.0-beta.1
-       '@vue/compiler-dom': 3.5.0-beta.1
-       '@vue/compiler-ssr': 3.5.0-beta.1
-       '@vue/shared': 3.5.0-beta.1
++      '@vue/compiler-core': 3.5.6
++      '@vue/compiler-dom': 3.5.6
++      '@vue/compiler-ssr': 3.5.6
++      '@vue/shared': 3.5.6
 +      estree-walker: 2.0.2
 +      magic-string: 0.30.11
-       postcss: 8.4.41
-       source-map-js: 1.2.0
++      postcss: 8.4.47
++      source-map-js: 1.2.1
 +
-   '@vue/compiler-ssr@3.5.0-beta.1':
++  '@vue/compiler-ssr@3.5.6':
 +    dependencies:
-       '@vue/compiler-dom': 3.5.0-beta.1
-       '@vue/shared': 3.5.0-beta.1
++      '@vue/compiler-dom': 3.5.6
++      '@vue/shared': 3.5.6
 +
    '@vue/consolidate@1.0.0': {}
  
-   '@vue/reactivity@3.5.0-beta.1':
++  '@vue/reactivity@3.5.6':
 +    dependencies:
-       '@vue/shared': 3.5.0-beta.1
++      '@vue/shared': 3.5.6
 +
-   '@vue/repl@4.3.1': {}
+   '@vue/repl@4.4.2': {}
  
-   '@vue/runtime-core@3.5.0-beta.1':
++  '@vue/runtime-core@3.5.6':
 +    dependencies:
-       '@vue/reactivity': 3.5.0-beta.1
-       '@vue/shared': 3.5.0-beta.1
++      '@vue/reactivity': 3.5.6
++      '@vue/shared': 3.5.6
 +
-   '@vue/runtime-dom@3.5.0-beta.1':
++  '@vue/runtime-dom@3.5.6':
 +    dependencies:
-       '@vue/reactivity': 3.5.0-beta.1
-       '@vue/runtime-core': 3.5.0-beta.1
-       '@vue/shared': 3.5.0-beta.1
++      '@vue/reactivity': 3.5.6
++      '@vue/runtime-core': 3.5.6
++      '@vue/shared': 3.5.6
 +      csstype: 3.1.3
 +
-   '@vue/server-renderer@3.5.0-beta.1(vue@3.5.0-beta.1(typescript@5.5.4))':
++  '@vue/server-renderer@3.5.6(vue@3.5.6(typescript@5.6.2))':
 +    dependencies:
-       '@vue/compiler-ssr': 3.5.0-beta.1
-       '@vue/shared': 3.5.0-beta.1
-       vue: 3.5.0-beta.1(typescript@5.5.4)
++      '@vue/compiler-ssr': 3.5.6
++      '@vue/shared': 3.5.6
++      vue: 3.5.6(typescript@5.6.2)
 +
-   '@vue/shared@3.5.0-beta.1': {}
++  '@vue/shared@3.5.6': {}
 +
 +  '@vueuse/core@10.9.0(vue@packages+vue)':
 +    dependencies:
 +      '@types/web-bluetooth': 0.0.20
 +      '@vueuse/metadata': 10.9.0
 +      '@vueuse/shared': 10.9.0(vue@packages+vue)
 +      vue-demi: 0.14.7(vue@packages+vue)
 +    transitivePeerDependencies:
 +      - '@vue/composition-api'
 +      - vue
 +
 +  '@vueuse/metadata@10.9.0': {}
 +
 +  '@vueuse/shared@10.9.0(vue@packages+vue)':
 +    dependencies:
 +      vue-demi: 0.14.7(vue@packages+vue)
 +    transitivePeerDependencies:
 +      - '@vue/composition-api'
 +      - vue
 +
    '@zeit/schemas@2.36.0': {}
  
    accepts@1.3.8:
      dependencies:
        fill-range: 7.1.1
  
-   browserslist@4.23.3:
-     dependencies:
-       caniuse-lite: 1.0.30001651
-       electron-to-chromium: 1.5.5
-       node-releases: 2.0.18
-       update-browserslist-db: 1.1.0(browserslist@4.23.3)
    buffer-crc32@0.2.13: {}
  
 +  buffer-from@1.1.2: {}
 +
    buffer@5.7.1:
      dependencies:
        base64-js: 1.5.1
  
    concat-map@0.0.1: {}
  
-   confbox@0.1.7: {}
 +  connect@3.7.0:
 +    dependencies:
 +      debug: 2.6.9
 +      finalhandler: 1.1.2
 +      parseurl: 1.3.3
 +      utils-merge: 1.0.1
 +    transitivePeerDependencies:
 +      - supports-color
 +
    constantinople@4.0.1:
      dependencies:
        '@babel/parser': 7.25.3
  
    eastasianwidth@0.2.0: {}
  
-   electron-to-chromium@1.5.5: {}
 +  ee-first@1.1.1: {}
 +
    emoji-regex@10.3.0: {}
  
    emoji-regex@8.0.0: {}
  
    es-module-lexer@1.5.4: {}
  
-   esbuild-plugin-polyfill-node@0.3.0(esbuild@0.23.0):
+   esbuild-plugin-polyfill-node@0.3.0(esbuild@0.23.1):
      dependencies:
        '@jspm/core': 2.0.1
-       esbuild: 0.23.0
+       esbuild: 0.23.1
        import-meta-resolve: 3.1.1
  
 +  esbuild@0.20.2:
 +    optionalDependencies:
 +      '@esbuild/aix-ppc64': 0.20.2
 +      '@esbuild/android-arm': 0.20.2
 +      '@esbuild/android-arm64': 0.20.2
 +      '@esbuild/android-x64': 0.20.2
 +      '@esbuild/darwin-arm64': 0.20.2
 +      '@esbuild/darwin-x64': 0.20.2
 +      '@esbuild/freebsd-arm64': 0.20.2
 +      '@esbuild/freebsd-x64': 0.20.2
 +      '@esbuild/linux-arm': 0.20.2
 +      '@esbuild/linux-arm64': 0.20.2
 +      '@esbuild/linux-ia32': 0.20.2
 +      '@esbuild/linux-loong64': 0.20.2
 +      '@esbuild/linux-mips64el': 0.20.2
 +      '@esbuild/linux-ppc64': 0.20.2
 +      '@esbuild/linux-riscv64': 0.20.2
 +      '@esbuild/linux-s390x': 0.20.2
 +      '@esbuild/linux-x64': 0.20.2
 +      '@esbuild/netbsd-x64': 0.20.2
 +      '@esbuild/openbsd-x64': 0.20.2
 +      '@esbuild/sunos-x64': 0.20.2
 +      '@esbuild/win32-arm64': 0.20.2
 +      '@esbuild/win32-ia32': 0.20.2
 +      '@esbuild/win32-x64': 0.20.2
 +
    esbuild@0.21.5:
      optionalDependencies:
        '@esbuild/aix-ppc64': 0.21.5
        - supports-color
        - typescript
  
-   eslint-plugin-vitest@0.5.4(eslint@9.8.0)(typescript@5.5.4)(vitest@1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6)):
 -  eslint-plugin-vitest@0.5.4(eslint@9.10.0)(typescript@5.6.2)(vitest@2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0)):
++  eslint-plugin-vitest@0.5.4(eslint@9.10.0)(typescript@5.6.2)(vitest@2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6)):
      dependencies:
-       '@typescript-eslint/utils': 7.18.0(eslint@9.8.0)(typescript@5.5.4)
-       eslint: 9.8.0
+       '@typescript-eslint/utils': 7.18.0(eslint@9.10.0)(typescript@5.6.2)
+       eslint: 9.10.0
      optionalDependencies:
-       vitest: 1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6)
 -      vitest: 2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0)
++      vitest: 2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6)
      transitivePeerDependencies:
        - supports-color
        - typescript
      dependencies:
        pend: 1.2.0
  
++  fdir@6.3.0(picomatch@4.0.2):
++    optionalDependencies:
++      picomatch: 4.0.2
++
 +  fflate@0.8.2: {}
 +
    file-entry-cache@8.0.0:
      dependencies:
        flat-cache: 4.0.1
  
    mitt@3.0.1: {}
  
-   mlly@1.7.1:
-     dependencies:
-       acorn: 8.12.1
-       pathe: 1.1.2
-       pkg-types: 1.1.3
-       ufo: 1.5.4
-   monaco-editor@0.50.0: {}
+   monaco-editor@0.51.0: {}
  
 +  mrmime@2.0.0: {}
 +
    ms@2.0.0: {}
  
    ms@2.1.2: {}
      dependencies:
        entities: 4.5.0
  
 +  parseurl@1.3.3: {}
 +
    path-exists@4.0.0: {}
  
-   path-is-absolute@1.0.1: {}
    path-is-inside@1.0.2: {}
  
    path-key@3.1.1: {}
  
    picocolors@1.0.1: {}
  
+   picocolors@1.1.0: {}
    picomatch@2.3.1: {}
  
-   pidtree@0.6.0: {}
++  picomatch@4.0.2: {}
 +
-   pkg-types@1.1.3:
-     dependencies:
-       confbox: 0.1.7
-       mlly: 1.7.1
-       pathe: 1.1.2
+   pidtree@0.6.0: {}
  
-   postcss-modules-extract-imports@3.1.0(postcss@8.4.41):
+   postcss-modules-extract-imports@3.1.0(postcss@8.4.47):
      dependencies:
-       postcss: 8.4.41
+       postcss: 8.4.47
  
-   postcss-modules-local-by-default@4.0.5(postcss@8.4.41):
+   postcss-modules-local-by-default@4.0.5(postcss@8.4.47):
      dependencies:
-       icss-utils: 5.1.0(postcss@8.4.41)
-       postcss: 8.4.41
-       postcss-selector-parser: 6.1.1
+       icss-utils: 5.1.0(postcss@8.4.47)
+       postcss: 8.4.47
+       postcss-selector-parser: 6.1.2
        postcss-value-parser: 4.2.0
  
-   postcss-modules-scope@3.2.0(postcss@8.4.41):
+   postcss-modules-scope@3.2.0(postcss@8.4.47):
      dependencies:
-       postcss: 8.4.41
-       postcss-selector-parser: 6.1.1
+       postcss: 8.4.47
+       postcss-selector-parser: 6.1.2
  
-   postcss-modules-values@4.0.0(postcss@8.4.41):
+   postcss-modules-values@4.0.0(postcss@8.4.47):
      dependencies:
-       icss-utils: 5.1.0(postcss@8.4.41)
-       postcss: 8.4.41
+       icss-utils: 5.1.0(postcss@8.4.47)
+       postcss: 8.4.47
  
-   postcss-modules@6.0.0(postcss@8.4.41):
+   postcss-modules@6.0.0(postcss@8.4.47):
      dependencies:
        generic-names: 4.0.0
-       icss-utils: 5.1.0(postcss@8.4.41)
+       icss-utils: 5.1.0(postcss@8.4.47)
        lodash.camelcase: 4.3.0
-       postcss: 8.4.41
-       postcss-modules-extract-imports: 3.1.0(postcss@8.4.41)
-       postcss-modules-local-by-default: 4.0.5(postcss@8.4.41)
-       postcss-modules-scope: 3.2.0(postcss@8.4.41)
-       postcss-modules-values: 4.0.0(postcss@8.4.41)
+       postcss: 8.4.47
+       postcss-modules-extract-imports: 3.1.0(postcss@8.4.47)
+       postcss-modules-local-by-default: 4.0.5(postcss@8.4.47)
+       postcss-modules-scope: 3.2.0(postcss@8.4.47)
+       postcss-modules-values: 4.0.0(postcss@8.4.47)
        string-hash: 1.1.3
  
-   postcss-selector-parser@6.1.1:
+   postcss-selector-parser@6.1.2:
      dependencies:
        cssesc: 3.0.0
        util-deprecate: 1.0.2
  
    source-map-js@1.2.0: {}
  
+   source-map-js@1.2.1: {}
 +  source-map-support@0.5.21:
 +    dependencies:
 +      buffer-from: 1.1.2
 +      source-map: 0.6.1
 +
    source-map@0.6.1: {}
  
    spdx-correct@3.2.0:
      dependencies:
        temp-dir: 3.0.0
  
-   test-exclude@6.0.0:
 +  terser@5.31.6:
 +    dependencies:
 +      '@jridgewell/source-map': 0.3.6
 +      acorn: 8.12.1
 +      commander: 2.20.3
 +      source-map-support: 0.5.21
 +
+   test-exclude@7.0.1:
      dependencies:
        '@istanbuljs/schema': 0.1.3
-       glob: 7.2.3
-       minimatch: 3.1.2
+       glob: 10.4.5
+       minimatch: 9.0.5
  
    text-decoder@1.1.1:
      dependencies:
  
    tinybench@2.9.0: {}
  
-   tinypool@0.8.4: {}
+   tinyexec@0.3.0: {}
  
-   tinyspy@2.2.1: {}
++  tinyglobby@0.2.6:
++    dependencies:
++      fdir: 6.3.0(picomatch@4.0.2)
++      picomatch: 4.0.2
++
+   tinypool@1.0.0: {}
+   tinyrainbow@1.2.0: {}
+   tinyspy@3.0.0: {}
  
 +  titleize@3.0.0: {}
 +
    to-fast-properties@2.0.0: {}
  
    to-regex-range@5.0.1:
  
    universalify@2.0.1: {}
  
-   update-browserslist-db@1.1.0(browserslist@4.23.3):
-     dependencies:
-       browserslist: 4.23.3
-       escalade: 3.1.2
-       picocolors: 1.0.1
 +  unpipe@1.0.0: {}
 +
 +  untildify@4.0.0: {}
 +
    update-check@1.5.4:
      dependencies:
        registry-auth-token: 3.3.2
  
    vary@1.1.2: {}
  
-   vite-hyper-config@0.2.1(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)(vite@5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)):
 -  vite-node@2.1.1(@types/node@20.16.5)(sass@1.78.0):
++  vite-hyper-config@0.2.1(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)(vite@5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)):
 +    dependencies:
 +      cac: 6.7.14
 +      picocolors: 1.0.1
-       vite: 5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
-       vite-node: 1.5.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
++      vite: 5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
++      vite-node: 1.5.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
 +    transitivePeerDependencies:
 +      - '@types/node'
 +      - less
 +      - lightningcss
 +      - sass
 +      - sass-embedded
 +      - stylus
 +      - sugarss
 +      - supports-color
 +      - terser
 +
-   vite-node@1.5.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6):
++  vite-node@1.5.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6):
 +    dependencies:
 +      cac: 6.7.14
 +      debug: 4.3.6
 +      pathe: 1.1.2
 +      picocolors: 1.0.1
-       vite: 5.4.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
++      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
 +    transitivePeerDependencies:
 +      - '@types/node'
 +      - less
 +      - lightningcss
 +      - sass
 +      - sass-embedded
 +      - stylus
 +      - sugarss
 +      - supports-color
 +      - terser
 +
-   vite-node@1.6.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6):
++  vite-node@2.1.1(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6):
      dependencies:
        cac: 6.7.14
        debug: 4.3.6
        pathe: 1.1.2
-       picocolors: 1.0.1
-       vite: 5.4.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
 -      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)
++      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
      transitivePeerDependencies:
        - '@types/node'
        - less
        - supports-color
        - terser
  
-   vite-plugin-inspect@0.7.42(rollup@4.20.0)(vite@5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)):
 -  vite@5.4.0(@types/node@20.16.5)(sass@1.78.0):
++  vite-plugin-inspect@0.7.42(rollup@4.21.3)(vite@5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)):
 +    dependencies:
 +      '@antfu/utils': 0.7.7
-       '@rollup/pluginutils': 5.1.0(rollup@4.20.0)
++      '@rollup/pluginutils': 5.1.0(rollup@4.21.3)
 +      debug: 4.3.6
 +      error-stack-parser-es: 0.1.1
 +      fs-extra: 11.2.0
 +      open: 9.1.0
 +      picocolors: 1.0.1
 +      sirv: 2.0.4
-       vite: 5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
++      vite: 5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
 +    transitivePeerDependencies:
 +      - rollup
 +      - supports-color
 +
-   vite@5.2.9(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6):
++  vite@5.2.9(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6):
 +    dependencies:
 +      esbuild: 0.20.2
 +      postcss: 8.4.41
 +      rollup: 4.20.0
 +    optionalDependencies:
-       '@types/node': 20.14.14
++      '@types/node': 20.16.5
 +      fsevents: 2.3.3
-       sass: 1.77.8
++      sass: 1.78.0
 +      terser: 5.31.6
 +
-   vite@5.3.3(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6):
++  vite@5.3.3(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6):
      dependencies:
        esbuild: 0.21.5
        postcss: 8.4.41
        rollup: 4.20.0
      optionalDependencies:
-       '@types/node': 20.14.14
+       '@types/node': 20.16.5
        fsevents: 2.3.3
-       sass: 1.77.8
+       sass: 1.78.0
 +      terser: 5.31.6
  
-   vite@5.4.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6):
 -  vitest@2.1.1(@types/node@20.16.5)(jsdom@25.0.0)(sass@1.78.0):
++  vite@5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6):
 +    dependencies:
 +      esbuild: 0.21.5
-       postcss: 8.4.41
-       rollup: 4.20.0
++      postcss: 8.4.47
++      rollup: 4.21.3
 +    optionalDependencies:
-       '@types/node': 20.14.14
++      '@types/node': 20.16.5
 +      fsevents: 2.3.3
-       sass: 1.77.8
++      sass: 1.78.0
 +      terser: 5.31.6
 +
-   vitest@1.6.0(@types/node@20.14.14)(@vitest/ui@1.6.0)(jsdom@24.1.1)(sass@1.77.8)(terser@5.31.6):
++  vitest@2.1.1(@types/node@20.16.5)(@vitest/ui@2.1.1)(jsdom@25.0.0)(sass@1.78.0)(terser@5.31.6):
      dependencies:
-       '@vitest/expect': 1.6.0
-       '@vitest/runner': 1.6.0
-       '@vitest/snapshot': 1.6.0
-       '@vitest/spy': 1.6.0
-       '@vitest/utils': 1.6.0
-       acorn-walk: 8.3.3
-       chai: 4.5.0
+       '@vitest/expect': 2.1.1
 -      '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0))
++      '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6))
+       '@vitest/pretty-format': 2.1.1
+       '@vitest/runner': 2.1.1
+       '@vitest/snapshot': 2.1.1
+       '@vitest/spy': 2.1.1
+       '@vitest/utils': 2.1.1
+       chai: 5.1.1
        debug: 4.3.6
-       execa: 8.0.1
-       local-pkg: 0.5.0
        magic-string: 0.30.11
        pathe: 1.1.2
-       picocolors: 1.0.1
        std-env: 3.7.0
-       strip-literal: 2.1.0
        tinybench: 2.9.0
-       tinypool: 0.8.4
-       vite: 5.4.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
-       vite-node: 1.6.0(@types/node@20.14.14)(sass@1.77.8)(terser@5.31.6)
+       tinyexec: 0.3.0
+       tinypool: 1.0.0
+       tinyrainbow: 1.2.0
 -      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)
 -      vite-node: 2.1.1(@types/node@20.16.5)(sass@1.78.0)
++      vite: 5.4.0(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
++      vite-node: 2.1.1(@types/node@20.16.5)(sass@1.78.0)(terser@5.31.6)
        why-is-node-running: 2.3.0
      optionalDependencies:
-       '@types/node': 20.14.14
-       '@vitest/ui': 1.6.0(vitest@1.6.0)
-       jsdom: 24.1.1
+       '@types/node': 20.16.5
++      '@vitest/ui': 2.1.1(vitest@2.1.1)
+       jsdom: 25.0.0
      transitivePeerDependencies:
        - less
        - lightningcss
  
    void-elements@3.1.0: {}
  
-   vue@3.5.0-beta.1(typescript@5.5.4):
 +  vue-demi@0.14.7(vue@packages+vue):
 +    dependencies:
 +      vue: link:packages/vue
 +
-       '@vue/compiler-dom': 3.5.0-beta.1
-       '@vue/compiler-sfc': 3.5.0-beta.1
-       '@vue/runtime-dom': 3.5.0-beta.1
-       '@vue/server-renderer': 3.5.0-beta.1(vue@3.5.0-beta.1(typescript@5.5.4))
-       '@vue/shared': 3.5.0-beta.1
++  vue@3.5.6(typescript@5.6.2):
 +    dependencies:
-       typescript: 5.5.4
++      '@vue/compiler-dom': 3.5.6
++      '@vue/compiler-sfc': 3.5.6
++      '@vue/runtime-dom': 3.5.6
++      '@vue/server-renderer': 3.5.6(vue@3.5.6(typescript@5.6.2))
++      '@vue/shared': 3.5.6
 +    optionalDependencies:
++      typescript: 5.6.2
 +
    w3c-xmlserializer@5.0.0:
      dependencies:
        xml-name-validator: 5.0.0
index 9af8c528fd40176c072a0677ca9ce7f69ac4430f,23270954bb3897e8e5b906518c496aff2dd979d3..d01dbb0480c8d9d5774e3d987fad62a1760569e5
@@@ -1,7 -1,6 +1,8 @@@
  packages:
    - 'packages/*'
+   - 'packages-private/*'
 +  - playground
 +  - benchmark
  
  catalog:
    '@babel/parser': ^7.25.3
Simple merge
Simple merge
index 7609c531ede572e1ddf3e15248512089cd1f5e86,c68e3703b91b8e1b04d3d96a26cd0851a837a473..01c6ff521164a97445ebfb5af3ea1aed6b2809f7
@@@ -5,28 -6,41 +6,47 @@@ import nodeResolve from '@rollup/plugin
  import { minify } from '@swc/core'
  import replace from '@rollup/plugin-replace'
  import { brotliCompressSync, gzipSync } from 'node:zlib'
+ import { parseArgs } from 'node:util'
+ import pico from 'picocolors'
+ import prettyBytes from 'pretty-bytes'
+ const {
+   values: { write },
+ } = parseArgs({
+   options: {
+     write: {
+       type: 'boolean',
+       default: false,
+     },
+   },
+ })
  
  const sizeDir = path.resolve('temp/size')
 -const entry = path.resolve('./packages/vue/dist/vue.runtime.esm-bundler.js')
 +const vue = path.resolve('./packages/vue/dist/vue.runtime.esm-bundler.js')
 +const vapor = path.resolve(
 +  './packages/vue-vapor/dist/vue-vapor.runtime.esm-bundler.js',
 +)
  
- interface Preset {
-   name: string
-   imports: '*' | string[]
-   from: string
- }
+ /**
+  * @typedef {Object} Preset
+  * @property {string} name - The name of the preset
 - * @property {string[]} imports - The imports that are part of this preset
++ * @property {'*' | string[]} imports - The imports that are part of this preset
++ * @property {string} from - The path to the entry file
+  * @property {Record<string, string>} [replace]
+  */
  
- const presets: Preset[] = [
-   { name: 'createApp', imports: ['createApp'], from: vue },
-   { name: 'createSSRApp', imports: ['createSSRApp'], from: vue },
+ /** @type {Preset[]} */
+ const presets = [
    {
-     name: 'defineCustomElement',
-     imports: ['defineCustomElement'],
+     name: 'createApp (CAPI only)',
+     imports: ['createApp'],
+     replace: { __VUE_OPTIONS_API__: 'false' },
 +    from: vue,
    },
 -  { name: 'createApp', imports: ['createApp'] },
 -  { name: 'createSSRApp', imports: ['createSSRApp'] },
 -  { name: 'defineCustomElement', imports: ['defineCustomElement'] },
++  { name: 'createApp', imports: ['createApp'], from: vue },
++  { name: 'createSSRApp', imports: ['createSSRApp'], from: vue },
++  { name: 'defineCustomElement', imports: ['defineCustomElement'], from: vue },
 +  { name: 'vapor', imports: '*', from: vapor },
    {
      name: 'overall',
      imports: [
@@@ -61,13 -85,16 +92,19 @@@ async function main() 
    )
  }
  
- async function generateBundle(preset: Preset) {
+ /**
+  * Generates a bundle for a given preset
+  *
+  * @param {Preset} preset - The preset to generate the bundle for
+  * @returns {Promise<{name: string, size: number, gzip: number, brotli: number}>} - The result of the bundling process
+  */
+ async function generateBundle(preset) {
    const id = 'virtual:entry'
 -  const content = `export { ${preset.imports.join(', ')} } from '${entry}'`
 -
 +  const exportSpecifiers =
 +    preset.imports === '*'
 +      ? `* as ${preset.name}`
 +      : `{ ${preset.imports.join(', ')} }`
 +  const content = `export ${exportSpecifiers} from '${preset.from}'`
    const result = await rollup({
      input: id,
      plugins: [
Simple merge
Simple merge
diff --cc tsconfig.json
Simple merge
index bc60f7e87059f72dc8316773a7cd395ea1d851aa,67db1d8506cec179264ed96e87fb8d6a0148c9e0..fb67562fca57c36a632a865aa4c312506992e8b1
@@@ -23,9 -23,10 +23,10 @@@ export default defineConfig(
    },
    test: {
      globals: true,
+     pool: 'threads',
      setupFiles: 'scripts/setup-vitest.ts',
      environmentMatchGlobs: [
 -      ['packages/{vue,vue-compat,runtime-dom}/**', 'jsdom'],
 +      ['packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**', 'jsdom'],
      ],
      sequence: {
        hooks: 'list',
Simple merge