### Pull Request Checklist
- Vue core has two primary work branches: `main` and `minor`.
+
- If your pull request is a feature that adds new API surface, it should be submitted against the `minor` branch.
- Otherwise, it should be submitted against the `main` branch.
- [Make sure to tick the "Allow edits from maintainers" box](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork). This allows us to directly make minor edits / refactors and saves a lot of time.
- If adding a new feature:
+
- Add accompanying test case.
- Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.
- If fixing a bug:
+
- If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update entities encoding/decoding (fix #3899)`.
- Provide a detailed description of the bug in the PR. Live demo preferred.
- Add appropriate test coverage if applicable. You can check the coverage of your code addition by running `nr test-coverage`.
- The PR should fix the intended bug **only** and not introduce unrelated changes. This includes unnecessary refactors - a PR should focus on the fix and not code style, this makes it easier to trace changes in the future.
- Consider the performance / size impact of the changes, and whether the bug being fixes justifies the cost. If the bug being fixed is a very niche edge case, we should try to minimize the size / perf cost to make it worthwhile.
+
- Is the code perf-sensitive (e.g. in "hot paths" like component updates or the vdom patch function?)
+
- If the branch is dev-only, performance is less of a concern.
- Check how much extra bundle size the change introduces.
- `vue`: The public facing "full build" which includes both the runtime AND the compiler.
- Private utility packages:
+
- `dts-test`: Contains type-only tests against generated dts files.
- `sfc-playground`: The playground continuously deployed at https://play.vuejs.org. To run the playground locally, use [`nr dev-sfc`](#nr-dev-sfc).
```mermaid
flowchart LR
- vue["vue"]
compiler-sfc["@vue/compiler-sfc"]
compiler-dom["@vue/compiler-dom"]
- compiler-vapor["@vue/compiler-vapor"]
compiler-core["@vue/compiler-core"]
+ vue["vue"]
runtime-dom["@vue/runtime-dom"]
- runtime-vapor["@vue/runtime-vapor"]
runtime-core["@vue/runtime-core"]
reactivity["@vue/reactivity"]
subgraph "Runtime Packages"
runtime-dom --> runtime-core
- runtime-vapor --> runtime-core
runtime-core --> reactivity
end
subgraph "Compiler Packages"
compiler-sfc --> compiler-core
compiler-sfc --> compiler-dom
- compiler-sfc --> compiler-vapor
compiler-dom --> compiler-core
- compiler-vapor --> compiler-core
end
- vue --> compiler-sfc
vue ---> compiler-dom
vue --> runtime-dom
- vue --> compiler-vapor
- vue --> runtime-vapor
-
- %% Highlight class
- classDef highlight stroke:#35eb9a,stroke-width:3px;
- class compiler-vapor,runtime-vapor highlight;
```
There are some rules to follow when importing across package boundaries:
- Performance: if a refactor PR claims to improve performance, there should be benchmarks showcasing said performance unless the improvement is self-explanatory.
- Code quality / stylistic PRs: we should be conservative on merging this type PRs because (1) they can be subjective in many cases, and (2) they often come with large git diffs, causing merge conflicts with other pending PRs, and leading to unwanted noise when tracing changes through git history. Use your best judgement on this type of PRs on whether they are worth it.
+
- For PRs in this category that are approved, do not merge immediately. Group them before releasing a new minor, after all feature-oriented PRs are merged.
### Reviewing a Feature
- Feature PRs should always have clear context and explanation on why the feature should be added, ideally in the form of an RFC. If the PR doesn't explain what real-world problem it is solving, ask the contributor to clarify.
- Decide if the feature should require an RFC process. The line isn't always clear, but a rough criteria is whether it is augmenting an existing API vs. adding a new API. Some examples:
+
- Adding a new built-in component or directive is "significant" and definitely requires an RFC.
- Template syntax additions like adding a new `v-on` modifier or a new `v-bind` syntax sugar are "substantial". It would be nice to have an RFC for it, but a detailed explanation on the use case and reasoning behind the design directly in the PR itself can be acceptable.
- Small, low-impact additions like exposing a new utility type or adding a new app config option can be self-explanatory, but should still provide enough context in the PR.
- Implementation: code style should be consistent with the rest of the codebase, follow common best practices. Prefer code that is boring but easy to understand over "clever" code.
- Size: bundle size matters. We have a GitHub action that compares the size change for every PR. We should always aim to realize the desired changes with the smallest amount of code size increase.
+
- Sometimes we need to compare the size increase vs. perceived benefits to decide whether a change is justifiable. Also take extra care to make sure added code can be tree-shaken if not needed.
- Make sure to put dev-only code in `__DEV__` branches so they are tree-shakable.
- Make sure it doesn't accidentally cause dev-only or compiler-only code branches to be included in the runtime build. Notable case is that some functions in @vue/shared are compiler-only and should not be used in runtime code, e.g. `isHTMLTag` and `isSVGTag`.
- Performance
+
- Be careful about code changes in "hot paths", in particular the Virtual DOM renderer (`runtime-core/src/renderer.ts`) and component instantiation code.
- Potential Breakage
branches:
- main
- minor
- - vapor
jobs:
test:
uses: ./.github/workflows/test.yml
continuous-release:
- if: github.repository == 'vuejs/core' && github.ref_name != 'vapor'
+ if: github.repository == 'vuejs/core'
runs-on: ubuntu-latest
steps:
- name: Checkout
- name: verify treeshaking
run: node scripts/verify-treeshaking.js
- e2e-vapor:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - name: Setup cache for Chromium binary
- uses: actions/cache@v4
- with:
- path: ~/.cache/puppeteer
- key: chromium-${{ hashFiles('pnpm-lock.yaml') }}
-
- - name: Install pnpm
- uses: pnpm/action-setup@v4.0.0
-
- - name: Install Node.js
- uses: actions/setup-node@v4
- with:
- node-version-file: '.node-version'
- cache: 'pnpm'
-
- - run: pnpm install
- - run: node node_modules/puppeteer/install.mjs
-
- - name: Run e2e tests
- run: pnpm run test-e2e-vapor
-
lint-and-test-dts:
runs-on: ubuntu-latest
env:
dts-build/packages
*.tsbuildinfo
*.tgz
-packages-private/benchmark/reference
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
- "editor.formatOnSave": true,
- "vitest.disableWorkspaceWarning": true
+ "editor.formatOnSave": true
}
// Packages targeting DOM
{
- files: ['packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**'],
+ files: ['packages/{vue,vue-compat,runtime-dom}/**'],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
},
files: [
'packages-private/template-explorer/**',
'packages-private/sfc-playground/**',
- 'packages-private/local-playground/**',
],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
'./*.{js,ts}',
'packages/*/*.js',
'packages/vue/*/*.js',
- 'packages-private/benchmark/*',
- 'packages-private/e2e-utils/*',
],
rules: {
'no-restricted-globals': 'off',
"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 compiler-dom -f global -p --size",
+ "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-shared runtime-dom runtime-core reactivity shared runtime-vapor -f esm-bundler",
+ "size-esm": "node scripts/build.js runtime-dom 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 --project unit --project unit-jsdom",
+ "test-unit": "vitest --project unit",
"test-e2e": "node scripts/build.js vue -f global -d && vitest --project e2e",
- "test-e2e-vapor": "pnpm run prepare-e2e-vapor && vitest --project e2e-vapor",
- "prepare-e2e-vapor": "node scripts/build.js -f cjs+esm-bundler+esm-bundler-runtime && pnpm run -C packages-private/vapor-e2e-test build",
"test-dts": "run-s build-dts test-dts-only",
"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",
"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 || node scripts/build.js -f cjs",
- "dev-compiler": "run-p \"dev template-explorer\" serve open",
- "dev-sfc": "run-s dev-prepare-cjs dev-sfc-run",
- "dev-sfc-serve": "vite packages-private/sfc-playground",
- "dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if esm-browser-vapor\" \"dev vue -ipf esm-browser-vapor\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve",
- "dev-vapor": "pnpm -C packages-private/local-playground run dev",
+ "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-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",
"serve": "serve",
"open": "open http://localhost:3000/packages-private/template-explorer/local.html",
- "build-sfc-playground": "run-s build-sfc-deps build-sfc-playground-self",
- "build-sfc-deps": "node scripts/build.js -f ~global+global-runtime",
- "build-sfc-playground-self": "pnpm run -C packages-private/sfc-playground build",
+ "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-sfc-playground-self": "cd packages-private/sfc-playground && npm run build",
"preinstall": "npx only-allow pnpm",
"postinstall": "simple-git-hooks"
},
"@types/node": "^22.16.0",
"@types/semver": "^7.7.0",
"@types/serve-handler": "^6.1.4",
- "@vitest/ui": "^3.0.2",
"@vitest/coverage-v8": "^3.1.4",
"@vitest/eslint-plugin": "^1.2.1",
"@vue/consolidate": "1.0.0",
+++ /dev/null
-<script setup>
-import { shallowRef, triggerRef } from 'vue'
-import { buildData } from './data'
-import { defer, wrap } from './profiling'
-
-const selected = shallowRef()
-const rows = shallowRef([])
-
-// Bench Add: https://jsbench.me/45lzxprzmu/1
-const add = wrap('add', () => {
- rows.value.push(...buildData(1000))
- triggerRef(rows)
-})
-
-const remove = wrap('remove', id => {
- rows.value.splice(
- rows.value.findIndex(d => d.id === id),
- 1,
- )
- triggerRef(rows)
-})
-
-const select = wrap('select', id => {
- selected.value = id
-})
-
-const run = wrap('run', () => {
- rows.value = buildData()
- selected.value = undefined
-})
-
-const update = wrap('update', () => {
- const _rows = rows.value
- for (let i = 0, len = _rows.length; i < len; i += 10) {
- _rows[i].label.value += ' !!!'
- }
-})
-
-const runLots = wrap('runLots', () => {
- rows.value = buildData(10000)
- selected.value = undefined
-})
-
-const clear = wrap('clear', () => {
- rows.value = []
- selected.value = undefined
-})
-
-const swapRows = wrap('swap', () => {
- const _rows = rows.value
- if (_rows.length > 998) {
- const d1 = _rows[1]
- const d998 = _rows[998]
- _rows[1] = d998
- _rows[998] = d1
- triggerRef(rows)
- }
-})
-
-async function bench() {
- for (let i = 0; i < 30; i++) {
- rows.value = []
- await runLots()
- await defer()
- }
-}
-
-const globalThis = window
-</script>
-
-<template>
- <h1>Vue.js (VDOM) Benchmark</h1>
-
- <div style="display: flex; gap: 4px; margin-bottom: 4px">
- <label>
- <input
- type="checkbox"
- :value="globalThis.doProfile"
- @change="globalThis.doProfile = $event.target.checked"
- />
- Profiling
- </label>
- <label>
- <input
- type="checkbox"
- :value="globalThis.reactivity"
- @change="globalThis.reactivity = $event.target.checked"
- />
- Reactivity Cost
- </label>
- </div>
-
- <div
- id="control"
- style="display: flex; flex-direction: column; width: fit-content; gap: 6px"
- >
- <button @click="bench">Benchmark mounting</button>
- <button id="run" @click="run">Create 1,000 rows</button>
- <button id="runlots" @click="runLots">Create 10,000 rows</button>
- <button id="add" @click="add">Append 1,000 rows</button>
- <button id="update" @click="update">Update every 10th row</button>
- <button id="clear" @click="clear">Clear</button>
- <button id="swaprows" @click="swapRows">Swap Rows</button>
- </div>
- <div id="time"></div>
- <table class="table table-hover table-striped test-data">
- <tbody>
- <tr
- v-for="row of rows"
- :key="row.id"
- :class="selected === row.id ? 'danger' : ''"
- >
- <td class="col-md-1">{{ row.id }}</td>
- <td class="col-md-4">
- <a @click="select(row.id)">{{ row.label.value }}</a>
- </td>
- <td class="col-md-1">
- <a @click="remove(row.id)">
- <span class="glyphicon glyphicon-remove" aria-hidden="true">x</span>
- </a>
- </td>
- <td class="col-md-6"></td>
- </tr>
- </tbody>
- </table>
- <span
- class="preloadicon glyphicon glyphicon-remove"
- aria-hidden="true"
- ></span>
-</template>
-
-<style>
-.danger {
- background-color: red;
-}
-</style>
+++ /dev/null
-<script setup vapor>
-import { shallowRef, triggerRef } from 'vue'
-import { buildData } from './data'
-import { defer, wrap } from './profiling'
-
-const selected = shallowRef()
-const rows = shallowRef([])
-
-// Bench Add: https://jsbench.me/45lzxprzmu/1
-const add = wrap('add', () => {
- rows.value.push(...buildData(1000))
- triggerRef(rows)
-})
-
-const remove = wrap('remove', id => {
- rows.value.splice(
- rows.value.findIndex(d => d.id === id),
- 1,
- )
- triggerRef(rows)
-})
-
-const select = wrap('select', id => {
- selected.value = id
-})
-
-const run = wrap('run', () => {
- rows.value = buildData()
- selected.value = undefined
-})
-
-const update = wrap('update', () => {
- const _rows = rows.value
- for (let i = 0, len = _rows.length; i < len; i += 10) {
- _rows[i].label.value += ' !!!'
- }
-})
-
-const runLots = wrap('runLots', () => {
- rows.value = buildData(10000)
- selected.value = undefined
-})
-
-const clear = wrap('clear', () => {
- rows.value = []
- selected.value = undefined
-})
-
-const swapRows = wrap('swap', () => {
- const _rows = rows.value
- if (_rows.length > 998) {
- const d1 = _rows[1]
- const d998 = _rows[998]
- _rows[1] = d998
- _rows[998] = d1
- triggerRef(rows)
- }
-})
-
-async function bench() {
- for (let i = 0; i < 30; i++) {
- rows.value = []
- await runLots()
- await defer()
- }
-}
-
-const globalThis = window
-</script>
-
-<template>
- <h1>Vue.js (Vapor) Benchmark</h1>
-
- <div style="display: flex; gap: 4px; margin-bottom: 4px">
- <label>
- <input
- type="checkbox"
- :value="globalThis.doProfile"
- @change="globalThis.doProfile = $event.target.checked"
- />
- Profiling
- </label>
- <label>
- <input
- type="checkbox"
- :value="globalThis.reactivity"
- @change="globalThis.reactivity = $event.target.checked"
- />
- Reactivity Cost
- </label>
- </div>
-
- <div
- id="control"
- style="display: flex; flex-direction: column; width: fit-content; gap: 6px"
- >
- <button @click="bench">Benchmark mounting</button>
- <button id="run" @click="run">Create 1,000 rows</button>
- <button id="runlots" @click="runLots">Create 10,000 rows</button>
- <button id="add" @click="add">Append 1,000 rows</button>
- <button id="update" @click="update">Update every 10th row</button>
- <button id="clear" @click="clear">Clear</button>
- <button id="swaprows" @click="swapRows">Swap Rows</button>
- </div>
- <div id="time"></div>
- <table class="table table-hover table-striped test-data">
- <tbody>
- <tr
- v-for="row of rows"
- :key="row.id"
- :class="selected === row.id ? 'danger' : ''"
- >
- <td class="col-md-1">{{ row.id }}</td>
- <td class="col-md-4">
- <a @click="select(row.id)">{{ row.label.value }}</a>
- </td>
- <td class="col-md-1">
- <a @click="remove(row.id)">
- <span class="glyphicon glyphicon-remove" aria-hidden="true">x</span>
- </a>
- </td>
- <td class="col-md-6"></td>
- </tr>
- </tbody>
- </table>
- <span
- class="preloadicon glyphicon glyphicon-remove"
- aria-hidden="true"
- ></span>
-</template>
-
-<style>
-.danger {
- background-color: red;
-}
-</style>
+++ /dev/null
-import { shallowRef } from 'vue'
-
-let ID = 1
-
-function _random(max: number) {
- return Math.round(Math.random() * 1000) % max
-}
-
-export function buildData(count = 1000) {
- const adjectives = [
- 'pretty',
- 'large',
- 'big',
- 'small',
- 'tall',
- 'short',
- 'long',
- 'handsome',
- 'plain',
- 'quaint',
- 'clean',
- 'elegant',
- 'easy',
- 'angry',
- 'crazy',
- 'helpful',
- 'mushy',
- 'odd',
- 'unsightly',
- 'adorable',
- 'important',
- 'inexpensive',
- 'cheap',
- 'expensive',
- 'fancy',
- ]
- const colours = [
- 'red',
- 'yellow',
- 'blue',
- 'green',
- 'pink',
- 'brown',
- 'purple',
- 'brown',
- 'white',
- 'black',
- 'orange',
- ]
- const nouns = [
- 'table',
- 'chair',
- 'house',
- 'bbq',
- 'desk',
- 'car',
- 'pony',
- 'cookie',
- 'sandwich',
- 'burger',
- 'pizza',
- 'mouse',
- 'keyboard',
- ]
- const data = []
- for (let i = 0; i < count; i++)
- data.push({
- id: ID++,
- label: shallowRef(
- adjectives[_random(adjectives.length)] +
- ' ' +
- colours[_random(colours.length)] +
- ' ' +
- nouns[_random(nouns.length)],
- ),
- })
- return data
-}
+++ /dev/null
-<!doctype html>
-<html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Vue Vapor Benchmark</title>
- <style>
- html {
- color-scheme: light dark;
- }
- </style>
- </head>
- <body class="done">
- <div id="app"></div>
- <script type="module" src="./index.ts"></script>
- </body>
-</html>
+++ /dev/null
-if (import.meta.env.IS_VAPOR) {
- import('./vapor')
-} else {
- import('./vdom')
-}
+++ /dev/null
-/* eslint-disable no-console */
-/* eslint-disable no-restricted-syntax */
-/* eslint-disable no-restricted-globals */
-
-import { nextTick } from 'vue'
-
-declare global {
- var doProfile: boolean
- var reactivity: boolean
- var recordTime: boolean
- var times: Record<string, number[]>
-}
-
-globalThis.recordTime = true
-globalThis.doProfile = false
-globalThis.reactivity = false
-
-export const defer = () => new Promise(r => requestIdleCallback(r))
-
-const times: Record<string, number[]> = (globalThis.times = {})
-
-export function wrap(
- id: string,
- fn: (...args: any[]) => any,
-): (...args: any[]) => Promise<void> {
- return async (...args) => {
- if (!globalThis.recordTime) {
- return fn(...args)
- }
-
- document.body.classList.remove('done')
-
- const { doProfile } = globalThis
- await nextTick()
-
- doProfile && console.profile(id)
- const start = performance.now()
- fn(...args)
-
- await nextTick()
- let time: number
- if (globalThis.reactivity) {
- time = performance.measure(
- 'flushJobs-measure',
- 'flushJobs-start',
- 'flushJobs-end',
- ).duration
- performance.clearMarks()
- performance.clearMeasures()
- } else {
- time = performance.now() - start
- }
- const prevTimes = times[id] || (times[id] = [])
- prevTimes.push(time)
-
- const { min, max, median, mean, std } = compute(prevTimes)
- const msg =
- `${id}: min: ${min} / ` +
- `max: ${max} / ` +
- `median: ${median}ms / ` +
- `mean: ${mean}ms / ` +
- `time: ${time.toFixed(2)}ms / ` +
- `std: ${std} ` +
- `over ${prevTimes.length} runs`
- doProfile && console.profileEnd(id)
- console.log(msg)
- const timeEl = document.getElementById('time')!
- timeEl.textContent = msg
-
- document.body.classList.add('done')
- }
-}
-
-function compute(array: number[]) {
- const n = array.length
- const max = Math.max(...array)
- const min = Math.min(...array)
- const mean = array.reduce((a, b) => a + b) / n
- const std = Math.sqrt(
- array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n,
- )
- const median = array.slice().sort((a, b) => a - b)[Math.floor(n / 2)]
- return {
- max: round(max),
- min: round(min),
- mean: round(mean),
- std: round(std),
- median: round(median),
- }
-}
-
-function round(n: number) {
- return +n.toFixed(2)
-}
+++ /dev/null
-import { createVaporApp } from 'vue'
-import App from './AppVapor.vue'
-
-createVaporApp(App as any).mount('#app')
+++ /dev/null
-import { createApp } from 'vue'
-import App from './App.vue'
-
-createApp(App).mount('#app')
+++ /dev/null
-// @ts-check
-import path from 'node:path'
-import { parseArgs } from 'node:util'
-import { mkdir, rm, writeFile } from 'node:fs/promises'
-import Vue from '@vitejs/plugin-vue'
-import { build } from 'vite'
-import connect from 'connect'
-import sirv from 'sirv'
-import { launch } from 'puppeteer'
-import colors from 'picocolors'
-import { exec, getSha } from '../../scripts/utils.js'
-import process from 'node:process'
-import readline from 'node:readline'
-
-// Thanks to https://github.com/krausest/js-framework-benchmark (Apache-2.0 license)
-const {
- values: {
- skipLib,
- skipApp,
- skipBench,
- vdom,
- noVapor,
- port: portStr,
- count: countStr,
- warmupCount: warmupCountStr,
- noHeadless,
- noMinify,
- reference,
- },
-} = parseArgs({
- allowNegative: true,
- allowPositionals: true,
- options: {
- skipLib: {
- type: 'boolean',
- short: 'l',
- },
- skipApp: {
- type: 'boolean',
- short: 'a',
- },
- skipBench: {
- type: 'boolean',
- short: 'b',
- },
- noVapor: {
- type: 'boolean',
- },
- vdom: {
- type: 'boolean',
- short: 'v',
- },
- port: {
- type: 'string',
- short: 'p',
- default: '8193',
- },
- count: {
- type: 'string',
- short: 'c',
- default: '30',
- },
- warmupCount: {
- type: 'string',
- short: 'w',
- default: '5',
- },
- noHeadless: {
- type: 'boolean',
- },
- noMinify: {
- type: 'boolean',
- },
- reference: {
- type: 'boolean',
- short: 'r',
- },
- },
-})
-
-const port = +(/** @type {string}*/ (portStr))
-const count = +(/** @type {string}*/ (countStr))
-const warmupCount = +(/** @type {string}*/ (warmupCountStr))
-const sha = await getSha(true)
-
-if (!skipLib && !reference) {
- await buildLib()
-}
-if (!skipApp && !reference) {
- await rm('client/dist', { recursive: true }).catch(() => {})
- vdom && (await buildApp(false))
- !noVapor && (await buildApp(true))
-}
-const server = startServer()
-
-if (!skipBench) {
- await benchmark()
- server.close()
-}
-
-async function buildLib() {
- console.info(colors.blue('Building lib...'))
-
- /** @type {import('node:child_process').SpawnOptions} */
- const options = {
- cwd: path.resolve(import.meta.dirname, '../..'),
- stdio: 'inherit',
- env: { ...process.env, BENCHMARK: 'true' },
- }
- const [{ ok }, { ok: ok2 }, { ok: ok3 }] = await Promise.all([
- exec(
- 'pnpm',
- `run --silent build shared compiler-core compiler-dom -pf cjs`.split(' '),
- options,
- ),
- exec(
- 'pnpm',
- 'run --silent build compiler-sfc compiler-ssr compiler-vapor -f cjs'.split(
- ' ',
- ),
- options,
- ),
- exec(
- 'pnpm',
- `run --silent build shared reactivity runtime-core runtime-dom runtime-vapor vue -f esm-bundler+esm-bundler-runtime`.split(
- ' ',
- ),
- options,
- ),
- ])
-
- if (!ok || !ok2 || !ok3) {
- console.error('Failed to build')
- process.exit(1)
- }
-}
-
-/** @param {boolean} isVapor */
-async function buildApp(isVapor) {
- console.info(
- colors.blue(`\nBuilding ${isVapor ? 'Vapor' : 'Virtual DOM'} app...\n`),
- )
-
- process.env.NODE_ENV = 'production'
-
- const CompilerSFC = await import(
- '../../packages/compiler-sfc/dist/compiler-sfc.cjs.js'
- )
-
- const runtimePath = path.resolve(
- import.meta.dirname,
- '../../packages/vue/dist/vue.runtime.esm-bundler.js',
- )
-
- const mode = isVapor ? 'vapor' : 'vdom'
- await build({
- root: './client',
- base: `/${mode}`,
- define: {
- 'import.meta.env.IS_VAPOR': String(isVapor),
- },
- build: {
- minify: !noMinify,
- outDir: path.resolve('./client/dist', mode),
- rollupOptions: {
- onwarn(log, handler) {
- if (log.code === 'INVALID_ANNOTATION') return
- handler(log)
- },
- },
- },
- resolve: {
- alias: {
- vue: runtimePath,
- },
- },
- clearScreen: false,
- plugins: [
- Vue({
- compiler: CompilerSFC,
- }),
- ],
- })
-}
-
-function startServer() {
- const server = connect()
- .use(sirv(reference ? './reference' : './client/dist', { dev: true }))
- .listen(port)
- printPort()
- process.on('SIGTERM', () => server.close())
- return server
-}
-
-async function benchmark() {
- console.info(colors.blue(`\nStarting benchmark...`))
-
- const browser = await initBrowser()
-
- await mkdir('results', { recursive: true }).catch(() => {})
- if (!noVapor) {
- await doBench(browser, true)
- }
- if (vdom) {
- await doBench(browser, false)
- }
-
- await browser.close()
-}
-
-/**
- * @param {boolean} isVapor
- */
-function getURL(isVapor) {
- return `http://localhost:${port}/${reference ? '' : isVapor ? 'vapor' : 'vdom'}/`
-}
-
-/**
- *
- * @param {import('puppeteer').Browser} browser
- * @param {boolean} isVapor
- */
-async function doBench(browser, isVapor) {
- const mode = reference ? `reference` : isVapor ? 'vapor' : 'vdom'
- console.info('\n\nmode:', mode)
-
- const page = await browser.newPage()
- page.emulateCPUThrottling(4)
- await page.goto(getURL(isVapor), {
- waitUntil: 'networkidle0',
- })
-
- await forceGC()
- const t = performance.now()
-
- console.log('warmup run')
- await eachRun(() => withoutRecord(benchOnce), warmupCount)
-
- console.log('benchmark run')
- await eachRun(benchOnce, count)
-
- console.info(
- 'Total time:',
- colors.cyan(((performance.now() - t) / 1000).toFixed(2)),
- 's',
- )
- const times = await getTimes()
- const result =
- /** @type {Record<string, typeof compute>} */
- Object.fromEntries(Object.entries(times).map(([k, v]) => [k, compute(v)]))
-
- console.table(result)
- await writeFile(
- `results/benchmark-${sha}-${mode}.json`,
- JSON.stringify(result, undefined, 2),
- )
- await page.close()
- return result
-
- async function benchOnce() {
- await clickButton('run') // test: create rows
- await clickButton('update') // partial update
- await clickButton('swaprows') // swap rows
- await select() // test: select row, remove row
- await clickButton('clear') // clear rows
-
- await withoutRecord(() => clickButton('run'))
- await clickButton('add') // append rows to large table
-
- await withoutRecord(() => clickButton('clear'))
- await clickButton('runlots') // create many rows
- await withoutRecord(() => clickButton('clear'))
-
- // TODO replace all rows
- }
-
- function getTimes() {
- return page.evaluate(() => /** @type {any} */ (globalThis).times)
- }
-
- async function forceGC() {
- await page.evaluate(
- `window.gc({type:'major',execution:'sync',flavor:'last-resort'})`,
- )
- }
-
- /** @param {() => any} fn */
- async function withoutRecord(fn) {
- const currentRecordTime = await page.evaluate(() => globalThis.recordTime)
- await page.evaluate(() => (globalThis.recordTime = false))
- await fn()
- await page.evaluate(
- currentRecordTime => (globalThis.recordTime = currentRecordTime),
- currentRecordTime,
- )
- }
-
- /** @param {string} id */
- async function clickButton(id) {
- await page.click(`#${id}`)
- await wait()
- }
-
- async function select() {
- for (let i = 1; i <= 10; i++) {
- await page.click(`tbody > tr:nth-child(2) > td:nth-child(2) > a`)
- await page.waitForSelector(`tbody > tr:nth-child(2).danger`)
- await page.click(`tbody > tr:nth-child(2) > td:nth-child(3) > a`)
- await wait()
- }
- }
-
- async function wait() {
- await page.waitForSelector('.done')
- }
-}
-
-/**
- * @param {Function} bench
- * @param {number} count
- */
-async function eachRun(bench, count) {
- for (let i = 0; i < count; i++) {
- readline.cursorTo(process.stdout, 0)
- readline.clearLine(process.stdout, 0)
- process.stdout.write(`${i + 1}/${count}`)
- await bench()
- }
- if (count === 0) {
- process.stdout.write('0/0 (skip)')
- }
- process.stdout.write('\n')
-}
-
-async function initBrowser() {
- const disableFeatures = [
- 'Translate', // avoid translation popups
- 'PrivacySandboxSettings4', // avoid privacy popup
- 'IPH_SidePanelGenericMenuFeature', // bookmark popup see https://github.com/krausest/js-framework-benchmark/issues/1688
- ]
-
- const args = [
- '--js-flags=--expose-gc', // needed for gc() function
- '--no-default-browser-check',
- '--disable-sync',
- '--no-first-run',
- '--ash-no-nudges',
- '--disable-extensions',
- `--disable-features=${disableFeatures.join(',')}`,
- ]
-
- const headless = !noHeadless
- console.info('headless:', headless)
- const browser = await launch({
- headless: headless,
- args,
- })
- console.log('browser version:', colors.blue(await browser.version()))
-
- return browser
-}
-
-/** @param {number[]} array */
-function compute(array) {
- const n = array.length
- const max = Math.max(...array)
- const min = Math.min(...array)
- const mean = array.reduce((a, b) => a + b) / n
- const std = Math.sqrt(
- array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n,
- )
- const median = array.slice().sort((a, b) => a - b)[Math.floor(n / 2)]
- return {
- max: round(max),
- min: round(min),
- mean: round(mean),
- std: round(std),
- median: round(median),
- }
-}
-
-/** @param {number} n */
-function round(n) {
- return +n.toFixed(2)
-}
-
-function printPort() {
- const vaporLink = !noVapor
- ? `\n${reference ? `Reference` : `Vapor`}: ${colors.blue(getURL(true))}`
- : ''
- const vdomLink = vdom ? `\nvDom: ${colors.blue(getURL(false))}` : ''
- console.info(`\n\nServer started at`, vaporLink, vdomLink)
-}
+++ /dev/null
-{
- "name": "benchmark",
- "version": "0.0.0",
- "author": "三咲智子 Kevin Deng <sxzz@sxzz.moe>",
- "license": "MIT",
- "type": "module",
- "scripts": {
- "dev": "pnpm start --noMinify --skipBench --vdom",
- "start": "node index.js"
- },
- "dependencies": {
- "@vitejs/plugin-vue": "catalog:",
- "connect": "^3.7.0",
- "sirv": "^2.0.4",
- "vite": "catalog:"
- },
- "devDependencies": {
- "@types/connect": "^3.4.38"
- }
-}
+++ /dev/null
-{
- "compilerOptions": {
- "target": "esnext",
- "lib": ["es2022", "dom"],
- "allowJs": true,
- "moduleDetection": "force",
- "module": "preserve",
- "moduleResolution": "bundler",
- "resolveJsonModule": true,
- "types": ["node", "vite/client"],
- "strict": true,
- "noUnusedLocals": true,
- "declaration": true,
- "esModuleInterop": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": true,
- "skipLibCheck": true,
- "noEmit": true,
- "paths": {
- "vue": ["../packages/vue/src/runtime-with-vapor.ts"],
- "@vue/*": ["../packages/*/src"]
- }
- },
- "include": ["**/*"]
-}
+++ /dev/null
-<!doctype html>
-<html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Vue Vapor</title>
- </head>
- <body>
- <div id="app"></div>
- <script type="module" src="./src/main.ts"></script>
- </body>
-</html>
+++ /dev/null
-{
- "name": "playground",
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "node ./setup/vite.js",
- "build": "vite build -c vite.prod.config.ts",
- "prepreview": "cd ../ && pnpm run build runtime-vapor -f esm-bundler",
- "preview": "pnpm run build && vite preview -c vite.prod.config.ts"
- },
- "dependencies": {
- "@vueuse/core": "^11.1.0",
- "vue": "workspace:*"
- },
- "devDependencies": {
- "@vitejs/plugin-vue": "catalog:",
- "@vue/compiler-sfc": "workspace:*",
- "vite": "catalog:",
- "vite-hyper-config": "^0.4.0",
- "vite-plugin-inspect": "^0.8.7"
- }
-}
+++ /dev/null
-// @ts-check
-import path from 'node:path'
-
-const resolve = (/** @type {string} */ p) =>
- path.resolve(import.meta.dirname, '../../../packages', p)
-
-/**
- * @param {Object} [env]
- * @param {boolean} [env.browser]
- * @returns {import('vite').Plugin}
- */
-export function DevPlugin({ browser = false } = {}) {
- return {
- name: 'dev-plugin',
- config() {
- return {
- resolve: {
- alias: {
- vue: resolve('vue/src/runtime-with-vapor.ts'),
-
- '@vue/runtime-core': resolve('runtime-core/src'),
- '@vue/runtime-dom': resolve('runtime-dom/src'),
- '@vue/runtime-vapor': resolve('runtime-vapor/src'),
-
- '@vue/compiler-core': resolve('compiler-core/src'),
- '@vue/compiler-dom': resolve('compiler-dom/src'),
- '@vue/compiler-vapor': resolve('compiler-vapor/src'),
-
- '@vue/compiler-sfc': resolve('compiler-sfc/src'),
- '@vue/compiler-ssr': resolve('compiler-ssr/src'),
-
- '@vue/reactivity': resolve('reactivity/src'),
- '@vue/shared': resolve('shared/src'),
- '@vue/runtime-shared': resolve('runtime-shared/src'),
- },
- },
- define: {
- __COMMIT__: `"__COMMIT__"`,
- __VERSION__: `"0.0.0"`,
- __DEV__: `true`,
- // this is only used during Vue's internal tests
- __TEST__: `false`,
- // If the build is expected to run directly in the browser (global / esm builds)
- __BROWSER__: String(browser),
- __GLOBAL__: String(false),
- __ESM_BUNDLER__: String(true),
- __ESM_BROWSER__: String(false),
- // is targeting Node (SSR)?
- __NODE_JS__: String(false),
- // need SSR-specific branches?
- __SSR__: String(false),
- __BENCHMARK__: 'false',
-
- // 2.x compat build
- __COMPAT__: String(false),
-
- // feature flags
- __FEATURE_SUSPENSE__: `true`,
- __FEATURE_OPTIONS_API__: `true`,
- __FEATURE_PROD_DEVTOOLS__: `false`,
- __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__: `false`,
- },
- }
- },
- }
-}
+++ /dev/null
-// @ts-check
-
-import { startVite } from 'vite-hyper-config'
-import { DevPlugin } from './dev.js'
-
-startVite(
- undefined,
- { plugins: [DevPlugin()] },
- {
- deps: {
- inline: ['@vitejs/plugin-vue'],
- },
- },
-)
+++ /dev/null
-*
-!.gitignore
-!App.vue
-!main.ts
-!style.css
+++ /dev/null
-<script setup lang="ts">
-import { ref } from 'vue'
-import VaporComp from './VaporComp.vue'
-
-const msg = ref('hello')
-const passSlot = ref(true)
-</script>
-
-<template>
- <input v-model="msg" />
- <button @click="passSlot = !passSlot">toggle #test slot</button>
- <VaporComp :msg="msg">
- <template #default="{ foo }">
- <div>slot props: {{ foo }}</div>
- <div>component prop: {{ msg }}</div>
- </template>
-
- <template #test v-if="passSlot"> A test slot </template>
- </VaporComp>
-</template>
+++ /dev/null
-import './_entry'
+++ /dev/null
-.red {
- color: red;
-}
-.green {
- color: green;
-}
+++ /dev/null
-{
- "extends": "../tsconfig.json",
- "compilerOptions": {
- "isolatedDeclarations": false,
- "allowJs": true
- },
- "include": ["./**/*", "../../packages/*/src"]
-}
+++ /dev/null
-import { defineConfig } from 'vite'
-import Inspect from 'vite-plugin-inspect'
-import { DevPlugin } from './setup/dev'
-import Vue from '@vitejs/plugin-vue'
-import * as CompilerSFC from '@vue/compiler-sfc'
-
-export default defineConfig({
- clearScreen: false,
- plugins: [
- Vue({
- compiler: CompilerSFC,
- }),
- DevPlugin(),
- Inspect(),
- ],
- optimizeDeps: {
- exclude: ['@vueuse/core'],
- },
-})
+++ /dev/null
-import { defineConfig } from 'vite'
-import Vue from '@vitejs/plugin-vue'
-import * as CompilerSFC from '@vue/compiler-sfc'
-
-export default defineConfig({
- build: {
- modulePreload: false,
- target: 'esnext',
- minify: 'terser',
- terserOptions: {
- format: { comments: false },
- compress: {
- pure_getters: true,
- },
- },
- },
- clearScreen: false,
- plugins: [
- Vue({
- compiler: CompilerSFC,
- features: {
- optionsAPI: false,
- },
- }),
- ],
-})
<script setup lang="ts">
import Header from './Header.vue'
-import {
- Repl,
- type SFCOptions,
- useStore,
- useVueImportMap,
- StoreState,
-} from '@vue/repl'
+import { Repl, useStore, SFCOptions, useVueImportMap } from '@vue/repl'
import Monaco from '@vue/repl/monaco-editor'
import { ref, watchEffect, onMounted, computed } from 'vue'
)
const autoSave = ref(initAutoSave)
-const { vueVersion, productionMode, importMap } = useVueImportMap({
- runtimeDev: () => {
- return import.meta.env.PROD
- ? `${location.origin}/vue.runtime-with-vapor.esm-browser.js`
- : `${location.origin}/src/vue-dev-proxy`
- },
- runtimeProd: () => {
- return import.meta.env.PROD
- ? `${location.origin}/vue.runtime-with-vapor.esm-browser.prod.js`
- : `${location.origin}/src/vue-dev-proxy-prod`
- },
+const { productionMode, vueVersion, importMap } = useVueImportMap({
+ runtimeDev: import.meta.env.PROD
+ ? `${location.origin}/vue.runtime.esm-browser.js`
+ : `${location.origin}/src/vue-dev-proxy`,
+ runtimeProd: import.meta.env.PROD
+ ? `${location.origin}/vue.runtime.esm-browser.prod.js`
+ : `${location.origin}/src/vue-dev-proxy-prod`,
serverRenderer: import.meta.env.PROD
? `${location.origin}/server-renderer.esm-browser.js`
: `${location.origin}/src/vue-server-renderer-dev-proxy`,
useSSRMode.value = true
}
-const files: StoreState['files'] = ref(Object.create(null))
-
// enable experimental features
const sfcOptions = computed(
(): SFCOptions => ({
inlineTemplate: productionMode.value,
isProd: productionMode.value,
propsDestructure: true,
- // vapor: useVaporMode.value,
},
style: {
isProd: productionMode.value,
},
template: {
- // vapor: useVaporMode.value,
isProd: productionMode.value,
compilerOptions: {
isCustomElement: (tag: string) =>
const store = useStore(
{
- files,
- vueVersion,
builtinImportMap: importMap,
+ vueVersion,
sfcOptions,
},
hash,
:clearConsole="false"
:preview-options="{
customCode: {
- importCode: `import { initCustomFormatter, vaporInteropPlugin } from 'vue'`,
- useCode: `
- app.use(vaporInteropPlugin)
- if (window.devtoolsFormatters) {
+ importCode: `import { initCustomFormatter } from 'vue'`,
+ useCode: `if (window.devtoolsFormatters) {
const index = window.devtoolsFormatters.findIndex((v) => v.__vue_custom_formatter)
window.devtoolsFormatters.splice(index, 1)
initCustomFormatter()
'toggle-theme',
'toggle-ssr',
'toggle-prod',
- 'toggle-vapor',
'toggle-autosave',
'reload-page',
])
}
.toggle-prod span,
-.toggle-vapor span,
.toggle-ssr span,
.toggle-autosave span {
font-size: 12px;
background-color: var(--green);
}
-.toggle-vapor span {
- background-color: var(--btn-bg);
-}
-
-.toggle-vapor.enabled span {
- color: #fff;
- background-color: var(--green);
-}
-
.toggle-dark svg {
width: 18px;
height: 18px;
// serve vue to the iframe sandbox during dev.
-export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.prod.js'
+export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
// serve vue to the iframe sandbox during dev.
-export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.js'
+export * from 'vue'
+++ /dev/null
-<script setup lang="ts">
-import { ref } from 'vue'
-
-const msg = ref('Hello World!')
-</script>
-
-<template>
- <h1>{{ msg }}</h1>
-</template>
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(`vue/dist/vue.runtime-with-vapor.esm-browser.js`)
- copyFile(`vue/dist/vue.runtime-with-vapor.esm-browser.prod.js`)
copyFile(`server-renderer/dist/server-renderer.esm-browser.js`)
},
}
"enableNonBrowserBranches": true
},
"dependencies": {
- "@vue/compiler-vapor": "workspace:^",
"monaco-editor": "^0.52.2",
"source-map-js": "^1.2.1"
}
import type * as m from 'monaco-editor'
-import type { CompilerError } from '@vue/compiler-dom'
-import { compile } from '@vue/compiler-dom'
import {
+ type CompilerError,
type CompilerOptions,
- compile as vaporCompile,
-} from '@vue/compiler-vapor'
-// import { compile as ssrCompile } from '@vue/compiler-ssr'
-
+ compile,
+} from '@vue/compiler-dom'
+import { compile as ssrCompile } from '@vue/compiler-ssr'
import {
compilerOptions,
defaultOptions,
initOptions,
ssrMode,
- vaporMode,
} from './options'
import { toRaw, watchEffect } from '@vue/runtime-dom'
import { SourceMapConsumer } from 'source-map-js'
console.clear()
try {
const errors: CompilerError[] = []
- const compileFn = /* ssrMode.value ? ssrCompile : */ (
- vaporMode.value ? vaporCompile : compile
- ) as typeof vaporCompile
+ const compileFn = ssrMode.value ? ssrCompile : compile
const start = performance.now()
const { code, ast, map } = compileFn(source, {
...compilerOptions,
- prefixIdentifiers:
- compilerOptions.prefixIdentifiers ||
- compilerOptions.mode === 'module' ||
- compilerOptions.ssr,
filename: 'ExampleTemplate.vue',
sourceMap: true,
onError: err => {
import { createApp, h, reactive, ref } from 'vue'
-import type { CompilerOptions } from '@vue/compiler-vapor'
+import type { CompilerOptions } from '@vue/compiler-dom'
import { BindingTypes } from '@vue/compiler-core'
export const ssrMode = ref(false)
-export const vaporMode = ref(true)
export const defaultOptions: CompilerOptions = {
mode: 'module',
compilerOptions.prefixIdentifiers || compilerOptions.mode === 'module'
return [
- h('h1', `Vue Template Explorer`),
+ h('h1', `Vue 3 Template Explorer`),
h(
'a',
{
- href: `https://github.com/vuejs/vue/tree/${__COMMIT__}`,
+ href: `https://github.com/vuejs/core/tree/${__COMMIT__}`,
target: `_blank`,
},
`@${__COMMIT__}`,
}),
h('label', { for: 'compat' }, 'v2 compat mode'),
]),
-
- h('li', [
- h('input', {
- type: 'checkbox',
- id: 'vapor',
- checked: vaporMode.value,
- onChange(e: Event) {
- vaporMode.value = (e.target as HTMLInputElement).checked
- },
- }),
- h('label', { for: 'vapor' }, 'vapor'),
- ]),
]),
]),
]
"compilerOptions": {
"isolatedDeclarations": false
},
- "include": [".", "../packages/vue/__tests__/e2e/e2eUtils.ts"]
+ "include": ["."]
}
+++ /dev/null
-import path from 'node:path'
-import {
- E2E_TIMEOUT,
- setupPuppeteer,
-} from '../../../packages/vue/__tests__/e2e/e2eUtils'
-import connect from 'connect'
-import sirv from 'sirv'
-
-describe('e2e: todomvc', () => {
- const {
- page,
- click,
- isVisible,
- count,
- text,
- value,
- isChecked,
- isFocused,
- classList,
- enterValue,
- clearValue,
- timeout,
- } = setupPuppeteer()
-
- let server: any
- const port = '8194'
- beforeAll(() => {
- server = connect()
- .use(sirv(path.resolve(import.meta.dirname, '../dist')))
- .listen(port)
- process.on('SIGTERM', () => server && server.close())
- })
-
- afterAll(() => {
- server.close()
- })
-
- async function removeItemAt(n: number) {
- const item = (await page().$('.todo:nth-child(' + n + ')'))!
- const itemBBox = (await item.boundingBox())!
- await page().mouse.move(itemBBox.x + 10, itemBBox.y + 10)
- await click('.todo:nth-child(' + n + ') .destroy')
- }
-
- test(
- 'vapor',
- async () => {
- const baseUrl = `http://localhost:${port}/todomvc/`
- await page().goto(baseUrl)
-
- expect(await isVisible('.main')).toBe(false)
- expect(await isVisible('.footer')).toBe(false)
- expect(await count('.filters .selected')).toBe(1)
- expect(await text('.filters .selected')).toBe('All')
- expect(await count('.todo')).toBe(0)
-
- await enterValue('.new-todo', 'test')
- expect(await count('.todo')).toBe(1)
- expect(await isVisible('.todo .edit')).toBe(false)
- expect(await text('.todo label')).toBe('test')
- expect(await text('.todo-count strong')).toBe('1')
- expect(await isChecked('.todo .toggle')).toBe(false)
- expect(await isVisible('.main')).toBe(true)
- expect(await isVisible('.footer')).toBe(true)
- expect(await isVisible('.clear-completed')).toBe(false)
- expect(await value('.new-todo')).toBe('')
-
- await enterValue('.new-todo', 'test2')
- expect(await count('.todo')).toBe(2)
- expect(await text('.todo:nth-child(2) label')).toBe('test2')
- expect(await text('.todo-count strong')).toBe('2')
-
- // toggle
- await click('.todo .toggle')
- expect(await count('.todo.completed')).toBe(1)
- expect(await classList('.todo:nth-child(1)')).toContain('completed')
- expect(await text('.todo-count strong')).toBe('1')
- expect(await isVisible('.clear-completed')).toBe(true)
-
- await enterValue('.new-todo', 'test3')
- expect(await count('.todo')).toBe(3)
- expect(await text('.todo:nth-child(3) label')).toBe('test3')
- expect(await text('.todo-count strong')).toBe('2')
-
- await enterValue('.new-todo', 'test4')
- await enterValue('.new-todo', 'test5')
- expect(await count('.todo')).toBe(5)
- expect(await text('.todo-count strong')).toBe('4')
-
- // toggle more
- await click('.todo:nth-child(4) .toggle')
- await click('.todo:nth-child(5) .toggle')
- expect(await count('.todo.completed')).toBe(3)
- expect(await text('.todo-count strong')).toBe('2')
-
- // remove
- await removeItemAt(1)
- expect(await count('.todo')).toBe(4)
- expect(await count('.todo.completed')).toBe(2)
- expect(await text('.todo-count strong')).toBe('2')
- await removeItemAt(2)
- expect(await count('.todo')).toBe(3)
- expect(await count('.todo.completed')).toBe(2)
- expect(await text('.todo-count strong')).toBe('1')
-
- // remove all
- await click('.clear-completed')
- expect(await count('.todo')).toBe(1)
- expect(await text('.todo label')).toBe('test2')
- expect(await count('.todo.completed')).toBe(0)
- expect(await text('.todo-count strong')).toBe('1')
- expect(await isVisible('.clear-completed')).toBe(false)
-
- // prepare to test filters
- await enterValue('.new-todo', 'test')
- await enterValue('.new-todo', 'test')
- await click('.todo:nth-child(2) .toggle')
- await click('.todo:nth-child(3) .toggle')
-
- // active filter
- await click('.filters li:nth-child(2) a')
- await timeout(1)
- expect(await count('.todo')).toBe(1)
- expect(await count('.todo.completed')).toBe(0)
- // add item with filter active
- await enterValue('.new-todo', 'test')
- expect(await count('.todo')).toBe(2)
-
- // completed filter
- await click('.filters li:nth-child(3) a')
- await timeout(1)
- expect(await count('.todo')).toBe(2)
- expect(await count('.todo.completed')).toBe(2)
-
- // filter on page load
- await page().goto(`${baseUrl}#active`)
- expect(await count('.todo')).toBe(2)
- expect(await count('.todo.completed')).toBe(0)
- expect(await text('.todo-count strong')).toBe('2')
-
- // completed on page load
- await page().goto(`${baseUrl}#completed`)
- expect(await count('.todo')).toBe(2)
- expect(await count('.todo.completed')).toBe(2)
- expect(await text('.todo-count strong')).toBe('2')
-
- // toggling with filter active
- await click('.todo .toggle')
- expect(await count('.todo')).toBe(1)
- await click('.filters li:nth-child(2) a')
- await timeout(1)
- expect(await count('.todo')).toBe(3)
- await click('.todo .toggle')
- expect(await count('.todo')).toBe(2)
-
- // editing triggered by blur
- await click('.filters li:nth-child(1) a')
- await timeout(1)
- await click('.todo:nth-child(1) label', { clickCount: 2 })
- expect(await count('.todo.editing')).toBe(1)
- expect(await isFocused('.todo:nth-child(1) .edit')).toBe(true)
- await clearValue('.todo:nth-child(1) .edit')
- await page().type('.todo:nth-child(1) .edit', 'edited!')
- await click('.new-todo') // blur
- expect(await count('.todo.editing')).toBe(0)
- expect(await text('.todo:nth-child(1) label')).toBe('edited!')
-
- // editing triggered by enter
- await click('.todo label', { clickCount: 2 })
- await enterValue('.todo:nth-child(1) .edit', 'edited again!')
- expect(await count('.todo.editing')).toBe(0)
- expect(await text('.todo:nth-child(1) label')).toBe('edited again!')
-
- // cancel
- await click('.todo label', { clickCount: 2 })
- await clearValue('.todo:nth-child(1) .edit')
- await page().type('.todo:nth-child(1) .edit', 'edited!')
- await page().keyboard.press('Escape')
- expect(await count('.todo.editing')).toBe(0)
- expect(await text('.todo:nth-child(1) label')).toBe('edited again!')
-
- // empty value should remove
- await click('.todo label', { clickCount: 2 })
- await enterValue('.todo:nth-child(1) .edit', ' ')
- expect(await count('.todo')).toBe(3)
-
- // toggle all
- await click('.toggle-all+label')
- expect(await count('.todo.completed')).toBe(3)
- await click('.toggle-all+label')
- expect(await count('.todo:not(.completed)')).toBe(3)
- },
- E2E_TIMEOUT,
- )
-})
+++ /dev/null
-import path from 'node:path'
-import {
- E2E_TIMEOUT,
- setupPuppeteer,
-} from '../../../packages/vue/__tests__/e2e/e2eUtils'
-import connect from 'connect'
-import sirv from 'sirv'
-
-describe('vdom / vapor interop', () => {
- const { page, click, text, enterValue } = setupPuppeteer()
-
- let server: any
- const port = '8193'
- beforeAll(() => {
- server = connect()
- .use(sirv(path.resolve(import.meta.dirname, '../dist')))
- .listen(port)
- process.on('SIGTERM', () => server && server.close())
- })
-
- afterAll(() => {
- server.close()
- })
-
- test(
- 'should work',
- async () => {
- const baseUrl = `http://localhost:${port}/interop/`
- await page().goto(baseUrl)
-
- expect(await text('.vapor > h2')).toContain('Vapor component in VDOM')
-
- expect(await text('.vapor-prop')).toContain('hello')
-
- const t = await text('.vdom-slot-in-vapor-default')
- expect(t).toContain('slot prop: slot prop')
- expect(t).toContain('component prop: hello')
-
- await click('.change-vdom-slot-in-vapor-prop')
- expect(await text('.vdom-slot-in-vapor-default')).toContain(
- 'slot prop: changed',
- )
-
- expect(await text('.vdom-slot-in-vapor-test')).toContain('A test slot')
-
- await click('.toggle-vdom-slot-in-vapor')
- expect(await text('.vdom-slot-in-vapor-test')).toContain(
- 'fallback content',
- )
-
- await click('.toggle-vdom-slot-in-vapor')
- expect(await text('.vdom-slot-in-vapor-test')).toContain('A test slot')
-
- expect(await text('.vdom > h2')).toContain('VDOM component in Vapor')
-
- expect(await text('.vdom-prop')).toContain('hello')
-
- const tt = await text('.vapor-slot-in-vdom-default')
- expect(tt).toContain('slot prop: slot prop')
- expect(tt).toContain('component prop: hello')
-
- await click('.change-vapor-slot-in-vdom-prop')
- expect(await text('.vapor-slot-in-vdom-default')).toContain(
- 'slot prop: changed',
- )
-
- expect(await text('.vapor-slot-in-vdom-test')).toContain('fallback')
-
- await click('.toggle-vapor-slot-in-vdom-default')
- expect(await text('.vapor-slot-in-vdom-default')).toContain(
- 'default slot fallback',
- )
-
- await click('.toggle-vapor-slot-in-vdom-default')
-
- await enterValue('input', 'bye')
- expect(await text('.vapor-prop')).toContain('bye')
- expect(await text('.vdom-slot-in-vapor-default')).toContain('bye')
- expect(await text('.vdom-prop')).toContain('bye')
- expect(await text('.vapor-slot-in-vdom-default')).toContain('bye')
- },
- E2E_TIMEOUT,
- )
-})
+++ /dev/null
-<a href="/interop/">VDOM / Vapor interop</a>
-<a href="/todomvc/">Vapor TodoMVC</a>
+++ /dev/null
-<script setup lang="ts">
-import { ref } from 'vue'
-import VaporComp from './VaporComp.vue'
-
-const msg = ref('hello')
-const passSlot = ref(true)
-</script>
-
-<template>
- <input v-model="msg" />
- <button class="toggle-vdom-slot-in-vapor" @click="passSlot = !passSlot">
- toggle #test slot
- </button>
- <VaporComp :msg="msg">
- <template #default="{ foo }">
- <div>slot prop: {{ foo }}</div>
- <div>component prop: {{ msg }}</div>
- </template>
-
- <template #test v-if="passSlot">A test slot</template>
- </VaporComp>
-</template>
+++ /dev/null
-<script setup vapor lang="ts">
-import { ref } from 'vue'
-import VdomComp from './VdomComp.vue'
-
-defineProps<{
- msg: string
-}>()
-
-const ok = ref(true)
-const passSlot = ref(true)
-const slotProp = ref('slot prop')
-</script>
-
-<template>
- <div class="vapor" style="border: 2px solid red; padding: 10px">
- <h2>This is a Vapor component in VDOM</h2>
- <p class="vapor-prop">props.msg: {{ msg }}</p>
-
- <button @click="ok = !ok">Toggle slots</button>
-
- <div v-if="ok" style="border: 2px solid orange; padding: 10px">
- <h3>vdom slots in vapor component</h3>
- <button
- class="change-vdom-slot-in-vapor-prop"
- @click="slotProp = 'changed'"
- >
- change slot prop
- </button>
- <div class="vdom-slot-in-vapor-default">
- #default: <slot :foo="slotProp" />
- </div>
- <div class="vdom-slot-in-vapor-test">
- #test: <slot name="test">fallback content</slot>
- </div>
- </div>
-
- <button
- class="toggle-vapor-slot-in-vdom-default"
- @click="passSlot = !passSlot"
- >
- Toggle default slot to vdom
- </button>
- <VdomComp :msg="msg">
- <template #default="{ foo }" v-if="passSlot">
- <div>slot prop: {{ foo }}</div>
- <div>component prop: {{ msg }}</div>
- </template>
- </VdomComp>
- </div>
-</template>
+++ /dev/null
-<script setup lang="ts">
-import { ref } from 'vue'
-
-defineProps<{
- msg: string
-}>()
-
-const bar = ref('slot prop')
-</script>
-
-<template>
- <div class="vdom" style="border: 2px solid blue; padding: 10px">
- <h2>This is a VDOM component in Vapor</h2>
- <p class="vdom-prop">props.msg: {{ msg }}</p>
- <div style="border: 2px solid aquamarine; padding: 10px">
- <h3>vapor slots in vdom</h3>
- <button class="change-vapor-slot-in-vdom-prop" @click="bar = 'changed'">
- Change slot prop
- </button>
- <div class="vapor-slot-in-vdom-default">
- #default: <slot :foo="bar">default slot fallback</slot>
- </div>
- <div class="vapor-slot-in-vdom-test">
- #test <slot name="test">fallback</slot>
- </div>
- </div>
- </div>
-</template>
+++ /dev/null
-<script type="module" src="./main.ts"></script>
-<div id="app"></div>
+++ /dev/null
-import { createApp, vaporInteropPlugin } from 'vue'
-import App from './App.vue'
-
-createApp(App).use(vaporInteropPlugin).mount('#app')
+++ /dev/null
-{
- "name": "vapor-e2e-test",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite dev",
- "build": "vite build"
- },
- "devDependencies": {
- "@types/connect": "^3.4.38",
- "@vitejs/plugin-vue": "catalog:",
- "connect": "^3.7.0",
- "sirv": "^2.0.4",
- "vite": "catalog:",
- "vue": "workspace:*"
- }
-}
+++ /dev/null
-<script setup vapor>
-import {
- reactive,
- computed,
- onMounted,
- onUnmounted,
- watchPostEffect,
-} from 'vue'
-
-const STORAGE_KEY = 'todos-vuejs-3.x'
-
-const todoStorage = {
- fetch() {
- const todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
- todos.forEach((todo, index) => {
- todo.id = index
- })
- todoStorage.uid = todos.length
- return todos
- },
- save(todos) {
- localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
- },
-}
-
-const filters = {
- all(todos) {
- return todos
- },
- active(todos) {
- return todos.filter(todo => {
- return !todo.completed
- })
- },
- completed(todos) {
- return todos.filter(function (todo) {
- return todo.completed
- })
- },
-}
-
-function pluralize(n) {
- return n === 1 ? 'item' : 'items'
-}
-
-const state = reactive({
- todos: todoStorage.fetch(),
- editedTodo: null,
- newTodo: '',
- beforeEditCache: '',
- visibility: 'all',
- remaining: computed(() => {
- return filters.active(state.todos).length
- }),
- remainingText: computed(() => {
- return ` ${pluralize(state.remaining)} left`
- }),
- filteredTodos: computed(() => {
- return filters[state.visibility](state.todos)
- }),
- allDone: computed({
- get: function () {
- return state.remaining === 0
- },
- set: function (value) {
- state.todos.forEach(todo => {
- todo.completed = value
- })
- },
- }),
-})
-
-watchPostEffect(() => {
- todoStorage.save(state.todos)
-})
-
-onMounted(() => {
- window.addEventListener('hashchange', onHashChange)
- onHashChange()
-})
-
-onUnmounted(() => {
- window.removeEventListener('hashchange', onHashChange)
-})
-
-function onHashChange() {
- const visibility = window.location.hash.replace(/#\/?/, '')
- if (filters[visibility]) {
- state.visibility = visibility
- } else {
- window.location.hash = ''
- state.visibility = 'all'
- }
-}
-
-function addTodo() {
- const value = state.newTodo && state.newTodo.trim()
- if (!value) {
- return
- }
- state.todos.push({
- id: todoStorage.uid++,
- title: value,
- completed: false,
- })
- state.newTodo = ''
-}
-
-function removeTodo(todo) {
- state.todos.splice(state.todos.indexOf(todo), 1)
-}
-
-function editTodo(todo) {
- state.beforeEditCache = todo.title
- state.editedTodo = todo
-}
-
-function doneEdit(todo) {
- if (!state.editedTodo) {
- return
- }
- state.editedTodo = null
- todo.title = todo.title.trim()
- if (!todo.title) {
- removeTodo(todo)
- }
-}
-
-function cancelEdit(todo) {
- state.editedTodo = null
- todo.title = state.beforeEditCache
-}
-
-function removeCompleted() {
- state.todos = filters.active(state.todos)
-}
-
-// vapor custom directive
-const vTodoFocus = (el, value) => {
- watchPostEffect(() => value() && el.focus())
-}
-</script>
-
-<template>
- <section class="todoapp">
- <header class="header">
- <h1>todos</h1>
- <input
- class="new-todo"
- autofocus
- autocomplete="off"
- placeholder="What needs to be done?"
- v-model="state.newTodo"
- @keyup.enter="addTodo"
- />
- </header>
- <section class="main" v-show="state.todos.length">
- <input
- id="toggle-all"
- class="toggle-all"
- type="checkbox"
- v-model="state.allDone"
- />
- <label for="toggle-all">Mark all as complete</label>
- <ul class="todo-list">
- <li
- v-for="todo in state.filteredTodos"
- class="todo"
- :key="todo.id"
- :class="{
- completed: todo.completed,
- editing: todo === state.editedTodo,
- }"
- >
- <div class="view">
- <input class="toggle" type="checkbox" v-model="todo.completed" />
- <label @dblclick="editTodo(todo)">{{ todo.title }}</label>
- <button class="destroy" @click="removeTodo(todo)"></button>
- </div>
- <input
- class="edit"
- type="text"
- v-model="todo.title"
- v-todo-focus="todo === state.editedTodo"
- @blur="doneEdit(todo)"
- @keyup.enter="doneEdit(todo)"
- @keyup.escape="cancelEdit(todo)"
- />
- </li>
- </ul>
- </section>
- <footer class="footer" v-show="state.todos.length">
- <span class="todo-count">
- <strong>{{ state.remaining }}</strong>
- <span>{{ state.remainingText }}</span>
- </span>
- <ul class="filters">
- <li>
- <a href="#/all" :class="{ selected: state.visibility === 'all' }"
- >All</a
- >
- </li>
- <li>
- <a
- href="#/active"
- :class="{ selected: state.visibility === 'active' }"
- >Active</a
- >
- </li>
- <li>
- <a
- href="#/completed"
- :class="{ selected: state.visibility === 'completed' }"
- >Completed</a
- >
- </li>
- </ul>
-
- <button
- class="clear-completed"
- @click="removeCompleted"
- v-show="state.todos.length > state.remaining"
- >
- Clear completed
- </button>
- </footer>
- </section>
-</template>
+++ /dev/null
-<script type="module" src="./main.ts"></script>
-<div id="app"></div>
+++ /dev/null
-import { createVaporApp } from 'vue'
-import App from './App.vue'
-import 'todomvc-app-css/index.css'
-
-createVaporApp(App).mount('#app')
+++ /dev/null
-import { defineConfig } from 'vite'
-import Vue from '@vitejs/plugin-vue'
-import * as CompilerSFC from 'vue/compiler-sfc'
-import { resolve } from 'node:path'
-
-export default defineConfig({
- plugins: [
- Vue({
- compiler: CompilerSFC,
- }),
- ],
- build: {
- rollupOptions: {
- input: {
- interop: resolve(import.meta.dirname, 'interop/index.html'),
- todomvc: resolve(import.meta.dirname, 'todomvc/index.html'),
- },
- },
- },
-})
column: number
}
-export type AllNode =
- | ParentNode
- | ExpressionNode
- | TemplateChildNode
- | AttributeNode
- | DirectiveNode
-
export type ParentNode = RootNode | ElementNode | IfBranchNode | ForNode
export type ExpressionNode = SimpleExpressionNode | CompoundExpressionNode
Program,
} from '@babel/types'
import { walk } from 'estree-walker'
-import { type BindingMetadata, BindingTypes } from './options'
/**
* Return value indicates whether the AST walked can be a constant
return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
}
-export const isStaticProperty = (node?: Node): node is ObjectProperty =>
- !!node &&
+export const isStaticProperty = (node: Node): node is ObjectProperty =>
+ node &&
(node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
!node.computed
return node
}
}
-
-export function isStaticNode(node: Node): boolean {
- node = unwrapTSNode(node)
-
- switch (node.type) {
- case 'UnaryExpression': // void 0, !true
- return isStaticNode(node.argument)
-
- case 'LogicalExpression': // 1 > 2
- case 'BinaryExpression': // 1 + 2
- return isStaticNode(node.left) && isStaticNode(node.right)
-
- case 'ConditionalExpression': {
- // 1 ? 2 : 3
- return (
- isStaticNode(node.test) &&
- isStaticNode(node.consequent) &&
- isStaticNode(node.alternate)
- )
- }
-
- case 'SequenceExpression': // (1, 2)
- case 'TemplateLiteral': // `foo${1}`
- return node.expressions.every(expr => isStaticNode(expr))
-
- case 'ParenthesizedExpression': // (1)
- return isStaticNode(node.expression)
-
- case 'StringLiteral':
- case 'NumericLiteral':
- case 'BooleanLiteral':
- case 'NullLiteral':
- case 'BigIntLiteral':
- return true
- }
- return false
-}
-
-export function isConstantNode(node: Node, bindings: BindingMetadata): boolean {
- if (isStaticNode(node)) return true
-
- node = unwrapTSNode(node)
- switch (node.type) {
- case 'Identifier':
- const type = bindings[node.name]
- return type === BindingTypes.LITERAL_CONST
- case 'RegExpLiteral':
- return true
- case 'ObjectExpression':
- return node.properties.every(prop => {
- // { bar() {} } object methods are not considered static nodes
- if (prop.type === 'ObjectMethod') return false
- // { ...{ foo: 1 } }
- if (prop.type === 'SpreadElement')
- return isConstantNode(prop.argument, bindings)
- // { foo: 1 }
- return (
- (!prop.computed || isConstantNode(prop.key, bindings)) &&
- isConstantNode(prop.value, bindings)
- )
- })
- case 'ArrayExpression':
- return node.elements.every(element => {
- // [1, , 3]
- if (element === null) return true
- // [1, ...[2, 3]]
- if (element.type === 'SpreadElement')
- return isConstantNode(element.argument, bindings)
- // [1, 2]
- return isConstantNode(element, bindings)
- })
- }
- return false
-}
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
-export interface BaseCodegenResult {
+export interface CodegenResult {
code: string
preamble: string
- ast: unknown
- map?: RawSourceMap
- helpers?: Set<string> | Set<symbol>
-}
-
-export interface CodegenResult extends BaseCodegenResult {
ast: RootNode
- helpers: Set<symbol>
+ map?: RawSourceMap
}
-export enum NewlineType {
- /** Start with `\n` */
+enum NewlineType {
Start = 0,
- /** Ends with `\n` */
End = -1,
- /** No `\n` included */
None = -2,
- /** Don't know, calc it */
Unknown = -3,
}
export interface CodegenContext
- extends Omit<
- Required<CodegenOptions>,
- | 'bindingMetadata'
- | 'inline'
- | 'vaporRuntimeModuleName'
- | 'expressionPlugins'
- > {
+ extends Omit<Required<CodegenOptions>, 'bindingMetadata' | 'inline'> {
source: string
code: string
line: number
code: context.code,
preamble: isSetupInlined ? preambleContext.code : ``,
map: context.map ? context.map.toJSON() : undefined,
- helpers: ast.helpers,
}
}
createTransformContext,
traverseNode,
createStructuralDirectiveTransform,
- getSelfName,
type NodeTransform,
type StructuralDirectiveTransform,
type DirectiveTransform,
} from './transform'
export {
generate,
- NewlineType,
type CodegenContext,
type CodegenResult,
type CodegenSourceMapGenerator,
type RawSourceMap,
- type BaseCodegenResult,
} from './codegen'
export {
ErrorCodes,
errorMessages,
createCompilerError,
- defaultOnError,
- defaultOnWarn,
type CoreCompilerError,
type CompilerError,
} from './errors'
transformExpression,
processExpression,
stringifyExpression,
- isLiteralWhitelisted,
} from './transforms/transformExpression'
export {
buildSlots,
checkCompatEnabled,
warnDeprecation,
CompilerDeprecationTypes,
- type CompilerCompatOptions,
} from './compat/compatConfig'
* @default mode === 'module'
*/
prefixIdentifiers?: boolean
- /**
- * A list of parser plugins to enable for `@babel/parser`, which is used to
- * parse expressions in bindings and interpolations.
- * https://babeljs.io/docs/en/next/babel-parser#plugins
- */
- expressionPlugins?: ParserPlugin[]
/**
* Control whether generate SSR-optimized render functions instead.
* The resulting function must be attached to the component via the
* @default false
*/
cacheHandlers?: boolean
+ /**
+ * A list of parser plugins to enable for `@babel/parser`, which is used to
+ * parse expressions in bindings and interpolations.
+ * https://babeljs.io/docs/en/next/babel-parser#plugins
+ */
+ expressionPlugins?: ParserPlugin[]
/**
* SFC scoped styles ID
*/
filters?: Set<string>
}
-export function getSelfName(filename: string): string | null {
- const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
- return nameMatch ? capitalize(camelize(nameMatch[1])) : null
-}
-
export function createTransformContext(
root: RootNode,
{
compatConfig,
}: TransformOptions,
): TransformContext {
+ const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
const context: TransformContext = {
// options
filename,
- selfName: getSelfName(filename),
+ selfName: nameMatch && capitalize(camelize(nameMatch[1])),
prefixIdentifiers,
hoistStatic,
hmr,
import { IS_REF, UNREF } from '../runtimeHelpers'
import { BindingTypes } from '../options'
-export const isLiteralWhitelisted: (key: string) => boolean =
- /*@__PURE__*/ makeMap('true,false,null,this')
+const isLiteralWhitelisted = /*@__PURE__*/ makeMap('true,false,null,this')
export const transformExpression: NodeTransform = (node, context) => {
if (node.type === NodeTypes.INTERPOLATION) {
export const isMemberExpressionNode: (
exp: ExpressionNode,
- context: Pick<TransformContext, 'expressionPlugins'>,
+ context: TransformContext,
) => boolean = __BROWSER__
? (NOOP as any)
: (exp, context) => {
export const isMemberExpression: (
exp: ExpressionNode,
- context: Pick<TransformContext, 'expressionPlugins'>,
+ context: TransformContext,
) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
const fnExpRE =
export const isFnExpressionNode: (
exp: ExpressionNode,
- context: Pick<TransformContext, 'expressionPlugins'>,
+ context: TransformContext,
) => boolean = __BROWSER__
? (NOOP as any)
: (exp, context) => {
export const isFnExpression: (
exp: ExpressionNode,
- context: Pick<TransformContext, 'expressionPlugins'>,
+ context: TransformContext,
) => boolean = __BROWSER__ ? isFnExpressionBrowser : isFnExpressionNode
export function advancePositionWithClone(
}
}
-/** find directive */
export function findDir(
node: ElementNode,
name: string | RegExp,
}
}
-export const DOMErrorMessages: Record<DOMErrorCodes, string> = {
+export const DOMErrorMessages: { [code: number]: string } = {
[DOMErrorCodes.X_V_HTML_NO_EXPRESSION]: `v-html is missing expression.`,
[DOMErrorCodes.X_V_HTML_WITH_CHILDREN]: `v-html will override element children.`,
[DOMErrorCodes.X_V_TEXT_NO_EXPRESSION]: `v-text is missing expression.`,
[DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`,
[DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN]: `<Transition> expects exactly one child element or component.`,
[DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG]: `Tags with side effect (<script> and <style>) are ignored in client component templates.`,
-
- // just to fulfill types
- [DOMErrorCodes.__EXTEND_POINT__]: ``,
}
DOMErrorCodes,
DOMErrorMessages,
} from './errors'
-export { resolveModifiers } from './transforms/vOn'
-export { isValidHTMLNesting } from './htmlNesting'
export * from '@vue/compiler-core'
isStaticExp,
} from '@vue/compiler-core'
import { V_ON_WITH_KEYS, V_ON_WITH_MODIFIERS } from '../runtimeHelpers'
-import { capitalize, isString, makeMap } from '@vue/shared'
+import { capitalize, makeMap } from '@vue/shared'
const isEventOptionModifier = /*@__PURE__*/ makeMap(`passive,once,capture`)
const isNonKeyModifier = /*@__PURE__*/ makeMap(
const maybeKeyModifier = /*@__PURE__*/ makeMap('left,right')
const isKeyboardEvent = /*@__PURE__*/ makeMap(`onkeyup,onkeydown,onkeypress`)
-export const resolveModifiers = (
- key: ExpressionNode | string,
+const resolveModifiers = (
+ key: ExpressionNode,
modifiers: SimpleExpressionNode[],
- context: TransformContext | null,
+ context: TransformContext,
loc: SourceLocation,
-): {
- keyModifiers: string[]
- nonKeyModifiers: string[]
- eventOptionModifiers: string[]
-} => {
+) => {
const keyModifiers = []
const nonKeyModifiers = []
const eventOptionModifiers = []
if (
__COMPAT__ &&
modifier === 'native' &&
- context &&
checkCompatEnabled(
CompilerDeprecationTypes.COMPILER_V_ON_NATIVE,
context,
// 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 (keyString) {
- if (isKeyboardEvent(keyString.toLowerCase())) {
+ if (isStaticExp(key)) {
+ if (
+ isKeyboardEvent((key as SimpleExpressionNode).content.toLowerCase())
+ ) {
keyModifiers.push(modifier)
} else {
nonKeyModifiers.push(modifier)
The API is intentionally low-level due to the various considerations when integrating Vue SFCs in a build system:
- Separate hot-module replacement (HMR) for script, template and styles
+
- template updates should not reset component state
- style updates should be performed without component re-render
exports[`sfc reactive props destructure > default values w/ type declaration & key is string 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
-import { toDisplayString as _toDisplayString } from "vue"
-
export default /*@__PURE__*/_defineComponent({
props: {
-return (_ctx: any,_cache: any) => {
- return _toDisplayString(__props.foo)
-}
+return () => {}
}
})"
"onUpdate:modelValue": (val: number) => void // double-quoted string containing symbols
}>()
</script>
- <template>{{ foo }}</template>
`)
expect(bindings).toStrictEqual({
__propsAliases: {
"foo:bar": { type: String, required: true, default: 'foo-bar' },
"onUpdate:modelValue": { type: Function, required: true }
},`)
- expect(content).toMatch(`__props.foo`)
assertCode(content)
})
})
})
- describe('vapor mode', () => {
- test('on empty script', () => {
- const { descriptor } = parse(`<script vapor></script>`)
- expect(descriptor.vapor).toBe(true)
- })
- test('on template', () => {
- const { descriptor } = parse(`<template vapor><div/></template>`)
- expect(descriptor.vapor).toBe(true)
- })
- })
-
describe('warnings', () => {
function assertWarning(errors: Error[], msg: string) {
expect(errors.some(e => e.message.match(msg))).toBe(true)
"@vue/compiler-core": "workspace:*",
"@vue/compiler-dom": "workspace:*",
"@vue/compiler-ssr": "workspace:*",
- "@vue/compiler-vapor": "workspace:*",
"@vue/shared": "workspace:*",
"estree-walker": "catalog:",
"magic-string": "catalog:",
BindingTypes,
UNREF,
isFunctionType,
- isStaticNode,
unwrapTSNode,
walkIdentifiers,
} from '@vue/compiler-dom'
Declaration,
ExportSpecifier,
Identifier,
- LVal,
Node,
ObjectPattern,
Statement,
* Transform Vue SFCs into custom elements.
*/
customElement?: boolean | ((filename: string) => boolean)
- /**
- * Force to use of Vapor mode.
- */
- vapor?: boolean
}
export interface ImportBinding {
const scopeId = options.id ? options.id.replace(/^data-v-/, '') : ''
const scriptLang = script && script.lang
const scriptSetupLang = scriptSetup && scriptSetup.lang
- const vapor = sfc.vapor || options.vapor
- const ssr = options.templateOptions?.ssr
if (!scriptSetup) {
if (!script) {
}
// defineProps
- const isDefineProps = processDefineProps(ctx, init, decl.id as LVal)
+ const isDefineProps = processDefineProps(ctx, init, decl.id)
if (ctx.propsDestructureRestId) {
setupBindings[ctx.propsDestructureRestId] =
BindingTypes.SETUP_REACTIVE_CONST
// defineEmits
const isDefineEmits =
- !isDefineProps && processDefineEmits(ctx, init, decl.id as LVal)
+ !isDefineProps && processDefineEmits(ctx, init, decl.id)
!isDefineEmits &&
- (processDefineSlots(ctx, init, decl.id as LVal) ||
- processDefineModel(ctx, init, decl.id as LVal))
+ (processDefineSlots(ctx, init, decl.id) ||
+ processDefineModel(ctx, init, decl.id))
if (
isDefineProps &&
if (
sfc.cssVars.length &&
// no need to do this when targeting SSR
- !ssr
+ !options.templateOptions?.ssr
) {
ctx.helperImports.add(CSS_VARS_HELPER)
ctx.helperImports.add('unref')
} else {
// inline mode
if (sfc.template && !sfc.template.src) {
- if (ssr) {
+ if (options.templateOptions && options.templateOptions.ssr) {
hasInlinedSsrRenderFn = true
}
// inline render function mode - we are going to compile the template and
// inline it right here
- const { code, preamble, tips, errors, helpers, map } = compileTemplate({
+ const { code, ast, preamble, tips, errors, map } = compileTemplate({
filename,
ast: sfc.template.ast,
source: sfc.template.content,
scoped: sfc.styles.some(s => s.scoped),
isProd: options.isProd,
ssrCssVars: sfc.cssVars,
- vapor,
compilerOptions: {
...(options.templateOptions &&
options.templateOptions.compilerOptions),
// avoid duplicated unref import
// as this may get injected by the render function preamble OR the
// css vars codegen
- if (helpers && helpers.has(UNREF)) {
+ if (ast && ast.helpers.has(UNREF)) {
ctx.helperImports.delete('unref')
}
returned = code
`\n}\n\n`,
)
} else {
- ctx.s.appendRight(
- endOffset,
- // vapor mode generates its own return when inlined
- `\n${vapor && !ssr ? `` : `return `}${returned}\n}\n\n`,
- )
+ ctx.s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
}
// 10. finalize default export
ctx.s.prependLeft(
startOffset,
`\n${genDefaultAs} /*@__PURE__*/${ctx.helper(
- vapor && !ssr ? `defineVaporComponent` : `defineComponent`,
+ `defineComponent`,
)}({${def}${runtimeOptions}\n ${
hasAwait ? `async ` : ``
}setup(${args}) {\n${exposeCall}`,
)
ctx.s.appendRight(endOffset, `})`)
} else {
- // in TS, defineVaporComponent adds the option already
- if (vapor) {
- runtimeOptions += `\n __vapor: true,`
- }
if (defaultExport || definedOptions) {
// without TS, can't rely on rest spread, so we use Object.assign
// export default Object.assign(__default__, { ... })
}
}
+function isStaticNode(node: Node): boolean {
+ node = unwrapTSNode(node)
+
+ switch (node.type) {
+ case 'UnaryExpression': // void 0, !true
+ return isStaticNode(node.argument)
+
+ case 'LogicalExpression': // 1 > 2
+ case 'BinaryExpression': // 1 + 2
+ return isStaticNode(node.left) && isStaticNode(node.right)
+
+ case 'ConditionalExpression': {
+ // 1 ? 2 : 3
+ return (
+ isStaticNode(node.test) &&
+ isStaticNode(node.consequent) &&
+ isStaticNode(node.alternate)
+ )
+ }
+
+ case 'SequenceExpression': // (1, 2)
+ case 'TemplateLiteral': // `foo${1}`
+ return node.expressions.every(expr => isStaticNode(expr))
+
+ case 'ParenthesizedExpression': // (1)
+ return isStaticNode(node.expression)
+
+ case 'StringLiteral':
+ case 'NumericLiteral':
+ case 'BooleanLiteral':
+ case 'NullLiteral':
+ case 'BigIntLiteral':
+ return true
+ }
+ return false
+}
+
export function mergeSourceMaps(
scriptMap: RawSourceMap,
templateMap: RawSourceMap,
import {
- type BaseCodegenResult,
+ type CodegenResult,
type CompilerError,
type CompilerOptions,
type ElementNode,
} from './template/transformSrcset'
import { generateCodeFrame, isObject } from '@vue/shared'
import * as CompilerDOM from '@vue/compiler-dom'
-import * as CompilerVapor from '@vue/compiler-vapor'
import * as CompilerSSR from '@vue/compiler-ssr'
import consolidate from '@vue/consolidate'
import { warnOnce } from './warn'
import { genCssVarsFromList } from './style/cssVars'
export interface TemplateCompiler {
- compile(
- source: string | RootNode,
- options: CompilerOptions,
- ): BaseCodegenResult
+ compile(source: string | RootNode, options: CompilerOptions): CodegenResult
parse(template: string, options: ParserOptions): RootNode
}
export interface SFCTemplateCompileResults {
code: string
- ast?: unknown
+ ast?: RootNode
preamble?: string
source: string
tips: string[]
errors: (string | CompilerError)[]
map?: RawSourceMap
- helpers?: Set<string | symbol>
}
export interface SFCTemplateCompileOptions {
scoped?: boolean
slotted?: boolean
isProd?: boolean
- vapor?: boolean
ssr?: boolean
ssrCssVars?: string[]
inMap?: RawSourceMap
source,
ast: inAST,
ssr = false,
- vapor = false,
ssrCssVars,
isProd = false,
compiler,
const shortId = id.replace(/^data-v-/, '')
const longId = `data-v-${shortId}`
- const defaultCompiler = ssr
- ? (CompilerSSR as TemplateCompiler)
- : vapor
- ? (CompilerVapor as TemplateCompiler)
- : CompilerDOM
+ const defaultCompiler = ssr ? (CompilerSSR as TemplateCompiler) : CompilerDOM
compiler = compiler || defaultCompiler
if (compiler !== defaultCompiler) {
inAST = createRoot(template.children, inAST.source)
}
- let { code, ast, preamble, map, helpers } = compiler.compile(
- inAST || source,
- {
- mode: 'module',
- prefixIdentifiers: true,
- hoistStatic: true,
- cacheHandlers: true,
- ssrCssVars:
- ssr && ssrCssVars && ssrCssVars.length
- ? genCssVarsFromList(ssrCssVars, shortId, isProd, true)
- : '',
- scopeId: scoped ? longId : undefined,
- slotted,
- sourceMap: true,
- ...compilerOptions,
- hmr: !isProd,
- nodeTransforms: nodeTransforms.concat(
- compilerOptions.nodeTransforms || [],
- ),
- filename,
- onError: e => errors.push(e),
- onWarn: w => warnings.push(w),
- },
- )
+ let { code, ast, preamble, map } = compiler.compile(inAST || source, {
+ mode: 'module',
+ prefixIdentifiers: true,
+ hoistStatic: true,
+ cacheHandlers: true,
+ ssrCssVars:
+ ssr && ssrCssVars && ssrCssVars.length
+ ? genCssVarsFromList(ssrCssVars, shortId, isProd, true)
+ : '',
+ scopeId: scoped ? longId : undefined,
+ slotted,
+ sourceMap: true,
+ ...compilerOptions,
+ hmr: !isProd,
+ nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
+ filename,
+ onError: e => errors.push(e),
+ onWarn: w => warnings.push(w),
+ })
// inMap should be the map produced by ./parse.ts which is a simple line-only
// mapping. If it is present, we need to adjust the final map and errors to
return msg
})
- return {
- code,
- ast,
- preamble,
- source,
- errors,
- tips,
- map,
- helpers,
- }
+ return { code, ast, preamble, source, errors, tips, map }
}
function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap {
*/
slotted: boolean
- vapor: boolean
-
/**
* compare with an existing descriptor to determine whether HMR should perform
* a reload vs. re-render.
customBlocks: [],
cssVars: [],
slotted: false,
- vapor: false,
shouldForceReload: prevImports => hmrShouldReload(prevImports, descriptor),
}
ignoreEmpty &&
node.tag !== 'template' &&
isEmpty(node) &&
- !hasAttr(node, 'src')
+ !hasSrc(node)
) {
- descriptor.vapor ||= hasAttr(node, 'vapor')
return
}
switch (node.tag) {
source,
false,
) as SFCTemplateBlock)
- descriptor.vapor ||= !!templateBlock.attrs.vapor
if (!templateBlock.attrs.src) {
templateBlock.ast = createRoot(node.children, source)
break
case 'script':
const scriptBlock = createBlock(node, source, pad) as SFCScriptBlock
- descriptor.vapor ||= !!scriptBlock.attrs.vapor
- const isSetup = !!(scriptBlock.attrs.setup || scriptBlock.attrs.vapor)
+ const isSetup = !!scriptBlock.attrs.setup
if (isSetup && !descriptor.scriptSetup) {
descriptor.scriptSetup = scriptBlock
break
}
}
-function hasAttr(node: ElementNode, name: string) {
- return node.props.some(p => p.type === NodeTypes.ATTRIBUTE && p.name === name)
+function hasSrc(node: ElementNode) {
+ return node.props.some(p => {
+ if (p.type !== NodeTypes.ATTRIBUTE) {
+ return false
+ }
+ return p.name === 'src'
+ })
}
/**
)
}
ctx.propsTypeDecl = node.typeParameters.params[0]
- // register bindings
- const { props } = resolveTypeElements(ctx, ctx.propsTypeDecl)
- if (props) {
- for (const key in props) {
- if (!(key in ctx.bindingMetadata)) {
- ctx.bindingMetadata[key] = BindingTypes.PROPS
- }
- }
- }
}
// handle props destructure
for (const prop of props) {
propStrings.push(genRuntimePropFromType(ctx, prop, hasStaticDefaults))
+ // register bindings
+ if ('bindingMetadata' in ctx && !(prop.key in ctx.bindingMetadata)) {
+ ctx.bindingMetadata[prop.key] = BindingTypes.PROPS
+ }
}
let propsDecls = `{
+++ /dev/null
-The MIT License (MIT)
-
-Copyright (c) 2018-present, Yuxi (Evan) You
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-# @vue/compiler-vapor
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compile > bindings 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- const x0 = _child(n0)
- _renderEffect(() => _setText(x0, "count is " + _toDisplayString(_ctx.count) + "."))
- return n0
-}"
-`;
-
-exports[`compile > custom directive > basic 1`] = `
-"import { resolveDirective as _resolveDirective, withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _directive_test = _resolveDirective("test")
- const _directive_hello = _resolveDirective("hello")
- const n0 = t0()
- _withVaporDirectives(n0, [[_directive_test], [_directive_hello, void 0, void 0, { world: true }]])
- return n0
-}"
-`;
-
-exports[`compile > custom directive > component 1`] = `
-"import { resolveComponent as _resolveComponent, resolveDirective as _resolveDirective, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, withVaporDirectives as _withVaporDirectives, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const _component_Bar = _resolveComponent("Bar")
- const _component_Comp = _resolveComponent("Comp")
- const _directive_hello = _resolveDirective("hello")
- const _directive_test = _resolveDirective("test")
- const n4 = _createComponentWithFallback(_component_Comp, null, {
- "default": () => {
- const n0 = _createIf(() => (true), () => {
- const n3 = t0()
- _setInsertionState(n3)
- const n2 = _createComponentWithFallback(_component_Bar)
- _withVaporDirectives(n2, [[_directive_hello, void 0, void 0, { world: true }]])
- return n3
- })
- return n0
- }
- }, true)
- _withVaporDirectives(n4, [[_directive_test]])
- return n4
-}"
-`;
-
-exports[`compile > directives > custom directive > basic 1`] = `
-"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _withVaporDirectives(n0, [[_ctx.vExample]])
- return n0
-}"
-`;
-
-exports[`compile > directives > custom directive > binding value 1`] = `
-"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg]])
- return n0
-}"
-`;
-
-exports[`compile > directives > custom directive > dynamic parameters 1`] = `
-"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, _ctx.foo]])
- return n0
-}"
-`;
-
-exports[`compile > directives > custom directive > modifiers 1`] = `
-"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, void 0, { bar: true }]])
- return n0
-}"
-`;
-
-exports[`compile > directives > custom directive > modifiers w/o binding 1`] = `
-"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _withVaporDirectives(n0, [[_ctx.vExample, void 0, void 0, { "foo-bar": true }]])
- return n0
-}"
-`;
-
-exports[`compile > directives > custom directive > static parameters 1`] = `
-"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo"]])
- return n0
-}"
-`;
-
-exports[`compile > directives > custom directive > static parameters and modifiers 1`] = `
-"import { withVaporDirectives as _withVaporDirectives, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _withVaporDirectives(n0, [[_ctx.vExample, () => _ctx.msg, "foo", { bar: true }]])
- return n0
-}"
-`;
-
-exports[`compile > directives > v-cloak > basic 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<div>test</div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- return n0
-}"
-`;
-
-exports[`compile > directives > v-pre > basic 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- return n0
-}"
-`;
-
-exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
-"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
-const t1 = _template("<div> </div>")
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = t0()
- const n3 = t1()
- const n2 = _child(n3)
- _setInsertionState(n3, 0)
- const n1 = _createComponentWithFallback(_component_Comp)
- _renderEffect(() => {
- _setProp(n3, "id", _ctx.foo)
- _setText(n2, _toDisplayString(_ctx.bar))
- })
- return [n0, n3]
-}"
-`;
-
-exports[`compile > dynamic root 1`] = `
-"import { toDisplayString as _toDisplayString, setText as _setText, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const n0 = t0()
- _setText(n0, _toDisplayString(1) + _toDisplayString(2))
- return n0
-}"
-`;
-
-exports[`compile > dynamic root nodes and interpolation 1`] = `
-"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<button> </button>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- const x0 = _child(n0)
- n0.$evtclick = e => _ctx.handleClick(e)
- _renderEffect(() => {
- const _count = _ctx.count
- _setProp(n0, "id", _count)
- _setText(x0, _toDisplayString(_count) + "foo" + _toDisplayString(_count) + "foo" + _toDisplayString(_count))
- })
- return n0
-}"
-`;
-
-exports[`compile > execution order > basic 1`] = `
-"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- const x0 = _child(n0)
- _renderEffect(() => {
- _setProp(n0, "id", _ctx.foo)
- _setText(x0, _toDisplayString(_ctx.bar))
- })
- return n0
-}"
-`;
-
-exports[`compile > execution order > with v-once 1`] = `
-"import { child as _child, next as _next, nthChild as _nthChild, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div><span> </span> <br> </div>", true)
-
-export function render(_ctx) {
- const n3 = t0()
- const n0 = _child(n3)
- const n1 = _next(n0)
- const n2 = _nthChild(n3, 3)
- const x0 = _child(n0)
- _setText(x0, _toDisplayString(_ctx.foo))
- _renderEffect(() => {
- _setText(n1, " " + _toDisplayString(_ctx.bar))
- _setText(n2, " " + _toDisplayString(_ctx.baz))
- })
- return n3
-}"
-`;
-
-exports[`compile > expression parsing > interpolation 1`] = `
-"
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(a + b.value)))
- return n0
-"
-`;
-
-exports[`compile > expression parsing > v-bind 1`] = `
-"
- const n0 = t0()
- _renderEffect(() => {
- const _key = key.value
- _setDynamicProps(n0, [{ [_key+1]: _unref(foo)[_key+1]() }], true)
- })
- return n0
-"
-`;
-
-exports[`compile > fragment 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<p></p>")
-const t1 = _template("<span></span>")
-const t2 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t1()
- const n2 = t2()
- return [n0, n1, n2]
-}"
-`;
-
-exports[`compile > setInsertionState > next, child and nthChild should be above the setInsertionState 1`] = `
-"import { resolveComponent as _resolveComponent, child as _child, next as _next, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, nthChild as _nthChild, createIf as _createIf, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<div><div></div><!><div></div><!><div><button></button></div></div>", true)
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n6 = t1()
- const n5 = _next(_child(n6))
- const n7 = _nthChild(n6, 3)
- const p0 = _next(n7)
- const n4 = _child(p0)
- _setInsertionState(n6, n5)
- const n0 = _createComponentWithFallback(_component_Comp)
- _setInsertionState(n6, n7)
- const n1 = _createIf(() => (true), () => {
- const n3 = t0()
- return n3
- })
- _renderEffect(() => _setProp(n4, "disabled", _ctx.foo))
- return n6
-}"
-`;
-
-exports[`compile > static + dynamic root 1`] = `
-"import { toDisplayString as _toDisplayString, setText as _setText, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const n0 = t0()
- _setText(n0, _toDisplayString(1) + _toDisplayString(2) + "3" + _toDisplayString(4) + _toDisplayString(5) + "6" + _toDisplayString(7) + _toDisplayString(8) + "9" + 'A' + 'B')
- return n0
-}"
-`;
-
-exports[`compile > static template 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<div><p>hello</p><input><span></span></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- return n0
-}"
-`;
+++ /dev/null
-/**
- * @vitest-environment jsdom
- */
-
-const parser: DOMParser = new DOMParser()
-
-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')
-})
+++ /dev/null
-import { BindingTypes, type RootNode } from '@vue/compiler-dom'
-import { type CompilerOptions, compile as _compile } from '../src'
-
-// TODO This is a temporary test case for initial implementation.
-// Remove it once we have more comprehensive tests.
-// DO NOT ADD MORE TESTS HERE.
-
-function compile(template: string | RootNode, options: CompilerOptions = {}) {
- let { code } = _compile(template, {
- ...options,
- mode: 'module',
- prefixIdentifiers: true,
- })
- return code
-}
-
-describe('compile', () => {
- test('static template', () => {
- const code = compile(
- `<div>
- <p>hello</p>
- <input />
- <span />
- </div>`,
- )
- expect(code).matchSnapshot()
- })
-
- test('dynamic root', () => {
- const code = compile(`{{ 1 }}{{ 2 }}`)
- expect(code).matchSnapshot()
- })
-
- test('dynamic root nodes and interpolation', () => {
- const code = compile(
- `<button @click="handleClick" :id="count">{{count}}foo{{count}}foo{{count}} </button>`,
- )
- expect(code).matchSnapshot()
- })
-
- test('static + dynamic root', () => {
- const code = compile(
- `{{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}`,
- )
- expect(code).matchSnapshot()
- })
-
- test('fragment', () => {
- const code = compile(`<p/><span/><div/>`)
- expect(code).matchSnapshot()
- })
-
- test('bindings', () => {
- const code = compile(`<div>count is {{ count }}.</div>`, {
- bindingMetadata: {
- count: BindingTypes.SETUP_REF,
- },
- })
- expect(code).matchSnapshot()
- })
-
- describe('directives', () => {
- describe('v-pre', () => {
- test('basic', () => {
- const code = compile(`<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n`, {
- bindingMetadata: {
- foo: BindingTypes.SETUP_REF,
- bar: BindingTypes.SETUP_REF,
- },
- })
-
- expect(code).toMatchSnapshot()
- expect(code).contains(
- JSON.stringify('<div :id="foo"><Comp></Comp>{{ bar }}</div>'),
- )
- expect(code).not.contains('effect')
- })
-
- test('should not affect siblings after it', () => {
- const code = compile(
- `<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n` +
- `<div :id="foo"><Comp/>{{ bar }}</div>`,
- {
- bindingMetadata: {
- foo: BindingTypes.SETUP_REF,
- bar: BindingTypes.SETUP_REF,
- },
- },
- )
-
- expect(code).toMatchSnapshot()
- // Waiting for TODO, There should be more here.
- })
- })
-
- describe('v-cloak', () => {
- test('basic', () => {
- const code = compile(`<div v-cloak>test</div>`)
- expect(code).toMatchSnapshot()
- expect(code).not.contains('v-cloak')
- })
- })
-
- describe('custom directive', () => {
- test('basic', () => {
- const code = compile(`<div v-example></div>`, {
- bindingMetadata: {
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('binding value', () => {
- const code = compile(`<div v-example="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('static parameters', () => {
- const code = compile(`<div v-example:foo="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('modifiers', () => {
- const code = compile(`<div v-example.bar="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('modifiers w/o binding', () => {
- const code = compile(`<div v-example.foo-bar></div>`, {
- bindingMetadata: {
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('static parameters and modifiers', () => {
- const code = compile(`<div v-example:foo.bar="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('dynamic parameters', () => {
- const code = compile(`<div v-example:[foo]="msg"></div>`, {
- bindingMetadata: {
- foo: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
- })
- })
-
- describe('expression parsing', () => {
- test('interpolation', () => {
- const code = compile(`{{ a + b }}`, {
- inline: true,
- bindingMetadata: {
- b: BindingTypes.SETUP_REF,
- },
- })
- expect(code).matchSnapshot()
- expect(code).contains('a + b.value')
- })
-
- test('v-bind', () => {
- const code = compile(`<div :[key+1]="foo[key+1]()" />`, {
- inline: true,
- bindingMetadata: {
- key: BindingTypes.SETUP_REF,
- foo: BindingTypes.SETUP_MAYBE_REF,
- },
- })
- expect(code).matchSnapshot()
- expect(code).contains('const _key = key.value')
- expect(code).contains('_key+1')
- expect(code).contains(
- '_setDynamicProps(n0, [{ [_key+1]: _unref(foo)[_key+1]() }], true)',
- )
- })
-
- // TODO: add more test for expression parsing (v-on, v-slot, v-for)
- })
-
- describe('custom directive', () => {
- test('basic', () => {
- const code = compile(`<div v-test v-hello.world />`)
- expect(code).matchSnapshot()
- })
-
- test('component', () => {
- const code = compile(`
- <Comp v-test>
- <div v-if="true">
- <Bar v-hello.world />
- </div>
- </Comp>
- `)
- expect(code).matchSnapshot()
- })
- })
-
- describe('setInsertionState', () => {
- test('next, child and nthChild should be above the setInsertionState', () => {
- const code = compile(`
- <div>
- <div />
- <Comp />
- <div />
- <div v-if="true" />
- <div>
- <button :disabled="foo" />
- </div>
- </div>
- `)
- expect(code).toMatchSnapshot()
- })
- })
-
- describe('execution order', () => {
- test('basic', () => {
- const code = compile(`<div :id="foo">{{ bar }}</div>`)
- expect(code).matchSnapshot()
- expect(code).contains(
- `_setProp(n0, "id", _ctx.foo)
- _setText(x0, _toDisplayString(_ctx.bar))`,
- )
- })
- test('with v-once', () => {
- const code = compile(
- `<div>
- <span v-once>{{ foo }}</span>
- {{ bar }}<br>
- {{ baz }}
- </div>`,
- )
- expect(code).matchSnapshot()
- expect(code).contains(
- `_setText(n1, " " + _toDisplayString(_ctx.bar))
- _setText(n2, " " + _toDisplayString(_ctx.baz))`,
- )
- })
- })
-})
+++ /dev/null
-// import { compile } from '../src/compile'
-
-describe.todo('scopeId compiler support', () => {})
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: expression > basic 1`] = `
-"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(_ctx.a)))
- return n0
-}"
-`;
-
-exports[`compiler: expression > props 1`] = `
-"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString($props.foo)))
- return n0
-}"
-`;
-
-exports[`compiler: expression > props aliased 1`] = `
-"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString($props['bar'])))
- return n0
-}"
-`;
-
-exports[`compiler: expression > update expression 1`] = `
-"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n1 = t0()
- const n0 = _child(n1)
- const x1 = _child(n1)
- _renderEffect(() => {
- const _String = String
- const _foo = _ctx.foo
- _setProp(n1, "id", _String(_foo.id++))
- _setProp(n1, "foo", _foo)
- _setProp(n1, "bar", _ctx.bar++)
- _setText(n0, _toDisplayString(_String(_foo.id++)) + " " + _toDisplayString(_foo) + " " + _toDisplayString(_ctx.bar))
- _setText(x1, _toDisplayString(_String(_foo.id++)) + " " + _toDisplayString(_foo) + " " + _toDisplayString(_ctx.bar))
- })
- return n1
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: children transform > anchor insertion in middle 1`] = `
-"import { child as _child, next as _next, setInsertionState as _setInsertionState, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<div><div></div><!><div></div></div>", true)
-
-export function render(_ctx) {
- const n4 = t1()
- const n3 = _next(_child(n4))
- _setInsertionState(n4, n3)
- const n0 = _createIf(() => (1), () => {
- const n2 = t0()
- return n2
- }, null, true)
- return n4
-}"
-`;
-
-exports[`compiler: children transform > children & sibling references 1`] = `
-"import { child as _child, next as _next, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div><p> </p> <p> </p></div>", true)
-
-export function render(_ctx) {
- const n3 = t0()
- const n0 = _child(n3)
- const n1 = _next(n0)
- const n2 = _next(n1)
- const x0 = _child(n0)
- const x2 = _child(n2)
- _renderEffect(() => {
- _setText(x0, _toDisplayString(_ctx.first))
- _setText(n1, " " + _toDisplayString(_ctx.second) + " " + _toDisplayString(_ctx.third) + " ")
- _setText(x2, _toDisplayString(_ctx.forth))
- })
- return n3
-}"
-`;
-
-exports[`compiler: children transform > efficient find 1`] = `
-"import { child as _child, nthChild as _nthChild, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div><div>x</div><div>x</div><div> </div></div>", true)
-
-export function render(_ctx) {
- const n1 = t0()
- const n0 = _nthChild(n1, 2)
- const x0 = _child(n0)
- _renderEffect(() => _setText(x0, _toDisplayString(_ctx.msg)))
- return n1
-}"
-`;
-
-exports[`compiler: children transform > efficient traversal 1`] = `
-"import { child as _child, next as _next, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div><div>x</div><div><span> </span></div><div><span> </span></div><div><span> </span></div></div>", true)
-
-export function render(_ctx) {
- const n3 = t0()
- const p0 = _next(_child(n3))
- const p1 = _next(p0)
- const p2 = _next(p1)
- const n0 = _child(p0)
- const n1 = _child(p1)
- const n2 = _child(p2)
- const x0 = _child(n0)
- const x1 = _child(n1)
- const x2 = _child(n2)
- _renderEffect(() => {
- const _msg = _ctx.msg
- _setText(x0, _toDisplayString(_msg))
- _setText(x1, _toDisplayString(_msg))
- _setText(x2, _toDisplayString(_msg))
- })
- return n3
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: element transform > component > cache v-on expression with unique handler name 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const _component_Bar = _resolveComponent("Bar")
- const _on_bar = $event => (_ctx.handleBar($event))
- const n0 = _createComponentWithFallback(_component_Foo, { onBar: () => _on_bar })
- const _on_bar1 = () => _ctx.handler
- const n1 = _createComponentWithFallback(_component_Bar, { onBar: () => _on_bar1 })
- return [n0, n1]
-}"
-`;
-
-exports[`compiler: element transform > component > do not resolve component from non-script-setup bindings 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const _component_Example = _resolveComponent("Example")
- const n0 = _createComponentWithFallback(_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';
-const t0 = _template("123")
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = _createComponent(_ctx.Comp)
- const n1 = t0()
- return [n0, n1]
-}"
-`;
-
-exports[`compiler: element transform > component > generate single root component 1`] = `
-"import { createComponent as _createComponent } from 'vue';
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = _createComponent(_ctx.Comp, null, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > import + resolve component 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_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';
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = _createComponent(_ctx.Example, null, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > resolve implicitly self-referencing component 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Example__self = _resolveComponent("Example", true)
- const n0 = _createComponentWithFallback(_component_Example__self, 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';
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- 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';
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = _createComponent(_ctx.Foo.Example, null, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > static props 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_component_Foo, {
- id: () => ("foo"),
- class: () => ("bar")
- }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > v-bind="obj" 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_component_Foo, { $: [
- () => (_ctx.obj)
- ] }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > v-bind="obj" after static prop 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_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, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_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, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_component_Foo, {
- id: () => ("foo"),
- $: [
- () => (_ctx.obj),
- { class: () => ("bar") }
- ]
- }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > v-for on component should not mark as single root 1`] = `
-"import { createComponent as _createComponent, createFor as _createFor } from 'vue';
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = _createFor(() => (_ctx.items), (_for_item0) => {
- const n2 = _createComponent(_ctx.Comp)
- return n2
- }, (item) => (item), 2)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > v-on expression is a function call 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const _on_bar = $event => (_ctx.handleBar($event))
- const n0 = _createComponentWithFallback(_component_Foo, { onBar: () => _on_bar }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > v-on expression is inline statement 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const _on_bar = () => _ctx.handler
- const n0 = _createComponentWithFallback(_component_Foo, { onBar: () => _on_bar }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component > v-on="obj" 1`] = `
-"import { resolveComponent as _resolveComponent, toHandlers as _toHandlers, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_component_Foo, { $: [
- () => (_toHandlers(_ctx.obj))
- ] }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component dynamic event with once modifier 1`] = `
-"import { resolveComponent as _resolveComponent, toHandlerKey as _toHandlerKey, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_component_Foo, { $: [
- () => ({ [_toHandlerKey(_ctx.foo) + "Once"]: () => _ctx.bar })
- ] }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component event with once modifier 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_component_Foo, { onFooOnce: () => _ctx.bar }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > component with dynamic event arguments 1`] = `
-"import { resolveComponent as _resolveComponent, toHandlerKey as _toHandlerKey, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_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, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponentWithFallback(_component_Foo, { $: [
- () => ({ [_ctx.foo-_ctx.bar]: _ctx.bar }),
- () => ({ [_ctx.baz]: _ctx.qux })
- ] }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > dynamic component > capitalized version w/ static binding 1`] = `
-"import { resolveDynamicComponent as _resolveDynamicComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createComponentWithFallback(_resolveDynamicComponent("foo"), null, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > dynamic component > dynamic binding 1`] = `
-"import { createDynamicComponent as _createDynamicComponent } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createDynamicComponent(() => (_ctx.foo), null, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > dynamic component > dynamic binding shorthand 1`] = `
-"import { createDynamicComponent as _createDynamicComponent } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createDynamicComponent(() => (_ctx.is), null, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > dynamic component > normal component with is prop 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_custom_input = _resolveComponent("custom-input")
- const n0 = _createComponentWithFallback(_component_custom_input, { is: () => ("foo") }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: element transform > dynamic component > static binding 1`] = `
-"import { resolveDynamicComponent as _resolveDynamicComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createComponentWithFallback(_resolveDynamicComponent("foo"), null, 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';
-const t0 = _template("<div>123</div>")
-const t1 = _template("<p></p>")
-const t2 = _template("<form></form>")
-
-export function render(_ctx) {
- const n1 = t1()
- const n3 = t2()
- const n0 = t0()
- 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';
-const t0 = _template("<div id=\\"foo\\"><span></span></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- return n0
-}"
-`;
-
-exports[`compiler: element transform > props merging: class 1`] = `
-"import { setClass as _setClass, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-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 { withKeys as _withKeys, delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- _delegate(n0, "click", _withKeys(e => _ctx.a(e), ["foo"]))
- _delegate(n0, "click", _withKeys(e => _ctx.b(e), ["bar"]))
- return n0
-}"
-`;
-
-exports[`compiler: element transform > props merging: style 1`] = `
-"import { setStyle as _setStyle, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _setStyle(n0, ["color: green", { color: 'red' }])
- return n0
-}"
-`;
-
-exports[`compiler: element transform > static props 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<div id=\\"foo\\" class=\\"bar\\"></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- return n0
-}"
-`;
-
-exports[`compiler: element transform > v-bind="obj" 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, [_ctx.obj], true))
- return n0
-}"
-`;
-
-exports[`compiler: element transform > v-bind="obj" after static prop 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, [{ id: "foo" }, _ctx.obj], true))
- return n0
-}"
-`;
-
-exports[`compiler: element transform > v-bind="obj" before static prop 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, [_ctx.obj, { id: "foo" }], true))
- return n0
-}"
-`;
-
-exports[`compiler: element transform > v-bind="obj" between static props 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, [{ id: "foo" }, _ctx.obj, { class: "bar" }], true))
- return n0
-}"
-`;
-
-exports[`compiler: element transform > v-on="obj" 1`] = `
-"import { setDynamicEvents as _setDynamicEvents, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicEvents(n0, _ctx.obj))
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: template ref transform > dynamic ref 1`] = `
-"import { renderEffect as _renderEffect, setRef as _setRef, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- let r0
- _renderEffect(() => r0 = _setRef(n0, _ctx.foo, r0))
- return n0
-}"
-`
-
-exports[`compiler: template ref transform > ref + v-for 1`] = `
-"import { setRef as _setRef, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = _createFor(() => ([1,2,3]), (_block) => {
- const n2 = t0()
- _setRef(n2, "foo", void 0, true)
- return [n2, () => {}]
- })
- return n0
-}"
-`
-
-exports[`compiler: template ref transform > ref + v-if 1`] = `
-"import { setRef as _setRef, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = _createIf(() => (true), () => {
- const n2 = t0()
- _setRef(n2, "foo")
- return n2
- })
- return n0
-}"
-`
-
-exports[`compiler: template ref transform > static ref 1`] = `
-"import { setRef as _setRef, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- _setRef(n0, "foo")
- return n0
-}"
-`
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: transform <slot> outlets > default slot outlet 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot("default", null)
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > default slot outlet with fallback 1`] = `
-"import { createSlot as _createSlot, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createSlot("default", null, () => {
- const n2 = t0()
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > default slot outlet with props & fallback 1`] = `
-"import { createSlot as _createSlot, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createSlot("default", { foo: () => (_ctx.bar) }, () => {
- const n2 = t0()
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > default slot outlet with props 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot("default", {
- foo: () => ("bar"),
- baz: () => (_ctx.qux),
- fooBar: () => (_ctx.foo-_ctx.bar)
- })
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > dynamically named slot outlet 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot(() => (_ctx.foo + _ctx.bar), null)
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > dynamically named slot outlet with v-bind shorthand 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot(() => (_ctx.name), null)
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > error on unexpected custom directive on <slot> 1`] = `
-"import { resolveDirective as _resolveDirective, createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const _directive_foo = _resolveDirective("foo")
- const n0 = _createSlot("default", null)
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > error on unexpected custom directive with v-show on <slot> 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot("default", null)
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > named slot outlet with fallback 1`] = `
-"import { createSlot as _createSlot, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createSlot("foo", null, () => {
- const n2 = t0()
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > named slot outlet with props & fallback 1`] = `
-"import { createSlot as _createSlot, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createSlot("foo", { foo: () => (_ctx.bar) }, () => {
- const n2 = t0()
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > statically named slot outlet 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot("foo", null)
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > statically named slot outlet with props 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot("foo", {
- foo: () => ("bar"),
- baz: () => (_ctx.qux)
- })
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > statically named slot outlet with v-bind="obj" 1`] = `
-"import { createSlot as _createSlot } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot("foo", {
- foo: () => ("bar"),
- $: [
- () => (_ctx.obj),
- { baz: () => (_ctx.qux) }
- ]
- })
- return n0
-}"
-`;
-
-exports[`compiler: transform <slot> outlets > statically named slot outlet with v-on 1`] = `
-"import { createSlot as _createSlot, toHandlers as _toHandlers } from 'vue';
-
-export function render(_ctx) {
- const n0 = _createSlot("default", {
- onClick: () => _ctx.foo,
- $: [
- () => (_toHandlers(_ctx.bar)),
- { baz: () => (_ctx.qux) }
- ]
- })
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: template ref transform > dynamic ref 1`] = `
-"import { createTemplateRefSetter as _createTemplateRefSetter, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _setTemplateRef = _createTemplateRefSetter()
- const n0 = t0()
- let r0
- _renderEffect(() => r0 = _setTemplateRef(n0, _ctx.foo, r0))
- return n0
-}"
-`;
-
-exports[`compiler: template ref transform > function ref 1`] = `
-"import { createTemplateRefSetter as _createTemplateRefSetter, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _setTemplateRef = _createTemplateRefSetter()
- const n0 = t0()
- let r0
- _renderEffect(() => {
- const _foo = _ctx.foo
- r0 = _setTemplateRef(n0, bar => {
- _foo.value = bar
- ;({ baz: _ctx.baz } = bar)
- console.log(_foo.value, _ctx.baz)
- }, r0)
- })
- return n0
-}"
-`;
-
-exports[`compiler: template ref transform > ref + v-for 1`] = `
-"import { createTemplateRefSetter as _createTemplateRefSetter, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _setTemplateRef = _createTemplateRefSetter()
- const n0 = _createFor(() => ([1,2,3]), (_for_item0) => {
- const n2 = t0()
- _setTemplateRef(n2, "foo", void 0, true)
- return n2
- }, null, 4)
- return n0
-}"
-`;
-
-exports[`compiler: template ref transform > ref + v-if 1`] = `
-"import { createTemplateRefSetter as _createTemplateRefSetter, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _setTemplateRef = _createTemplateRefSetter()
- const n0 = _createIf(() => (true), () => {
- const n2 = t0()
- _setTemplateRef(n2, "foo")
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: template ref transform > static ref (inline mode) 1`] = `
-"
- const _setTemplateRef = _createTemplateRefSetter()
- const n0 = t0()
- _setTemplateRef(n0, foo)
- return n0
-"
-`;
-
-exports[`compiler: template ref transform > static ref 1`] = `
-"import { createTemplateRefSetter as _createTemplateRefSetter, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _setTemplateRef = _createTemplateRefSetter()
- const n0 = t0()
- _setTemplateRef(n0, "foo")
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: text transform > consecutive text 1`] = `
-"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(_ctx.msg)))
- return n0
-}"
-`;
-
-exports[`compiler: text transform > no consecutive text 1`] = `
-"import { setText as _setText, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const n0 = t0()
- _setText(n0, "hello world")
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`cache multiple access > cache variable used in both property shorthand and normal binding 1`] = `
-"import { setStyle as _setStyle, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _color = _ctx.color
- _setStyle(n0, {color: _color})
- _setProp(n0, "id", _color)
- })
- return n0
-}"
-`;
-
-exports[`cache multiple access > dynamic key bindings with expressions 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _key = _ctx.key
- _setDynamicProps(n0, [{ [_key+1]: _ctx.foo[_key+1]() }], true)
- })
- return n0
-}"
-`;
-
-exports[`cache multiple access > dynamic property access 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _obj = _ctx.obj
- _setProp(n0, "id", _obj[1][_ctx.baz] + _obj.bar)
- })
- return n0
-}"
-`;
-
-exports[`cache multiple access > function calls with arguments 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t0()
- const n2 = t0()
- _renderEffect(() => {
- const _foo = _ctx.foo
- const _bar = _ctx.bar
- const _foo_bar_baz = _foo[_bar(_ctx.baz)]
- _setProp(n0, "id", _foo_bar_baz)
- _setProp(n1, "id", _foo_bar_baz)
- _setProp(n2, "id", _bar() + _foo)
- })
- return [n0, n1, n2]
-}"
-`;
-
-exports[`cache multiple access > not cache variable and member expression with the same name 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setProp(n0, "id", _ctx.bar + _ctx.obj.bar))
- return n0
-}"
-`;
-
-exports[`cache multiple access > not cache variable in function expression 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, [{ foo: bar => _ctx.foo = bar }], true))
- return n0
-}"
-`;
-
-exports[`cache multiple access > not cache variable only used in property shorthand 1`] = `
-"import { setStyle as _setStyle, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setStyle(n0, {color: _ctx.color}))
- return n0
-}"
-`;
-
-exports[`cache multiple access > object property chain access 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t0()
- _renderEffect(() => {
- const _obj = _ctx.obj
- const _obj_foo_baz_obj_bar = _obj['foo']['baz'] + _obj.bar
- _setProp(n0, "id", _obj_foo_baz_obj_bar)
- _setProp(n1, "id", _obj_foo_baz_obj_bar)
- })
- return [n0, n1]
-}"
-`;
-
-exports[`cache multiple access > object property name substring cases 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _p = _ctx.p
- const _p_title = _p.title
- _setProp(n0, "id", _p_title + _p.titles + _p_title)
- })
- return n0
-}"
-`;
-
-exports[`cache multiple access > optional chaining 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _obj = _ctx.obj
- _setProp(n0, "id", _obj?.foo + _obj?.bar)
- })
- return n0
-}"
-`;
-
-exports[`cache multiple access > repeated expression in expressions 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t0()
- const n2 = t0()
- _renderEffect(() => {
- const _foo = _ctx.foo
- const _foo_bar = _foo + _ctx.bar
- _setProp(n0, "id", _foo_bar)
- _setProp(n1, "id", _foo_bar)
- _setProp(n2, "id", _foo + _foo_bar)
- })
- return [n0, n1, n2]
-}"
-`;
-
-exports[`cache multiple access > repeated expressions 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t0()
- _renderEffect(() => {
- const _foo_bar = _ctx.foo + _ctx.bar
- _setProp(n0, "id", _foo_bar)
- _setProp(n1, "id", _foo_bar)
- })
- return [n0, n1]
-}"
-`;
-
-exports[`cache multiple access > repeated variable in expressions 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t0()
- _renderEffect(() => {
- const _foo = _ctx.foo
- _setProp(n0, "id", _foo + _foo + _ctx.bar)
- _setProp(n1, "id", _foo)
- })
- return [n0, n1]
-}"
-`;
-
-exports[`cache multiple access > repeated variables 1`] = `
-"import { setClass as _setClass, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t0()
- _renderEffect(() => {
- const _foo = _ctx.foo
- _setClass(n0, _foo)
- _setClass(n1, _foo)
- })
- return [n0, n1]
-}"
-`;
-
-exports[`cache multiple access > variable name substring edge cases 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _title = _ctx.title
- _setProp(n0, "id", _title + _ctx.titles + _title)
- })
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .attr modifier 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setAttr(n0, "foo-bar", _ctx.id))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .attr modifier w/ innerHTML 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setAttr(n0, "innerHTML", _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .attr modifier w/ no expression 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setAttr(n0, "foo-bar", _ctx.fooBar))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .attr modifier w/ progress value 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<progress></progress>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setAttr(n0, "value", _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .attr modifier w/ textContent 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setAttr(n0, "textContent", _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .attr modifier w/ value 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setAttr(n0, "value", _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .camel modifier 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setProp(n0, "fooBar", _ctx.id))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .camel modifier w/ dynamic arg 1`] = `
-"import { camelize as _camelize, setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, [{ [_camelize(_ctx.foo)]: _ctx.id }], true))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .camel modifier w/ no expression 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setProp(n0, "fooBar", _ctx.fooBar))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier (shorthand) 1`] = `
-"import { setDOMProp as _setDOMProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.id))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier (shorthand) w/ innerHTML 1`] = `
-"import { setHtml as _setHtml, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setHtml(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier (shorthand) w/ no expression 1`] = `
-"import { setDOMProp as _setDOMProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.fooBar))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier (shorthand) w/ progress value 1`] = `
-"import { setDOMProp as _setDOMProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<progress></progress>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "value", _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier (shorthand) w/ textContent 1`] = `
-"import { setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier (shorthand) w/ value 1`] = `
-"import { setValue as _setValue, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setValue(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier 1`] = `
-"import { setDOMProp as _setDOMProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.id))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier w/ dynamic arg 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, [{ ["." + _ctx.fooBar]: _ctx.id }], true))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier w/ innerHTML 1`] = `
-"import { setHtml as _setHtml, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setHtml(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier w/ no expression 1`] = `
-"import { setDOMProp as _setDOMProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.fooBar))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier w/ progress value 1`] = `
-"import { setDOMProp as _setDOMProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<progress></progress>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "value", _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier w/ textContent 1`] = `
-"import { setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > .prop modifier w/ value 1`] = `
-"import { setValue as _setValue, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setValue(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > :innerHTML 1`] = `
-"import { setHtml as _setHtml, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setHtml(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > :textContext 1`] = `
-"import { setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > :value 1`] = `
-"import { setValue as _setValue, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setValue(n0, _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > :value w/ progress 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<progress></progress>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setProp(n0, "value", _ctx.foo))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > attributes must be set as attribute 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<input>")
-const t2 = _template("<textarea></textarea>")
-const t3 = _template("<img>")
-const t4 = _template("<video></video>")
-const t5 = _template("<canvas></canvas>")
-const t6 = _template("<source>")
-
-export function render(_ctx) {
- const n0 = t0()
- const n1 = t1()
- const n2 = t2()
- const n3 = t3()
- const n4 = t4()
- const n5 = t5()
- const n6 = t6()
- _renderEffect(() => {
- const _width = _ctx.width
- const _height = _ctx.height
- _setAttr(n0, "spellcheck", _ctx.spellcheck)
- _setAttr(n0, "draggable", _ctx.draggable)
- _setAttr(n0, "translate", _ctx.translate)
- _setAttr(n0, "form", _ctx.form)
- _setAttr(n1, "list", _ctx.list)
- _setAttr(n2, "type", _ctx.type)
- _setAttr(n3, "width", _width)
- _setAttr(n3, "height", _height)
- _setAttr(n4, "width", _width)
- _setAttr(n4, "height", _height)
- _setAttr(n5, "width", _width)
- _setAttr(n5, "height", _height)
- _setAttr(n6, "width", _width)
- _setAttr(n6, "height", _height)
- })
- return [n0, n1, n2, n3, n4, n5, n6]
-}"
-`;
-
-exports[`compiler v-bind > basic 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setProp(n0, "id", _ctx.id))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > dynamic arg 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _id = _ctx.id
- const _title = _ctx.title
- _setDynamicProps(n0, [{ [_id]: _id, [_title]: _title }], true)
- })
- return n0
-}"
-`;
-
-exports[`compiler v-bind > dynamic arg w/ static attribute 1`] = `
-"import { setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
- const _id = _ctx.id
- _setDynamicProps(n0, [{ [_id]: _id, foo: "bar", checked: "" }], true)
- })
- return n0
-}"
-`;
-
-exports[`compiler v-bind > no expression (shorthand) 1`] = `
-"import { setAttr as _setAttr, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setAttr(n0, "camel-case", _ctx.camelCase))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > no expression 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setProp(n0, "id", _ctx.id))
- return n0
-}"
-`;
-
-exports[`compiler v-bind > number value 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponentWithFallback(_component_Comp, { depth: () => (0) }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler v-bind > should error if empty expression 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<div arg></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- return n0
-}"
-`;
-
-exports[`compiler v-bind > with constant value 1`] = `
-"import { setProp as _setProp, template as _template } from 'vue';
-const t0 = _template("<div f=\\"foo1\\" h=\\"1\\"></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _setProp(n0, "a", void 0)
- _setProp(n0, "b", 1 > 2)
- _setProp(n0, "c", 1 + 2)
- _setProp(n0, "d", 1 ? 2 : 3)
- _setProp(n0, "e", (2))
- _setProp(n0, "g", 1)
- _setProp(n0, "i", true)
- _setProp(n0, "j", null)
- _setProp(n0, "k", _ctx.x)
- _setProp(n0, "l", { foo: 1 })
- _setProp(n0, "m", { [_ctx.x]: 1 })
- _setProp(n0, "n", { ...{ foo: 1 } })
- _setProp(n0, "o", [1, , 3])
- _setProp(n0, "p", [1, ...[2, 3]])
- _setProp(n0, "q", [1, 2])
- _setProp(n0, "r", /\\s+/)
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: v-for > array de-structured value (with rest) 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.list), (_for_item0, _for_key0) => {
- const n2 = t0()
- const x2 = _child(n2)
- _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value[0] + _for_item0.value.slice(1) + _for_key0.value)))
- return n2
- }, ([id, ...other], index) => (id))
- return n0
-}"
-`;
-
-exports[`compiler: v-for > array de-structured value 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.list), (_for_item0, _for_key0) => {
- const n2 = t0()
- const x2 = _child(n2)
- _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value[0] + _for_item0.value[1] + _for_key0.value)))
- return n2
- }, ([id, other], index) => (id))
- return n0
-}"
-`;
-
-exports[`compiler: v-for > basic v-for 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.items), (_for_item0) => {
- const n2 = t0()
- const x2 = _child(n2)
- n2.$evtclick = () => (_ctx.remove(_for_item0.value))
- _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value)))
- return n2
- }, (item) => (item.id))
- return n0
-}"
-`;
-
-exports[`compiler: v-for > multi effect 1`] = `
-"import { setProp as _setProp, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.items), (_for_item0, _for_key0) => {
- const n2 = t0()
- _renderEffect(() => {
- _setProp(n2, "item", _for_item0.value)
- _setProp(n2, "index", _for_key0.value)
- })
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: v-for > nested v-for 1`] = `
-"import { setInsertionState as _setInsertionState, child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<span> </span>")
-const t1 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
- const n5 = t1()
- _setInsertionState(n5)
- const n2 = _createFor(() => (_for_item0.value), (_for_item1) => {
- const n4 = t0()
- const x4 = _child(n4)
- _renderEffect(() => _setText(x4, _toDisplayString(_for_item1.value+_for_item0.value)))
- return n4
- }, null, 1)
- return n5
- })
- return n0
-}"
-`;
-
-exports[`compiler: v-for > object de-structured value (with rest) 1`] = `
-"import { getRestElement as _getRestElement, child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.list), (_for_item0, _for_key0) => {
- const n2 = t0()
- const x2 = _child(n2)
- _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value.id + _getRestElement(_for_item0.value, ["id"]) + _for_key0.value)))
- return n2
- }, ({ id, ...other }, index) => (id))
- return n0
-}"
-`;
-
-exports[`compiler: v-for > object de-structured value 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<span> </span>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.items), (_for_item0) => {
- const n2 = t0()
- const x2 = _child(n2)
- _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value.id) + _toDisplayString(_for_item0.value.value)))
- return n2
- }, ({ id, value }) => (id))
- return n0
-}"
-`;
-
-exports[`compiler: v-for > object value, key and index 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.list), (_for_item0, _for_key0, _for_index0) => {
- const n2 = t0()
- const x2 = _child(n2)
- _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value + _for_key0.value + _for_index0.value)))
- return n2
- }, (value, key, index) => (key))
- return n0
-}"
-`;
-
-exports[`compiler: v-for > v-for aliases w/ complex expressions 1`] = `
-"import { getDefaultValue as _getDefaultValue, child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
- const n2 = t0()
- const x2 = _child(n2)
- _renderEffect(() => _setText(x2, _toDisplayString(_getDefaultValue(_for_item0.value.foo, _ctx.bar) + _ctx.bar + _ctx.baz + _getDefaultValue(_for_item0.value.baz[0], _ctx.quux) + _ctx.quux)))
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: v-for > w/o value 1`] = `
-"import { createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div>item</div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.items), (_for_item0) => {
- const n2 = t0()
- return n2
- })
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`v-html > should convert v-html to innerHTML 1`] = `
-"import { setHtml as _setHtml, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- _renderEffect(() => _setHtml(n0, _ctx.code))
- return n0
-}"
-`;
-
-exports[`v-html > should raise error and ignore children when v-html is present 1`] = `
-"import { setHtml as _setHtml, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => _setHtml(n0, _ctx.test))
- return n0
-}"
-`;
-
-exports[`v-html > should raise error if has no expression 1`] = `
-"import { setHtml as _setHtml, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _setHtml(n0, "")
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: v-if > basic v-if 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.ok), () => {
- const n2 = t0()
- const x2 = _child(n2)
- _renderEffect(() => _setText(x2, _toDisplayString(_ctx.msg)))
- return n2
- })
- return n0
-}"
-`;
-
-exports[`compiler: v-if > comment between branches 1`] = `
-"import { createIf as _createIf, child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<!--foo-->")
-const t2 = _template("<p></p>")
-const t3 = _template("<!--bar-->")
-const t4 = _template("fine")
-const t5 = _template("<div> </div>")
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.ok), () => {
- const n2 = t0()
- return n2
- }, () => _createIf(() => (_ctx.orNot), () => {
- const n5 = t1()
- const n6 = t2()
- return [n5, n6]
- }, () => {
- const n10 = t3()
- const n11 = t4()
- return [n10, n11]
- }))
- const n13 = t5()
- const x13 = _child(n13)
- _renderEffect(() => _setText(x13, _toDisplayString(_ctx.text)))
- return [n0, n13]
-}"
-`;
-
-exports[`compiler: v-if > dedupe same template 1`] = `
-"import { createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div>hello</div>")
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.ok), () => {
- const n2 = t0()
- return n2
- })
- const n3 = _createIf(() => (_ctx.ok), () => {
- const n5 = t0()
- return n5
- })
- return [n0, n3]
-}"
-`;
-
-exports[`compiler: v-if > template v-if 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("hello")
-const t2 = _template("<p> </p>", true)
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.ok), () => {
- const n2 = t0()
- const n3 = t1()
- const n4 = t2()
- const x4 = _child(n4)
- _renderEffect(() => _setText(x4, _toDisplayString(_ctx.msg)))
- return [n2, n3, n4]
- })
- return n0
-}"
-`;
-
-exports[`compiler: v-if > v-if + v-else 1`] = `
-"import { createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<p></p>")
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.ok), () => {
- const n2 = t0()
- return n2
- }, () => {
- const n4 = t1()
- return n4
- })
- return n0
-}"
-`;
-
-exports[`compiler: v-if > v-if + v-else-if + v-else 1`] = `
-"import { createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<p></p>")
-const t2 = _template("fine")
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.ok), () => {
- const n2 = t0()
- return n2
- }, () => _createIf(() => (_ctx.orNot), () => {
- const n4 = t1()
- return n4
- }, () => {
- const n7 = t2()
- return n7
- }))
- return n0
-}"
-`;
-
-exports[`compiler: v-if > v-if + v-else-if 1`] = `
-"import { createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<p></p>")
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.ok), () => {
- const n2 = t0()
- return n2
- }, () => _createIf(() => (_ctx.orNot), () => {
- const n4 = t1()
- return n4
- }))
- return n0
-}"
-`;
-
-exports[`compiler: v-if > v-if + v-if / v-else[-if] 1`] = `
-"import { setInsertionState as _setInsertionState, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<span>foo</span>")
-const t1 = _template("<span>bar</span>")
-const t2 = _template("<span>baz</span>")
-const t3 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n8 = t3()
- _setInsertionState(n8)
- const n0 = _createIf(() => (_ctx.foo), () => {
- const n2 = t0()
- return n2
- })
- _setInsertionState(n8)
- const n3 = _createIf(() => (_ctx.bar), () => {
- const n5 = t1()
- return n5
- }, () => {
- const n7 = t2()
- return n7
- })
- return n8
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: vModel transform > component > v-model for component should generate modelModifiers 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponentWithFallback(_component_Comp, { modelValue: () => (_ctx.foo),
- "onUpdate:modelValue": () => _value => (_ctx.foo = _value),
- modelModifiers: () => ({ trim: true, "bar-baz": true }) }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > component > v-model for component should work 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponentWithFallback(_component_Comp, { modelValue: () => (_ctx.foo),
- "onUpdate:modelValue": () => _value => (_ctx.foo = _value) }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > component > v-model with arguments for component should generate modelModifiers 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponentWithFallback(_component_Comp, {
- foo: () => (_ctx.foo),
- "onUpdate:foo": () => _value => (_ctx.foo = _value),
- fooModifiers: () => ({ trim: true }),
- bar: () => (_ctx.bar),
- "onUpdate:bar": () => _value => (_ctx.bar = _value),
- barModifiers: () => ({ number: true })
- }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > component > v-model with arguments for component should work 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponentWithFallback(_component_Comp, { bar: () => (_ctx.foo),
- "onUpdate:bar": () => _value => (_ctx.foo = _value) }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > component > v-model with dynamic arguments for component should generate modelModifiers 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponentWithFallback(_component_Comp, { $: [
- () => ({ [_ctx.foo]: _ctx.foo,
- ["onUpdate:" + _ctx.foo]: () => _value => (_ctx.foo = _value),
- [_ctx.foo + "Modifiers"]: () => ({ trim: true }) }),
- () => ({ [_ctx.bar]: _ctx.bar,
- ["onUpdate:" + _ctx.bar]: () => _value => (_ctx.bar = _value),
- [_ctx.bar + "Modifiers"]: () => ({ number: true }) })
- ] }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > component > v-model with dynamic arguments for component should work 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponentWithFallback(_component_Comp, { $: [
- () => ({ [_ctx.arg]: _ctx.foo,
- ["onUpdate:" + _ctx.arg]: () => _value => (_ctx.foo = _value) })
- ] }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > modifiers > .lazy 1`] = `
-"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyTextModel(n0, () => (_ctx.model), _value => (_ctx.model = _value), { lazy: true })
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > modifiers > .number 1`] = `
-"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyTextModel(n0, () => (_ctx.model), _value => (_ctx.model = _value), { number: true })
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > modifiers > .trim 1`] = `
-"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyTextModel(n0, () => (_ctx.model), _value => (_ctx.model = _value), { trim: true })
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support input (checkbox) 1`] = `
-"import { applyCheckboxModel as _applyCheckboxModel, template as _template } from 'vue';
-const t0 = _template("<input type=\\"checkbox\\">", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyCheckboxModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support input (dynamic type) 1`] = `
-"import { applyDynamicModel as _applyDynamicModel, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyDynamicModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support input (radio) 1`] = `
-"import { applyRadioModel as _applyRadioModel, template as _template } from 'vue';
-const t0 = _template("<input type=\\"radio\\">", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyRadioModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support input (text) 1`] = `
-"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<input type=\\"text\\">", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyTextModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support member expression 1`] = `
-"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<input>")
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- const n1 = t0()
- const n2 = t0()
- _applyTextModel(n0, () => (_ctx.setupRef.child), _value => (_ctx.setupRef.child = _value))
- _applyTextModel(n1, () => (_ctx.setupLet.child), _value => (_ctx.setupLet.child = _value))
- _applyTextModel(n2, () => (_ctx.setupMaybeRef.child), _value => (_ctx.setupMaybeRef.child = _value))
- return [n0, n1, n2]
-}"
-`;
-
-exports[`compiler: vModel transform > should support member expression w/ inline 1`] = `
-"
- const n0 = t0()
- const n1 = t0()
- const n2 = t0()
- _applyTextModel(n0, () => (setupRef.value.child), _value => (setupRef.value.child = _value))
- _applyTextModel(n1, () => (_unref(setupLet).child), _value => (_unref(setupLet).child = _value))
- _applyTextModel(n2, () => (_unref(setupMaybeRef).child), _value => (_unref(setupMaybeRef).child = _value))
- return [n0, n1, n2]
-"
-`;
-
-exports[`compiler: vModel transform > should support select 1`] = `
-"import { applySelectModel as _applySelectModel, template as _template } from 'vue';
-const t0 = _template("<select></select>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applySelectModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support simple expression 1`] = `
-"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyTextModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support textarea 1`] = `
-"import { applyTextModel as _applyTextModel, template as _template } from 'vue';
-const t0 = _template("<textarea></textarea>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyTextModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support w/ dynamic v-bind 1`] = `
-"import { applyDynamicModel as _applyDynamicModel, setDynamicProps as _setDynamicProps, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyDynamicModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- _renderEffect(() => _setDynamicProps(n0, [_ctx.obj], true))
- return n0
-}"
-`;
-
-exports[`compiler: vModel transform > should support w/ dynamic v-bind 2`] = `
-"import { applyDynamicModel as _applyDynamicModel, template as _template } from 'vue';
-const t0 = _template("<input>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyDynamicModel(n0, () => (_ctx.model), _value => (_ctx.model = _value))
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`v-on > complex member expression w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = e => _ctx.a['b' + _ctx.c](e)
- return n0
-}"
-`;
-
-exports[`v-on > dynamic arg 1`] = `
-"import { on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
-
- _on(n0, _ctx.event, e => _ctx.handler(e), {
- effect: true
- })
- })
- return n0
-}"
-`;
-
-exports[`v-on > dynamic arg with complex exp prefixing 1`] = `
-"import { on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
-
- _on(n0, _ctx.event(_ctx.foo), e => _ctx.handler(e), {
- effect: true
- })
- })
- return n0
-}"
-`;
-
-exports[`v-on > dynamic arg with prefixing 1`] = `
-"import { on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
-
- _on(n0, _ctx.event, e => _ctx.handler(e), {
- effect: true
- })
- })
- return n0
-}"
-`;
-
-exports[`v-on > event modifier 1`] = `
-"import { withModifiers as _withModifiers, on as _on, withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
-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, $props, $emit, $attrs, $slots) {
- 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()
- n0.$evtclick = _withModifiers(_ctx.handleEvent, ["stop"])
- _on(n1, "submit", _withModifiers(_ctx.handleEvent, ["prevent"]))
- n2.$evtclick = _withModifiers(_ctx.handleEvent, ["stop","prevent"])
- n3.$evtclick = _withModifiers(_ctx.handleEvent, ["self"])
- _on(n4, "click", _ctx.handleEvent, {
- capture: true
- })
- _on(n5, "click", _ctx.handleEvent, {
- once: true
- })
- _on(n6, "scroll", _ctx.handleEvent, {
- passive: true
- })
- n7.$evtcontextmenu = _withModifiers(_ctx.handleEvent, ["right"])
- n8.$evtclick = _withModifiers(_ctx.handleEvent, ["left"])
- n9.$evtmouseup = _withModifiers(_ctx.handleEvent, ["middle"])
- n10.$evtcontextmenu = _withKeys(_withModifiers(_ctx.handleEvent, ["right"]), ["enter"])
- n11.$evtkeyup = _withKeys(_ctx.handleEvent, ["enter"])
- n12.$evtkeyup = _withKeys(_ctx.handleEvent, ["tab"])
- n13.$evtkeyup = _withKeys(_ctx.handleEvent, ["delete"])
- n14.$evtkeyup = _withKeys(_ctx.handleEvent, ["esc"])
- n15.$evtkeyup = _withKeys(_ctx.handleEvent, ["space"])
- n16.$evtkeyup = _withKeys(_ctx.handleEvent, ["up"])
- n17.$evtkeyup = _withKeys(_ctx.handleEvent, ["down"])
- n18.$evtkeyup = _withKeys(_ctx.handleEvent, ["left"])
- n19.$evtkeyup = _withModifiers(e => _ctx.submit(e), ["middle"])
- n20.$evtkeyup = _withModifiers(e => _ctx.submit(e), ["middle","self"])
- n21.$evtkeyup = _withKeys(_withModifiers(_ctx.handleEvent, ["self"]), ["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 > expression with type 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- n0.$evtclick = e => _ctx.handleClick(e)
- return n0
-}"
-`;
-
-exports[`v-on > function expression w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = e => _ctx.foo(e)
- return n0
-}"
-`;
-
-exports[`v-on > inline statement w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = $event => (_ctx.foo($event))
- return n0
-}"
-`;
-
-exports[`v-on > multiple inline statements w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = $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 { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = $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 { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = (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 { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick =
- $event => {
- _ctx.foo($event)
- }
-
- return n0
-}"
-`;
-
-exports[`v-on > should NOT wrap as function if expression is already function expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = $event => _ctx.foo($event)
- return n0
-}"
-`;
-
-exports[`v-on > should NOT wrap as function if expression is complex member expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = e => _ctx.a['b' + _ctx.c](e)
- return n0
-}"
-`;
-
-exports[`v-on > should delegate event 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = e => _ctx.test(e)
- return n0
-}"
-`;
-
-exports[`v-on > should handle multi-line statement 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = () => {
-_ctx.foo();
-_ctx.bar()
-}
- return n0
-}"
-`;
-
-exports[`v-on > should handle multiple inline statement 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = () => {_ctx.foo();_ctx.bar()}
- return n0
-}"
-`;
-
-exports[`v-on > should not prefix member expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = e => _ctx.foo.bar(e)
- return n0
-}"
-`;
-
-exports[`v-on > should not wrap keys guard if no key modifier is present 1`] = `
-"import { withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("keyup")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtkeyup = _withModifiers(e => _ctx.test(e), ["exact"])
- return n0
-}"
-`;
-
-exports[`v-on > should support multiple events and modifiers options w/ prefixIdentifiers: true 1`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click", "keyup")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = _withModifiers(e => _ctx.test(e), ["stop"])
- n0.$evtkeyup = _withKeys(e => _ctx.test(e), ["enter"])
- return n0
-}"
-`;
-
-exports[`v-on > should support multiple modifiers and event options w/ prefixIdentifiers: true 1`] = `
-"import { withModifiers as _withModifiers, on as _on, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _on(n0, "click", _withModifiers(e => _ctx.test(e), ["stop","prevent"]), {
- capture: true,
- once: true
- })
- return n0
-}"
-`;
-
-exports[`v-on > should transform click.middle 1`] = `
-"import { withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("mouseup")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtmouseup = _withModifiers(e => _ctx.test(e), ["middle"])
- return n0
-}"
-`;
-
-exports[`v-on > should transform click.middle 2`] = `
-"import { withModifiers as _withModifiers, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
-
- _on(n0, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), _withModifiers(e => _ctx.test(e), ["middle"]), {
- effect: true
- })
- })
- return n0
-}"
-`;
-
-exports[`v-on > should transform click.right 1`] = `
-"import { withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("contextmenu")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtcontextmenu = _withModifiers(e => _ctx.test(e), ["right"])
- return n0
-}"
-`;
-
-exports[`v-on > should transform click.right 2`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
-
- _on(n0, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), _withKeys(_withModifiers(e => _ctx.test(e), ["right"]), ["right"]), {
- effect: true
- })
- })
- return n0
-}"
-`;
-
-exports[`v-on > should use delegate helper when have multiple events of same name 1`] = `
-"import { delegate as _delegate, withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- _delegate(n0, "click", e => _ctx.test(e))
- _delegate(n0, "click", _withModifiers(e => _ctx.test(e), ["stop"]))
- return n0
-}"
-`;
-
-exports[`v-on > should wrap as function if expression is inline statement 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtclick = () => (_ctx.i++)
- return n0
-}"
-`;
-
-exports[`v-on > should wrap both for dynamic key event w/ left/right modifiers 1`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _renderEffect(() => {
-
- _on(n0, _ctx.e, _withKeys(_withModifiers(e => _ctx.test(e), ["left"]), ["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()
- n0.$evtclick = () => (x.value=_unref(y))
- n1.$evtclick = () => (x.value++)
- n2.$evtclick = () => ({ x: x.value } = _unref(y))
- return [n0, n1, n2]
-"
-`;
-
-exports[`v-on > should wrap keys guard for keyboard events or dynamic events 1`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, on as _on, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _on(n0, "keydown", _withKeys(_withModifiers(e => _ctx.test(e), ["stop","ctrl"]), ["a"]), {
- capture: true
- })
- return n0
-}"
-`;
-
-exports[`v-on > should wrap keys guard for static key event w/ left/right modifiers 1`] = `
-"import { withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("keyup")
-
-export function render(_ctx) {
- const n0 = t0()
- n0.$evtkeyup = _withKeys(e => _ctx.test(e), ["left"])
- return n0
-}"
-`;
-
-exports[`v-on > simple expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-_delegateEvents("click")
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- n0.$evtclick = _ctx.handleClick
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: v-once > as root node 1`] = `
-"import { setProp as _setProp, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _setProp(n0, "id", _ctx.foo)
- return n0
-}"
-`;
-
-exports[`compiler: v-once > basic 1`] = `
-"import { child as _child, next as _next, toDisplayString as _toDisplayString, setText as _setText, setClass as _setClass, template as _template } from 'vue';
-const t0 = _template("<div> <span></span></div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n2 = t0()
- const n0 = _child(n2)
- const n1 = _next(n0)
- _setText(n0, _toDisplayString(_ctx.msg) + " ")
- _setClass(n1, _ctx.clz)
- return n2
-}"
-`;
-
-exports[`compiler: v-once > inside v-once 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<div><div></div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- return n0
-}"
-`;
-
-exports[`compiler: v-once > on component 1`] = `
-"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n1 = t0()
- _setInsertionState(n1)
- const n0 = _createComponentWithFallback(_component_Comp, { id: () => (_ctx.foo) }, null, null, true)
- return n1
-}"
-`;
-
-exports[`compiler: v-once > on nested plain element 1`] = `
-"import { child as _child, setProp as _setProp, template as _template } from 'vue';
-const t0 = _template("<div><div></div></div>", true)
-
-export function render(_ctx) {
- const n1 = t0()
- const n0 = _child(n1)
- _setProp(n0, "id", _ctx.foo)
- return n1
-}"
-`;
-
-exports[`compiler: v-once > with v-for 1`] = `
-"import { createFor as _createFor, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createFor(() => (_ctx.list), (_for_item0) => {
- const n2 = t0()
- return n2
- }, null, 4)
- return n0
-}"
-`;
-
-exports[`compiler: v-once > with v-if 1`] = `
-"import { createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.expr), () => {
- const n2 = t0()
- return n2
- }, null, true)
- return n0
-}"
-`;
-
-exports[`compiler: v-once > with v-if/else 1`] = `
-"import { createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-const t1 = _template("<p></p>")
-
-export function render(_ctx) {
- const n0 = _createIf(() => (_ctx.expr), () => {
- const n2 = t0()
- return n2
- }, () => {
- const n4 = t1()
- return n4
- }, true)
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: v-show transform > simple expression 1`] = `
-"import { applyVShow as _applyVShow, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- _applyVShow(n0, () => (_ctx.foo))
- return n0
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`compiler: transform slot > dynamic slots name 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template("foo")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n2 = _createComponentWithFallback(_component_Comp, null, {
- $: [
- () => ({
- name: _ctx.name,
- fn: () => {
- const n0 = t0()
- return n0
- }
- })
- ]
- }, true)
- return n2
-}"
-`;
-
-exports[`compiler: transform slot > dynamic slots name w/ v-for 1`] = `
-"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createForSlots as _createForSlots, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n2 = _createComponentWithFallback(_component_Comp, null, {
- $: [
- () => (_createForSlots(_ctx.list, (item) => ({
- name: item,
- fn: (_slotProps0) => {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["bar"])))
- return n0
- }
- })))
- ]
- }, true)
- return n2
-}"
-`;
-
-exports[`compiler: transform slot > dynamic slots name w/ v-for and provide absent key 1`] = `
-"import { resolveComponent as _resolveComponent, createForSlots as _createForSlots, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template("foo")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n2 = _createComponentWithFallback(_component_Comp, null, {
- $: [
- () => (_createForSlots(_ctx.list, (_, __, index) => ({
- name: index,
- fn: () => {
- const n0 = t0()
- return n0
- }
- })))
- ]
- }, true)
- return n2
-}"
-`;
-
-exports[`compiler: transform slot > dynamic slots name w/ v-if / v-else[-if] 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template("condition slot")
-const t1 = _template("another condition")
-const t2 = _template("else condition")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n6 = _createComponentWithFallback(_component_Comp, null, {
- $: [
- () => (_ctx.condition
- ? {
- name: "condition",
- fn: () => {
- const n0 = t0()
- return n0
- }
- }
- : _ctx.anotherCondition
- ? {
- name: "condition",
- fn: (_slotProps0) => {
- const n2 = t1()
- return n2
- }
- }
- : {
- name: "condition",
- fn: () => {
- const n4 = t2()
- return n4
- }
- })
- ]
- }, true)
- return n6
-}"
-`;
-
-exports[`compiler: transform slot > implicit default slot 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template("<div></div>")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n1 = _createComponentWithFallback(_component_Comp, null, {
- "default": () => {
- const n0 = t0()
- return n0
- }
- }, true)
- return n1
-}"
-`;
-
-exports[`compiler: transform slot > named slots w/ implicit default slot 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template("foo")
-const t1 = _template("bar")
-const t2 = _template("<span></span>")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n4 = _createComponentWithFallback(_component_Comp, null, {
- "one": () => {
- const n0 = t0()
- return n0
- },
- "default": () => {
- const n2 = t1()
- const n3 = t2()
- return [n2, n3]
- }
- }, true)
- return n4
-}"
-`;
-
-exports[`compiler: transform slot > nested component slot 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_B = _resolveComponent("B")
- const _component_A = _resolveComponent("A")
- const n1 = _createComponentWithFallback(_component_A, null, {
- "default": () => {
- const n0 = _createComponentWithFallback(_component_B)
- return n0
- }
- }, true)
- return n1
-}"
-`;
-
-exports[`compiler: transform slot > nested slots scoping 1`] = `
-"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const _component_Inner = _resolveComponent("Inner")
- const _component_Comp = _resolveComponent("Comp")
- const n5 = _createComponentWithFallback(_component_Comp, null, {
- "default": (_slotProps0) => {
- const n1 = _createComponentWithFallback(_component_Inner, null, {
- "default": (_slotProps1) => {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _slotProps1["bar"] + _ctx.baz)))
- return n0
- }
- })
- const n3 = t0()
- _renderEffect(() => _setText(n3, " " + _toDisplayString(_slotProps0["foo"] + _ctx.bar + _ctx.baz)))
- return [n1, n3]
- }
- }, true)
- return n5
-}"
-`;
-
-exports[`compiler: transform slot > on component dynamically named slot 1`] = `
-"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n1 = _createComponentWithFallback(_component_Comp, null, {
- $: [
- () => ({
- name: _ctx.named,
- fn: (_slotProps0) => {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _ctx.bar)))
- return n0
- }
- })
- ]
- }, true)
- return n1
-}"
-`;
-
-exports[`compiler: transform slot > on component named slot 1`] = `
-"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n1 = _createComponentWithFallback(_component_Comp, null, {
- "named": (_slotProps0) => {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _ctx.bar)))
- return n0
- }
- }, true)
- return n1
-}"
-`;
-
-exports[`compiler: transform slot > on-component default slot 1`] = `
-"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" ")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n1 = _createComponentWithFallback(_component_Comp, null, {
- "default": (_slotProps0) => {
- const n0 = t0()
- _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _ctx.bar)))
- return n0
- }
- }, true)
- return n1
-}"
-`;
-
-exports[`compiler: transform slot > quote slot name 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n1 = _createComponentWithFallback(_component_Comp, null, {
- "nav-bar-title-before": () => {
- return null
- }
- }, true)
- return n1
-}"
-`;
-
-exports[`compiler: transform slot > slot + v-if / v-else[-if] should not cause error 1`] = `
-"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createSlot as _createSlot, createComponentWithFallback as _createComponentWithFallback, createIf as _createIf, template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const _component_Foo = _resolveComponent("Foo")
- const _component_Bar = _resolveComponent("Bar")
- const n6 = t0()
- _setInsertionState(n6)
- const n0 = _createSlot("foo", null)
- _setInsertionState(n6)
- const n1 = _createIf(() => (true), () => {
- const n3 = _createComponentWithFallback(_component_Foo)
- return n3
- }, () => {
- const n5 = _createComponentWithFallback(_component_Bar)
- return n5
- })
- return n6
-}"
-`;
-
-exports[`compiler: transform slot > with whitespace: 'preserve' > implicit default slot 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" Header ")
-const t1 = _template(" ")
-const t2 = _template("<p></p>")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n4 = _createComponentWithFallback(_component_Comp, null, {
- "header": () => {
- const n0 = t0()
- return n0
- },
- "default": () => {
- const n2 = t1()
- const n3 = t2()
- return [n2, n3]
- }
- }, true)
- return n4
-}"
-`;
-
-exports[`compiler: transform slot > with whitespace: 'preserve' > named default slot + implicit whitespace content 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" Header ")
-const t1 = _template(" Default ")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n5 = _createComponentWithFallback(_component_Comp, null, {
- "header": () => {
- const n0 = t0()
- return n0
- },
- "default": () => {
- const n3 = t1()
- return n3
- }
- }, true)
- return n5
-}"
-`;
-
-exports[`compiler: transform slot > with whitespace: 'preserve' > should not generate whitespace only default slot 1`] = `
-"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
-const t0 = _template(" Header ")
-const t1 = _template(" Footer ")
-
-export function render(_ctx) {
- const _component_Comp = _resolveComponent("Comp")
- const n5 = _createComponentWithFallback(_component_Comp, null, {
- "header": () => {
- const n0 = t0()
- return n0
- },
- "footer": () => {
- const n3 = t1()
- return n3
- }
- }, true)
- return n5
-}"
-`;
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`v-text > should convert v-text to setText 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n0 = t0()
- const x0 = _child(n0)
- _renderEffect(() => _setText(x0, _toDisplayString(_ctx.str)))
- return n0
-}"
-`;
-
-exports[`v-text > should raise error and ignore children when v-text is present 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
-const t0 = _template("<div> </div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- const x0 = _child(n0)
- _renderEffect(() => _setText(x0, _toDisplayString(_ctx.test)))
- return n0
-}"
-`;
-
-exports[`v-text > should raise error if has no expression 1`] = `
-"import { template as _template } from 'vue';
-const t0 = _template("<div></div>", true)
-
-export function render(_ctx) {
- const n0 = t0()
- return n0
-}"
-`;
+++ /dev/null
-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 = {},
- ): {
- ast: RootNode
- ir: RootIRNode
- code: string
- helpers: Set<string>
- } => {
- const ast = parse(template, {
- prefixIdentifiers: true,
- ...options,
- ...overrideOptions,
- })
- const ir = transform(ast, {
- prefixIdentifiers: true,
- ...options,
- ...overrideOptions,
- })
- const { code, helpers } = generate(ir, {
- prefixIdentifiers: true,
- ...options,
- ...overrideOptions,
- })
- return { ast, ir, code, helpers }
- }
-}
+++ /dev/null
-import { BindingTypes } from '@vue/compiler-dom'
-import {
- transformChildren,
- transformElement,
- transformText,
- transformVBind,
-} from '../../src'
-import { makeCompile } from './_utils'
-
-const compileWithExpression = makeCompile({
- nodeTransforms: [transformElement, transformChildren, transformText],
- directiveTransforms: { bind: transformVBind },
-})
-
-describe('compiler: expression', () => {
- test('basic', () => {
- const { code } = compileWithExpression(`{{ a }}`)
- expect(code).toMatchSnapshot()
- expect(code).contains(`ctx.a`)
- })
-
- test('props', () => {
- const { code } = compileWithExpression(`{{ foo }}`, {
- bindingMetadata: { foo: BindingTypes.PROPS },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains(`$props.foo`)
- })
-
- test('props aliased', () => {
- const { code } = compileWithExpression(`{{ foo }}`, {
- bindingMetadata: {
- foo: BindingTypes.PROPS_ALIASED,
- __propsAliases: { foo: 'bar' } as any,
- },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains(`$props['bar']`)
- })
-
- test('update expression', () => {
- const { code } = compileWithExpression(`
- <div :id="String(foo.id++)" :foo="foo" :bar="bar++">
- {{ String(foo.id++) }} {{ foo }} {{ bar }}
- </div>
- `)
- expect(code).toMatchSnapshot()
- expect(code).contains(`_String(_foo.id++)`)
- })
-})
+++ /dev/null
-import { makeCompile } from './_utils'
-import {
- transformChildren,
- transformElement,
- transformText,
- transformVIf,
-} from '../../src'
-
-const compileWithElementTransform = makeCompile({
- nodeTransforms: [
- transformText,
- transformVIf,
- transformElement,
- transformChildren,
- ],
-})
-
-describe('compiler: children transform', () => {
- test('children & sibling references', () => {
- const { code, helpers } = compileWithElementTransform(
- `<div>
- <p>{{ first }}</p>
- {{ second }}
- {{ third }}
- <p>{{ forth }}</p>
- </div>`,
- )
- expect(code).toMatchSnapshot()
- expect(Array.from(helpers)).containSubset([
- 'child',
- 'toDisplayString',
- 'renderEffect',
- 'next',
- 'setText',
- 'template',
- ])
- })
-
- test('efficient traversal', () => {
- const { code } = compileWithElementTransform(
- `<div>
- <div>x</div>
- <div><span>{{ msg }}</span></div>
- <div><span>{{ msg }}</span></div>
- <div><span>{{ msg }}</span></div>
- </div>`,
- )
- expect(code).toMatchSnapshot()
- })
-
- test('efficient find', () => {
- const { code } = compileWithElementTransform(
- `<div>
- <div>x</div>
- <div>x</div>
- <div>{{ msg }}</div>
- </div>`,
- )
- expect(code).contains(`const n0 = _nthChild(n1, 2)`)
- expect(code).toMatchSnapshot()
- })
-
- test('anchor insertion in middle', () => {
- const { code } = compileWithElementTransform(
- `<div>
- <div></div>
- <div v-if="1"></div>
- <div></div>
- </div>`,
- )
- // ensure the insertion anchor is generated before the insertion statement
- expect(code).toMatch(`const n3 = _next(_child(n4))`)
- expect(code).toMatch(`_setInsertionState(n4, n3)`)
- expect(code).toMatchSnapshot()
- })
-})
+++ /dev/null
-import { makeCompile } from './_utils'
-import {
- IRDynamicPropsKind,
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformText,
- transformVBind,
- transformVFor,
- transformVOn,
-} from '../../src'
-import {
- type BindingMetadata,
- BindingTypes,
- NodeTypes,
-} from '@vue/compiler-dom'
-
-const compileWithElementTransform = makeCompile({
- nodeTransforms: [
- transformVFor,
- transformElement,
- transformChildren,
- transformText,
- ],
- directiveTransforms: {
- bind: transformVBind,
- on: transformVOn,
- },
-})
-
-describe('compiler: element transform', () => {
- describe('component', () => {
- test('import + resolve component', () => {
- const { code, ir, helpers } = compileWithElementTransform(`<Foo/>`)
- expect(code).toMatchSnapshot()
- expect(helpers).contains.all.keys('resolveComponent')
- expect(helpers).contains.all.keys('createComponentWithFallback')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 0,
- tag: 'Foo',
- asset: true,
- root: true,
- props: [[]],
- })
- })
-
- test('resolve implicitly self-referencing component', () => {
- const { code, helpers } = compileWithElementTransform(`<Example/>`, {
- filename: `/foo/bar/Example.vue?vue&type=template`,
- })
- expect(code).toMatchSnapshot()
- expect(code).toContain('_resolveComponent("Example", true)')
- expect(helpers).toContain('resolveComponent')
- })
-
- test('resolve component from setup bindings', () => {
- const { code, ir, helpers } = compileWithElementTransform(`<Example/>`, {
- bindingMetadata: {
- Example: BindingTypes.SETUP_MAYBE_REF,
- },
- })
- expect(code).toMatchSnapshot()
- expect(helpers).not.toContain('resolveComponent')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Example',
- asset: false,
- })
- })
-
- test('resolve component from setup bindings (inline)', () => {
- const { code, helpers } = compileWithElementTransform(`<Example/>`, {
- inline: true,
- bindingMetadata: {
- Example: BindingTypes.SETUP_MAYBE_REF,
- },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains(`unref(Example)`)
- expect(helpers).not.toContain('resolveComponent')
- expect(helpers).toContain('unref')
- })
-
- test('resolve component from setup bindings (inline const)', () => {
- const { code, helpers } = compileWithElementTransform(`<Example/>`, {
- inline: true,
- bindingMetadata: {
- Example: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).toMatchSnapshot()
- expect(helpers).not.toContain('resolveComponent')
- })
-
- test('resolve namespaced component from setup bindings', () => {
- const { code, helpers } = compileWithElementTransform(`<Foo.Example/>`, {
- bindingMetadata: {
- Foo: BindingTypes.SETUP_MAYBE_REF,
- },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains(`_ctx.Foo.Example`)
- expect(helpers).not.toContain('resolveComponent')
- })
-
- test('resolve namespaced component from setup bindings (inline const)', () => {
- const { code, helpers } = compileWithElementTransform(`<Foo.Example/>`, {
- inline: true,
- bindingMetadata: {
- Foo: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains(`Foo.Example`)
- expect(helpers).not.toContain('resolveComponent')
- })
-
- test('resolve namespaced component from props bindings (inline)', () => {
- const { code, helpers } = compileWithElementTransform(`<Foo.Example/>`, {
- inline: true,
- bindingMetadata: {
- Foo: BindingTypes.PROPS,
- },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains(`Foo.Example`)
- expect(helpers).not.toContain('resolveComponent')
- })
-
- test('resolve namespaced component from props bindings (non-inline)', () => {
- const { code, helpers } = compileWithElementTransform(`<Foo.Example/>`, {
- inline: false,
- bindingMetadata: {
- Foo: BindingTypes.PROPS,
- },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains('_ctx.Foo.Example')
- expect(helpers).not.toContain('resolveComponent')
- })
-
- test('do not resolve component from non-script-setup bindings', () => {
- const bindingMetadata: BindingMetadata = {
- Example: BindingTypes.SETUP_MAYBE_REF,
- }
- Object.defineProperty(bindingMetadata, '__isScriptSetup', {
- value: false,
- })
- const { code, ir, helpers } = compileWithElementTransform(`<Example/>`, {
- bindingMetadata,
- })
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('resolveComponent')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 0,
- tag: 'Example',
- asset: true,
- })
- })
-
- test('generate single root component', () => {
- const { code } = compileWithElementTransform(`<Comp/>`, {
- bindingMetadata: { Comp: BindingTypes.SETUP_CONST },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains('_createComponent(_ctx.Comp, null, null, true)')
- })
-
- test('generate multi root component', () => {
- const { code } = compileWithElementTransform(`<Comp/>123`, {
- bindingMetadata: { Comp: BindingTypes.SETUP_CONST },
- })
- expect(code).toMatchSnapshot()
- expect(code).contains('_createComponent(_ctx.Comp)')
- })
-
- test('v-for on component should not mark as single root', () => {
- const { code } = compileWithElementTransform(
- `<Comp v-for="item in items" :key="item"/>`,
- {
- bindingMetadata: { Comp: BindingTypes.SETUP_CONST },
- },
- )
- expect(code).toMatchSnapshot()
- expect(code).contains('_createComponent(_ctx.Comp)')
- })
-
- test('static props', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo id="foo" class="bar" />`,
- )
-
- expect(code).toMatchSnapshot()
- expect(code).contains(`{
- id: () => ("foo"),
- class: () => ("bar")
- }`)
-
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- asset: true,
- root: true,
- props: [
- [
- {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
- ],
- },
- {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'class',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'bar',
- isStatic: true,
- },
- ],
- },
- ],
- ],
- })
- })
-
- test('v-bind="obj"', () => {
- const { code, ir } = compileWithElementTransform(`<Foo v-bind="obj" />`)
- expect(code).toMatchSnapshot()
- expect(code).contains(`[
- () => (_ctx.obj)
- ]`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj', isStatic: false },
- },
- ],
- })
- })
-
- test('v-bind="obj" after static prop', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo id="foo" v-bind="obj" />`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains(`{
- id: () => ("foo"),
- $: [
- () => (_ctx.obj)
- ]
- }`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- ],
- })
- })
-
- test('v-bind="obj" before static prop', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo v-bind="obj" id="foo" />`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains(`[
- () => (_ctx.obj),
- { id: () => ("foo") }
- ]`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- ],
- })
- })
-
- test('v-bind="obj" between static props', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo id="foo" v-bind="obj" class="bar" />`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains(`{
- id: () => ("foo"),
- $: [
- () => (_ctx.obj),
- { class: () => ("bar") }
- ]
- }`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- [{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
- ],
- })
- })
-
- test.todo('props merging: event handlers', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo @click.foo="a" @click.bar="b" />`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains('onClick: () => [_ctx.a, _ctx.b]')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'onClick', isStatic: true },
- values: [{ content: 'a' }, { content: 'b' }],
- },
- ],
- ],
- },
- ])
- })
-
- test.todo('props merging: style', () => {
- const { code } = compileWithElementTransform(
- `<Foo style="color: green" :style="{ color: 'red' }" />`,
- )
- expect(code).toMatchSnapshot()
- })
-
- test.todo('props merging: class', () => {
- const { code } = compileWithElementTransform(
- `<Foo class="foo" :class="{ bar: isBar }" />`,
- )
- expect(code).toMatchSnapshot()
- })
-
- test('v-on="obj"', () => {
- const { code, ir } = compileWithElementTransform(`<Foo v-on="obj" />`)
- expect(code).toMatchSnapshot()
- expect(code).contains(`[
- () => (_toHandlers(_ctx.obj))
- ]`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- handler: true,
- },
- ],
- })
- })
-
- test('v-on expression is inline statement', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo v-on:bar="() => handler" />`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains(`onBar: () => _on_bar`)
- expect(code).contains(`const _on_bar = () => _ctx.handler`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar' }],
- },
- ],
- ],
- })
- })
-
- test('v-on expression is a function call', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo v-on:bar="handleBar($event)" />`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains(`onBar: () => _on_bar`)
- expect(code).contains(
- `const _on_bar = $event => (_ctx.handleBar($event))`,
- )
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar' }],
- },
- ],
- ],
- })
- })
-
- test('cache v-on expression with unique handler name', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo v-on:bar="handleBar($event)" /><Bar v-on:bar="() => handler" />`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains(`onBar: () => _on_bar`)
- expect(code).contains(
- `const _on_bar = $event => (_ctx.handleBar($event))`,
- )
- expect(code).contains(`onBar: () => _on_bar1`)
- expect(code).contains(`const _on_bar1 = () => _ctx.handler`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar' }],
- },
- ],
- ],
- })
-
- expect(ir.block.dynamic.children[1].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Bar',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar1' }],
- },
- ],
- ],
- })
- })
- })
-
- describe('dynamic component', () => {
- test('static binding', () => {
- const { code, ir, helpers } = compileWithElementTransform(
- `<component is="foo" />`,
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('resolveDynamicComponent')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
- })
- })
-
- test('capitalized version w/ static binding', () => {
- const { code, ir, helpers } = compileWithElementTransform(
- `<Component is="foo" />`,
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('resolveDynamicComponent')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
- })
- })
-
- test('dynamic binding', () => {
- const { code, ir, helpers } = compileWithElementTransform(
- `<component :is="foo" />`,
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('createDynamicComponent')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: false,
- },
- })
- })
-
- test('dynamic binding shorthand', () => {
- const { code, ir, helpers } =
- compileWithElementTransform(`<component :is />`)
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('createDynamicComponent')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'is',
- isStatic: false,
- },
- })
- })
-
- // #3934
- test('normal component with is prop', () => {
- const { code, ir, helpers } = compileWithElementTransform(
- `<custom-input is="foo" />`,
- {
- isNativeTag: () => false,
- },
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('resolveComponent')
- expect(helpers).not.toContain('resolveDynamicComponent')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'custom-input',
- asset: true,
- root: true,
- props: [[{ key: { content: 'is' }, values: [{ content: 'foo' }] }]],
- })
- })
- })
-
- test('static props', () => {
- const { code, ir } = compileWithElementTransform(
- `<div id="foo" class="bar" />`,
- )
-
- const template = '<div id="foo" class="bar"></div>'
- expect(code).toMatchSnapshot()
- expect(code).contains(JSON.stringify(template))
- expect(ir.template).toMatchObject([template])
- expect(ir.block.effect).lengthOf(0)
- })
-
- test('props + children', () => {
- const { code, ir } = compileWithElementTransform(
- `<div id="foo"><span/></div>`,
- )
-
- const template = '<div id="foo"><span></span></div>'
- expect(code).toMatchSnapshot()
- expect(code).contains(JSON.stringify(template))
- expect(ir.template).toMatchObject([template])
- expect(ir.block.effect).lengthOf(0)
- })
-
- test('v-bind="obj"', () => {
- const { code, ir } = compileWithElementTransform(`<div v-bind="obj" />`)
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'obj',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- element: 0,
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'obj',
- isStatic: false,
- },
- },
- ],
- },
- ],
- },
- ])
- expect(code).contains('_setDynamicProps(n0, [_ctx.obj], true)')
- })
-
- test('v-bind="obj" after static prop', () => {
- const { code, ir } = compileWithElementTransform(
- `<div id="foo" v-bind="obj" />`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'obj',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- element: 0,
- props: [
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'obj',
- isStatic: false,
- },
- },
- ],
- },
- ],
- },
- ])
- expect(code).contains(
- '_setDynamicProps(n0, [{ id: "foo" }, _ctx.obj], true)',
- )
- })
-
- test('v-bind="obj" before static prop', () => {
- const { code, ir } = compileWithElementTransform(
- `<div v-bind="obj" id="foo" />`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [{ content: 'obj' }],
- operations: [
- {
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- element: 0,
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- ],
- },
- ],
- },
- ])
- expect(code).contains(
- '_setDynamicProps(n0, [_ctx.obj, { id: "foo" }], true)',
- )
- })
-
- test('v-bind="obj" between static props', () => {
- const { code, ir } = compileWithElementTransform(
- `<div id="foo" v-bind="obj" class="bar" />`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [{ content: 'obj' }],
- operations: [
- {
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- element: 0,
- props: [
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- [{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
- ],
- },
- ],
- },
- ])
- expect(code).contains(
- '_setDynamicProps(n0, [{ id: "foo" }, _ctx.obj, { class: "bar" }], true)',
- )
- })
-
- test('props merging: event handlers', () => {
- const { code, ir } = compileWithElementTransform(
- `<div @click.foo="a" @click.bar="b" />`,
- )
- expect(code).toMatchSnapshot()
-
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- element: 0,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'click',
- isStatic: true,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'a',
- isStatic: false,
- },
- keyOverride: undefined,
- delegate: true,
- effect: false,
- },
- {
- type: IRNodeTypes.SET_EVENT,
- element: 0,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'click',
- isStatic: true,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'b',
- isStatic: false,
- },
- keyOverride: undefined,
- delegate: true,
- effect: false,
- },
- ])
- })
-
- test('props merging: style', () => {
- const { code, ir } = compileWithElementTransform(
- `<div style="color: green" :style="{ color: 'red' }" />`,
- )
- expect(code).toMatchSnapshot()
-
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_PROP,
- element: 0,
- prop: {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'style',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'color: green',
- isStatic: true,
- },
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: `{ color: 'red' }`,
- isStatic: false,
- },
- ],
- },
- },
- ])
- })
-
- test('props merging: class', () => {
- const { code, ir } = compileWithElementTransform(
- `<div class="foo" :class="{ bar: isBar }" />`,
- )
-
- expect(code).toMatchSnapshot()
-
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: `{ bar: isBar }`,
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_PROP,
- element: 0,
- prop: {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'class',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: `foo`,
- isStatic: true,
- },
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: `{ bar: isBar }`,
- isStatic: false,
- },
- ],
- },
- },
- ],
- },
- ])
- })
-
- test('v-on="obj"', () => {
- const { code, ir } = compileWithElementTransform(`<div v-on="obj" />`)
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'obj',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_DYNAMIC_EVENTS,
- element: 0,
- event: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'obj',
- isStatic: false,
- },
- },
- ],
- },
- ])
- expect(code).contains('_setDynamicEvents(n0, _ctx.obj)')
- })
-
- test('component with dynamic prop arguments', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo :[foo-bar]="bar" :[baz]="qux" />`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'foo-bar' },
- values: [{ content: 'bar' }],
- },
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'baz' },
- values: [{ content: 'qux' }],
- },
- ],
- })
- })
-
- test('component with dynamic event arguments', () => {
- const { code, ir } = compileWithElementTransform(
- `<Foo @[foo-bar]="bar" @[baz]="qux" />`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'foo-bar' },
- values: [{ content: 'bar' }],
- handler: true,
- },
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'baz' },
- values: [{ content: 'qux' }],
- handler: true,
- },
- ],
- })
- })
-
- test('component event with once modifier', () => {
- const { code } = compileWithElementTransform(`<Foo @foo.once="bar" />`)
- expect(code).toMatchSnapshot()
- })
-
- test('component dynamic event with once modifier', () => {
- const { code } = compileWithElementTransform(`<Foo @[foo].once="bar" />`)
- expect(code).toMatchSnapshot()
- })
-
- test('invalid html nesting', () => {
- const { code, ir } = compileWithElementTransform(
- `<p><div>123</div></p>
- <form><form/></form>`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.template).toEqual(['<div>123</div>', '<p></p>', '<form></form>'])
- expect(ir.block.dynamic).toMatchObject({
- children: [
- { id: 1, template: 1, children: [{ id: 0, template: 0 }] },
- { id: 3, template: 2, children: [{ id: 2, template: 2 }] },
- ],
- })
-
- expect(ir.block.operation).toMatchObject([
- { type: IRNodeTypes.INSERT_NODE, parent: 1, elements: [0] },
- { type: IRNodeTypes.INSERT_NODE, parent: 3, elements: [2] },
- ])
- })
-
- test('empty template', () => {
- const { code } = compileWithElementTransform('')
- expect(code).toMatchSnapshot()
- expect(code).contain('return null')
- })
-})
+++ /dev/null
-import { ErrorCodes, NodeTypes } from '@vue/compiler-dom'
-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, helpers } = compileWithSlotsOutlet(`<slot />`)
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('createSlot')
- expect(ir.block.effect).toEqual([])
- expect(ir.block.dynamic.children[0].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.dynamic.children[0].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.dynamic.children[0].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.dynamic.children[0].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.dynamic.children[0].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.dynamic.children[0].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.dynamic.children[0].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.dynamic.children[0].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]).toBe('<div></div>')
- expect(ir.block.dynamic.children[0].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]).toBe('<div></div>')
- expect(ir.block.dynamic.children[0].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]).toBe('<div></div>')
- expect(ir.block.dynamic.children[0].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.dynamic.children[0].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,
- },
- },
- })
- })
-})
+++ /dev/null
-import { BindingTypes } from '@vue/compiler-dom'
-import {
- DynamicFlag,
- type ForIRNode,
- IRNodeTypes,
- type IfIRNode,
- transformChildren,
- transformElement,
- transformTemplateRef,
- transformVFor,
- transformVIf,
-} from '../../src'
-import { makeCompile } from './_utils'
-
-const compileWithTransformRef = makeCompile({
- nodeTransforms: [
- transformVIf,
- transformVFor,
- transformTemplateRef,
- transformElement,
- transformChildren,
- ],
-})
-
-describe('compiler: template ref transform', () => {
- test('static ref', () => {
- const { ir, code } = compileWithTransformRef(`<div ref="foo" />`)
-
- expect(ir.block.dynamic.children[0]).toMatchObject({
- id: 0,
- flags: DynamicFlag.REFERENCED,
- })
- expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.operation).lengthOf(1)
- expect(ir.block.operation[0]).toMatchObject({
- type: IRNodeTypes.SET_TEMPLATE_REF,
- element: 0,
- value: {
- content: 'foo',
- isStatic: true,
- loc: {
- start: { line: 1, column: 10, offset: 9 },
- end: { line: 1, column: 15, offset: 14 },
- },
- },
- })
- expect(code).matchSnapshot()
- expect(code).contains('const _setTemplateRef = _createTemplateRefSetter()')
- expect(code).contains('_setTemplateRef(n0, "foo")')
- })
-
- test('static ref (inline mode)', () => {
- const { code } = compileWithTransformRef(`<div ref="foo" />`, {
- inline: true,
- bindingMetadata: { foo: BindingTypes.SETUP_REF },
- })
- expect(code).matchSnapshot()
- // pass the actual ref
- expect(code).contains('_setTemplateRef(n0, foo)')
- })
-
- test('dynamic ref', () => {
- const { ir, code } = compileWithTransformRef(`<div :ref="foo" />`)
-
- expect(ir.block.dynamic.children[0]).toMatchObject({
- id: 0,
- flags: DynamicFlag.REFERENCED,
- })
- expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.DECLARE_OLD_REF,
- id: 0,
- },
- ])
- expect(ir.block.effect).toMatchObject([
- {
- operations: [
- {
- type: IRNodeTypes.SET_TEMPLATE_REF,
- element: 0,
- value: {
- content: 'foo',
- isStatic: false,
- },
- },
- ],
- },
- ])
- expect(code).matchSnapshot()
- expect(code).contains('const _setTemplateRef = _createTemplateRefSetter()')
- expect(code).contains('_setTemplateRef(n0, _ctx.foo, r0)')
- })
-
- test('function ref', () => {
- const { ir, code } = compileWithTransformRef(
- `<div :ref="bar => {
- foo.value = bar
- ;({ baz } = bar)
- console.log(foo.value, baz)
- }" />`,
- )
- expect(ir.block.dynamic.children[0]).toMatchObject({
- id: 0,
- flags: DynamicFlag.REFERENCED,
- })
- expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.DECLARE_OLD_REF,
- id: 0,
- },
- ])
- expect(ir.block.effect).toMatchObject([
- {
- operations: [
- {
- type: IRNodeTypes.SET_TEMPLATE_REF,
- element: 0,
- value: {
- isStatic: false,
- },
- },
- ],
- },
- ])
- expect(code).toMatchSnapshot()
- expect(code).contains('const _setTemplateRef = _createTemplateRefSetter()')
- expect(code).contains(`_setTemplateRef(n0, bar => {
- _foo.value = bar
- ;({ baz: _ctx.baz } = bar)
- console.log(_foo.value, _ctx.baz)
- }, r0)`)
- })
-
- test('ref + v-if', () => {
- const { ir, code } = compileWithTransformRef(
- `<div ref="foo" v-if="true" />`,
- )
-
- const op = ir.block.dynamic.children[0].operation as IfIRNode
- expect(op.type).toBe(IRNodeTypes.IF)
-
- const { positive } = op
- expect(positive.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_TEMPLATE_REF,
- element: 2,
- value: {
- content: 'foo',
- isStatic: true,
- },
- effect: false,
- },
- ])
- expect(code).matchSnapshot()
- expect(code).contains('const _setTemplateRef = _createTemplateRefSetter()')
- expect(code).contains('_setTemplateRef(n2, "foo")')
- })
-
- test('ref + v-for', () => {
- const { ir, code } = compileWithTransformRef(
- `<div ref="foo" v-for="item in [1,2,3]" />`,
- )
-
- const { render } = ir.block.dynamic.children[0].operation as ForIRNode
- expect(render.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_TEMPLATE_REF,
- element: 2,
- value: {
- content: 'foo',
- isStatic: true,
- },
- refFor: true,
- effect: false,
- },
- ])
- expect(code).matchSnapshot()
- expect(code).contains('const _setTemplateRef = _createTemplateRefSetter()')
- expect(code).contains('_setTemplateRef(n2, "foo", void 0, true)')
- })
-})
+++ /dev/null
-// TODO: add tests for this transform
-import { NodeTypes } from '@vue/compiler-dom'
-import {
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformText,
- transformVBind,
- transformVOn,
-} from '../../src'
-
-import { makeCompile } from './_utils'
-
-const compileWithTextTransform = makeCompile({
- nodeTransforms: [transformElement, transformChildren, transformText],
- directiveTransforms: {
- bind: transformVBind,
- on: transformVOn,
- },
-})
-
-describe('compiler: text transform', () => {
- it('no consecutive text', () => {
- const { code, ir, helpers } = compileWithTextTransform(
- '{{ "hello world" }}',
- )
- expect(code).toMatchSnapshot()
- expect(helpers).contains.all.keys('setText', 'template')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_TEXT,
- element: 0,
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '"hello world"',
- isStatic: false,
- },
- ],
- },
- ])
- })
-
- it('consecutive text', () => {
- const { code, ir, helpers } = compileWithTextTransform('{{ msg }}')
- expect(code).toMatchSnapshot()
- expect(helpers).contains.all.keys('setText', 'template')
- expect(ir.block.operation).toMatchObject([])
- expect(ir.block.effect.length).toBe(1)
- })
-})
+++ /dev/null
-import { BindingTypes, ErrorCodes, NodeTypes } from '@vue/compiler-dom'
-import {
- DynamicFlag,
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformVBind,
-} from '../../src'
-import { makeCompile } from './_utils'
-
-const compileWithVBind = makeCompile({
- nodeTransforms: [transformElement, transformChildren],
- directiveTransforms: {
- bind: transformVBind,
- },
-})
-
-describe('compiler v-bind', () => {
- test('basic', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:id="id"/>`)
-
- expect(ir.block.dynamic.children[0]).toMatchObject({
- id: 0,
- flags: DynamicFlag.REFERENCED,
- })
- expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.effect).lengthOf(1)
- expect(ir.block.effect[0].expressions).lengthOf(1)
- expect(ir.block.effect[0].operations).lengthOf(1)
- expect(ir.block.effect[0]).toMatchObject({
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_PROP,
- element: 0,
- prop: {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: true,
- loc: {
- start: { line: 1, column: 13, offset: 12 },
- end: { line: 1, column: 15, offset: 14 },
- source: 'id',
- },
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: false,
- loc: {
- source: 'id',
- start: { line: 1, column: 17, offset: 16 },
- end: { line: 1, column: 19, offset: 18 },
- },
- },
- ],
- loc: {
- start: { column: 6, line: 1, offset: 5 },
- end: { column: 20, line: 1, offset: 19 },
- source: 'v-bind:id="id"',
- },
- runtimeCamelize: false,
- },
- },
- ],
- })
-
- expect(code).matchSnapshot()
- expect(code).contains('_setProp(n0, "id", _ctx.id')
- })
-
- test('no expression', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:id />`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_PROP,
- prop: {
- key: {
- content: `id`,
- isStatic: true,
- loc: {
- start: { line: 1, column: 13, offset: 12 },
- end: { line: 1, column: 15, offset: 14 },
- },
- },
- values: [
- {
- content: `id`,
- isStatic: false,
- loc: {
- start: { line: 1, column: 13, offset: 12 },
- end: { line: 1, column: 15, offset: 14 },
- },
- },
- ],
- },
- })
- expect(code).contains('_setProp(n0, "id", _ctx.id)')
- })
-
- test('no expression (shorthand)', () => {
- const { ir, code } = compileWithVBind(`<div :camel-case />`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_PROP,
- prop: {
- key: {
- content: `camel-case`,
- isStatic: true,
- },
- values: [
- {
- content: `camelCase`,
- isStatic: false,
- },
- ],
- },
- })
- expect(code).contains('_setAttr(n0, "camel-case", _ctx.camelCase)')
- })
-
- test('dynamic arg', () => {
- const { ir, code } = compileWithVBind(
- `<div v-bind:[id]="id" v-bind:[title]="title" />`,
- )
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- element: 0,
- props: [
- [
- {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: false,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: false,
- },
- ],
- },
- {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'title',
- isStatic: false,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'title',
- isStatic: false,
- },
- ],
- },
- ],
- ],
- })
- expect(code).contains(
- '_setDynamicProps(n0, [{ [_id]: _id, [_title]: _title }], true)',
- )
- })
-
- test('dynamic arg w/ static attribute', () => {
- const { ir, code } = compileWithVBind(
- `<div v-bind:[id]="id" foo="bar" checked />`,
- )
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- element: 0,
- props: [
- [
- {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: false,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: false,
- },
- ],
- },
- {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'bar',
- isStatic: true,
- },
- ],
- },
- {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'checked',
- isStatic: true,
- },
- },
- ],
- ],
- })
- expect(code).contains(
- '_setDynamicProps(n0, [{ [_id]: _id, foo: "bar", checked: "" }], true)',
- )
- })
-
- test('should error if empty expression', () => {
- const onError = vi.fn()
- const { ir, code } = compileWithVBind(`<div v-bind:arg="" />`, {
- onError,
- })
-
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
- loc: {
- start: { line: 1, column: 6 },
- end: { line: 1, column: 19 },
- },
- })
- expect(ir.template).toEqual(['<div arg></div>'])
-
- expect(code).matchSnapshot()
- expect(code).contains(JSON.stringify('<div arg></div>'))
- })
-
- test('error on invalid argument for same-name shorthand', () => {
- const onError = vi.fn()
- compileWithVBind(`<div v-bind:[arg] />`, { onError })
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
- loc: {
- start: {
- line: 1,
- column: 13,
- },
- end: {
- line: 1,
- column: 18,
- },
- },
- })
- })
-
- test('.camel modifier', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
-
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `fooBar`,
- isStatic: true,
- },
- values: [
- {
- content: `id`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: undefined,
- },
- })
-
- expect(code).matchSnapshot()
- expect(code).contains('_setProp(n0, "fooBar", _ctx.id)')
- })
-
- test('.camel modifier w/ no expression', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.camel />`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `fooBar`,
- isStatic: true,
- },
- values: [
- {
- content: `fooBar`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: undefined,
- },
- })
- expect(code).contains('renderEffect')
- expect(code).contains('_setProp(n0, "fooBar", _ctx.fooBar)')
- })
-
- test('.camel modifier w/ dynamic arg', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:[foo].camel="id"/>`)
-
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- props: [
- [
- {
- key: {
- content: `foo`,
- isStatic: false,
- },
- values: [
- {
- content: `id`,
- isStatic: false,
- },
- ],
- runtimeCamelize: true,
- modifier: undefined,
- },
- ],
- ],
- })
-
- expect(code).matchSnapshot()
- expect(code).contains('renderEffect')
- expect(code).contains(
- `_setDynamicProps(n0, [{ [_camelize(_ctx.foo)]: _ctx.id }], true)`,
- )
- })
-
- test.todo('.camel modifier w/ dynamic arg + prefixIdentifiers')
-
- test('.prop modifier', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:fooBar.prop="id"/>`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `fooBar`,
- isStatic: true,
- },
- values: [
- {
- content: `id`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: '.',
- },
- })
- expect(code).contains('renderEffect')
- expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.id)')
- })
-
- test('.prop modifier w/ no expression', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:fooBar.prop />`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `fooBar`,
- isStatic: true,
- },
- values: [
- {
- content: `fooBar`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: '.',
- },
- })
- expect(code).contains('renderEffect')
- expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.fooBar)')
- })
-
- test('.prop modifier w/ dynamic arg', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:[fooBar].prop="id"/>`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- props: [
- [
- {
- key: {
- content: `fooBar`,
- isStatic: false,
- },
- values: [
- {
- content: `id`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: '.',
- },
- ],
- ],
- })
- expect(code).contains('renderEffect')
- expect(code).contains(
- `_setDynamicProps(n0, [{ ["." + _ctx.fooBar]: _ctx.id }], true)`,
- )
- })
-
- test.todo('.prop modifier w/ dynamic arg + prefixIdentifiers')
-
- test('.prop modifier (shorthand)', () => {
- const { ir, code } = compileWithVBind(`<div .fooBar="id"/>`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `fooBar`,
- isStatic: true,
- },
- values: [
- {
- content: `id`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: '.',
- },
- })
- expect(code).contains('renderEffect')
- expect(code).contains(' _setDOMProp(n0, "fooBar", _ctx.id)')
- })
-
- test('.prop modifier (shorthand) w/ no expression', () => {
- const { ir, code } = compileWithVBind(`<div .fooBar />`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `fooBar`,
- isStatic: true,
- },
- values: [
- {
- content: `fooBar`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: '.',
- },
- })
- expect(code).contains('renderEffect')
- expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.fooBar)')
- })
-
- test('.prop modifier w/ innerHTML', () => {
- const { code } = compileWithVBind(`<div :innerHTML.prop="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setHtml(n0, _ctx.foo)')
- })
-
- test('.prop modifier (shorthand) w/ innerHTML', () => {
- const { code } = compileWithVBind(`<div .innerHTML="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setHtml(n0, _ctx.foo)')
- })
-
- test('.prop modifier w/ textContent', () => {
- const { code } = compileWithVBind(`<div :textContent.prop="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setText(n0, _ctx.foo)')
- })
-
- test('.prop modifier (shorthand) w/ textContent', () => {
- const { code } = compileWithVBind(`<div .textContent="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setText(n0, _ctx.foo)')
- })
-
- test('.prop modifier w/ value', () => {
- const { code } = compileWithVBind(`<div :value.prop="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setValue(n0, _ctx.foo)')
- })
-
- test('.prop modifier (shorthand) w/ value', () => {
- const { code } = compileWithVBind(`<div .value="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setValue(n0, _ctx.foo)')
- })
-
- test('.prop modifier w/ progress value', () => {
- const { code } = compileWithVBind(`<progress :value.prop="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setDOMProp(n0, "value", _ctx.foo)')
- })
-
- test('.prop modifier (shorthand) w/ progress value', () => {
- const { code } = compileWithVBind(`<progress .value="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setDOMProp(n0, "value", _ctx.foo)')
- })
-
- test('.attr modifier', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.attr="id"/>`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `foo-bar`,
- isStatic: true,
- },
- values: [
- {
- content: `id`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: '^',
- },
- })
- expect(code).contains('renderEffect')
- expect(code).contains('_setAttr(n0, "foo-bar", _ctx.id)')
- })
-
- test('.attr modifier w/ no expression', () => {
- const { ir, code } = compileWithVBind(`<div v-bind:foo-bar.attr />`)
-
- expect(code).matchSnapshot()
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- prop: {
- key: {
- content: `foo-bar`,
- isStatic: true,
- },
- values: [
- {
- content: `fooBar`,
- isStatic: false,
- },
- ],
- runtimeCamelize: false,
- modifier: '^',
- },
- })
-
- expect(code).contains('renderEffect')
- expect(code).contains('_setAttr(n0, "foo-bar", _ctx.fooBar)')
- })
-
- test('.attr modifier w/ innerHTML', () => {
- const { code } = compileWithVBind(`<div :innerHTML.attr="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setAttr(n0, "innerHTML", _ctx.foo)')
- })
-
- test('.attr modifier w/ textContent', () => {
- const { code } = compileWithVBind(`<div :textContent.attr="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setAttr(n0, "textContent", _ctx.foo)')
- })
-
- test('.attr modifier w/ value', () => {
- const { code } = compileWithVBind(`<div :value.attr="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setAttr(n0, "value", _ctx.foo)')
- })
-
- test('.attr modifier w/ progress value', () => {
- const { code } = compileWithVBind(`<progress :value.attr="foo" />`)
- expect(code).matchSnapshot()
- expect(code).contains('_setAttr(n0, "value", _ctx.foo)')
- })
-
- test('attributes must be set as attribute', () => {
- const { code } = compileWithVBind(`
- <div :spellcheck :draggable :translate :form />
- <input :list="list" />
- <textarea :type="type" />
- <img :width="width" :height="height"/>
- <video :width="width" :height="height"/>
- <canvas :width="width" :height="height"/>
- <source :width="width" :height="height"/>
- `)
-
- expect(code).matchSnapshot()
- expect(code).contains('_setAttr(n0, "spellcheck", _ctx.spellcheck)')
- expect(code).contains('_setAttr(n0, "draggable", _ctx.draggable)')
- expect(code).contains('_setAttr(n0, "translate", _ctx.translate)')
- expect(code).contains('_setAttr(n0, "form", _ctx.form)')
- expect(code).contains('_setAttr(n1, "list", _ctx.list)')
- expect(code).contains('_setAttr(n2, "type", _ctx.type)')
- expect(code).contains('_setAttr(n3, "width", _width)')
- expect(code).contains('_setAttr(n3, "height", _height)')
- expect(code).contains('_setAttr(n4, "width", _width)')
- expect(code).contains('_setAttr(n4, "height", _height)')
- expect(code).contains('_setAttr(n5, "width", _width)')
- expect(code).contains('_setAttr(n5, "height", _height)')
- expect(code).contains(' _setAttr(n6, "width", _width)')
- })
-
- test(':innerHTML', () => {
- const { code } = compileWithVBind(`
- <div :innerHTML="foo"/>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('_setHtml(n0, _ctx.foo)')
- })
-
- test(':textContext', () => {
- const { code } = compileWithVBind(`
- <div :textContent="foo"/>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('_setText(n0, _ctx.foo)')
- })
-
- test(':value', () => {
- const { code } = compileWithVBind(`
- <input :value="foo"/>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('_setValue(n0, _ctx.foo)')
- })
-
- test(':value w/ progress', () => {
- const { code } = compileWithVBind(`
- <progress :value="foo"/>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('_setProp(n0, "value", _ctx.foo)')
- })
-
- test('number value', () => {
- const { code } = compileWithVBind(`<Comp :depth="0" />`)
- expect(code).matchSnapshot()
- expect(code).contains('{ depth: () => (0) }')
- })
-
- test('with constant value', () => {
- const { code } = compileWithVBind(
- `
- <div
- :a="void 0"
- :b="1 > 2"
- :c="1 + 2"
- :d="1 ? 2 : 3"
- :e="(2)"
- :f="\`foo${1}\`"
- :g="1"
- :h="'1'"
- :i="true"
- :j="null"
- :k="x"
- :l="{ foo: 1 }"
- :m="{ [x]: 1 }"
- :n="{ ...{ foo: 1 } }"
- :o="[1, , 3]"
- :p="[1, ...[2, 3]]"
- :q="[1, 2]"
- :r="/\\s+/"
- />`,
- {
- bindingMetadata: {
- x: BindingTypes.LITERAL_CONST,
- },
- },
- )
- expect(code).matchSnapshot()
- })
-})
-
-describe('cache multiple access', () => {
- test('repeated variables', () => {
- const { code } = compileWithVBind(`
- <div :class="foo"></div>
- <div :class="foo"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _foo = _ctx.foo')
- expect(code).contains('setClass(n0, _foo)')
- expect(code).contains('setClass(n1, _foo)')
- })
-
- test('repeated expressions', () => {
- const { code } = compileWithVBind(`
- <div :id="foo + bar"></div>
- <div :id="foo + bar"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _foo_bar = _ctx.foo + _ctx.bar')
- expect(code).contains('_setProp(n0, "id", _foo_bar)')
- expect(code).contains('_setProp(n1, "id", _foo_bar)')
- })
-
- test('repeated variable in expressions', () => {
- const { code } = compileWithVBind(`
- <div :id="foo + foo + bar"></div>
- <div :id="foo"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _foo = _ctx.foo')
- expect(code).contains('_setProp(n0, "id", _foo + _foo + _ctx.bar)')
- expect(code).contains('_setProp(n1, "id", _foo)')
- })
-
- test('repeated expression in expressions', () => {
- const { code } = compileWithVBind(`
- <div :id="foo + bar"></div>
- <div :id="foo + bar"></div>
- <div :id="foo + foo + bar"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _foo_bar = _foo + _ctx.bar')
- expect(code).contains('_setProp(n0, "id", _foo_bar)')
- expect(code).contains('_setProp(n2, "id", _foo + _foo_bar)')
- })
-
- test('function calls with arguments', () => {
- const { code } = compileWithVBind(`
- <div :id="foo[bar(baz)]"></div>
- <div :id="foo[bar(baz)]"></div>
- <div :id="bar() + foo"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _foo_bar_baz = _foo[_bar(_ctx.baz)]')
- expect(code).contains('_setProp(n0, "id", _foo_bar_baz)')
- expect(code).contains('_setProp(n1, "id", _foo_bar_baz)')
- expect(code).contains('_setProp(n2, "id", _bar() + _foo)')
- })
-
- test('dynamic key bindings with expressions', () => {
- const { code } = compileWithVBind(`
- <div :[key+1]="foo[key+1]()" />
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _key = _ctx.key')
- expect(code).contains('[{ [_key+1]: _ctx.foo[_key+1]() }]')
- })
-
- test('object property chain access', () => {
- const { code } = compileWithVBind(`
- <div :id="obj['foo']['baz'] + obj.bar"></div>
- <div :id="obj['foo']['baz'] + obj.bar"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).contains(
- "const _obj_foo_baz_obj_bar = _obj['foo']['baz'] + _obj.bar",
- )
- expect(code).contains('_setProp(n0, "id", _obj_foo_baz_obj_bar)')
- expect(code).contains('_setProp(n1, "id", _obj_foo_baz_obj_bar)')
- })
-
- test('dynamic property access', () => {
- const { code } = compileWithVBind(`
- <div :id="obj[1][baz] + obj.bar"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _obj = _ctx.obj')
- expect(code).contains('_setProp(n0, "id", _obj[1][_ctx.baz] + _obj.bar)')
- })
-
- test('variable name substring edge cases', () => {
- const { code } = compileWithVBind(
- `<div :id="title + titles + title"></div>`,
- )
- expect(code).matchSnapshot()
- expect(code).contains('const _title = _ctx.title')
- expect(code).contains('_setProp(n0, "id", _title + _ctx.titles + _title)')
- })
-
- test('object property name substring cases', () => {
- const { code } = compileWithVBind(
- `<div :id="p.title + p.titles + p.title"></div>`,
- )
- expect(code).matchSnapshot()
- expect(code).contains('const _p = _ctx.p')
- expect(code).contains('const _p_title = _p.title')
- expect(code).contains('_setProp(n0, "id", _p_title + _p.titles + _p_title)')
- })
-
- test('cache variable used in both property shorthand and normal binding', () => {
- const { code } = compileWithVBind(`
- <div :style="{color}" :id="color"/>
- `)
- expect(code).matchSnapshot()
- expect(code).contains('const _color = _ctx.color')
- expect(code).contains('_setStyle(n0, {color: _color})')
- })
-
- test('optional chaining', () => {
- const { code } = compileWithVBind(`<div :id="obj?.foo + obj?.bar"></div>`)
- expect(code).matchSnapshot()
- expect(code).contains('const _obj = _ctx.obj')
- expect(code).contains('_setProp(n0, "id", _obj?.foo + _obj?.bar)')
- })
-
- test('not cache variable only used in property shorthand', () => {
- const { code } = compileWithVBind(`
- <div :style="{color}" />
- `)
- expect(code).matchSnapshot()
- expect(code).not.contains('const _color = _ctx.color')
- })
-
- test('not cache variable and member expression with the same name', () => {
- const { code } = compileWithVBind(`
- <div :id="bar + obj.bar"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).not.contains('const _bar = _ctx.bar')
- })
-
- test('not cache variable in function expression', () => {
- const { code } = compileWithVBind(`
- <div v-bind="{ foo: bar => foo = bar }"></div>
- `)
- expect(code).matchSnapshot()
- expect(code).not.contains('const _bar = _ctx.bar')
- })
-})
+++ /dev/null
-import { makeCompile } from './_utils'
-import {
- type ForIRNode,
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformText,
- transformVBind,
- transformVFor,
- transformVOn,
-} from '../../src'
-import { NodeTypes } from '@vue/compiler-dom'
-
-const compileWithVFor = makeCompile({
- nodeTransforms: [
- transformVFor,
- transformText,
- transformElement,
- transformChildren,
- ],
- directiveTransforms: {
- bind: transformVBind,
- on: transformVOn,
- },
-})
-
-describe('compiler: v-for', () => {
- test('basic v-for', () => {
- const { code, ir, helpers } = compileWithVFor(
- `<div v-for="item of items" :key="item.id" @click="remove(item)">{{ item }}</div>`,
- )
-
- expect(code).matchSnapshot()
- expect(helpers).contains('createFor')
- expect(ir.template).toEqual(['<div> </div>'])
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- id: 0,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'items',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'item',
- },
- key: undefined,
- index: undefined,
- render: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- keyProp: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'item.id',
- },
- })
- expect(ir.block.returns).toEqual([0])
- expect(ir.block.dynamic).toMatchObject({
- children: [{ id: 0 }],
- })
- expect(ir.block.effect).toEqual([])
- expect(
- (ir.block.dynamic.children[0].operation as ForIRNode).render.effect,
- ).lengthOf(1)
- })
-
- test('multi effect', () => {
- const { code } = compileWithVFor(
- `<div v-for="(item, index) of items" :item="item" :index="index" />`,
- )
- expect(code).matchSnapshot()
- })
-
- test('w/o value', () => {
- const { code } = compileWithVFor(`<div v-for=" of items">item</div>`)
- expect(code).matchSnapshot()
- })
-
- test('nested v-for', () => {
- const { code, ir } = compileWithVFor(
- `<div v-for="i in list"><span v-for="j in i">{{ j+i }}</span></div>`,
- )
- expect(code).matchSnapshot()
- expect(code).contains(`_createFor(() => (_ctx.list), (_for_item0) => {`)
- expect(code).contains(
- `_createFor(() => (_for_item0.value), (_for_item1) => {`,
- )
- expect(code).contains(`_for_item1.value+_for_item0.value`)
- expect(ir.template).toEqual(['<span> </span>', '<div></div>'])
- const parentOp = ir.block.dynamic.children[0].operation
- expect(parentOp).toMatchObject({
- type: IRNodeTypes.FOR,
- id: 0,
- source: { content: 'list' },
- value: { content: 'i' },
- render: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
- },
- })
- expect(
- (parentOp as any).render.dynamic.children[0].children[0].operation,
- ).toMatchObject({
- type: IRNodeTypes.FOR,
- id: 2,
- source: { content: 'i' },
- value: { content: 'j' },
- render: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- })
- })
-
- test('object value, key and index', () => {
- const { code, ir } = compileWithVFor(
- `<div v-for="(value, key, index) in list" :key="key">{{ value + key + index }}</div>`,
- )
- expect(code).matchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'list',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'value',
- },
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'key',
- },
- index: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'index',
- },
- })
- })
-
- test('object de-structured value', () => {
- const { code, ir } = compileWithVFor(
- '<span v-for="({ id, value }) in items" :key="id">{{ id }}{{ value }}</span>',
- )
- expect(code).matchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'items',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ id, value }',
- ast: {
- type: 'ArrowFunctionExpression',
- params: [
- {
- type: 'ObjectPattern',
- },
- ],
- },
- },
- key: undefined,
- index: undefined,
- })
- })
-
- test('object de-structured value (with rest)', () => {
- const { code, ir } = compileWithVFor(
- `<div v-for="( { id, ...other }, index) in list" :key="id">{{ id + other + index }}</div>`,
- )
- expect(code).matchSnapshot()
- expect(code).toContain('_getRestElement(_for_item0.value, ["id"])')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'list',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ id, ...other }',
- ast: {
- type: 'ArrowFunctionExpression',
- params: [
- {
- type: 'ObjectPattern',
- },
- ],
- },
- },
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'index',
- },
- index: undefined,
- })
- })
-
- test('array de-structured value', () => {
- const { code, ir } = compileWithVFor(
- `<div v-for="([id, other], index) in list" :key="id">{{ id + other + index }}</div>`,
- )
- expect(code).matchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'list',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '[id, other]',
- ast: {
- type: 'ArrowFunctionExpression',
- params: [
- {
- type: 'ArrayPattern',
- },
- ],
- },
- },
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'index',
- },
- index: undefined,
- })
- })
-
- test('array de-structured value (with rest)', () => {
- const { code, ir } = compileWithVFor(
- `<div v-for="([id, ...other], index) in list" :key="id">{{ id + other + index }}</div>`,
- )
- expect(code).matchSnapshot()
- expect(code).toContain('_for_item0.value.slice(1)')
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'list',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '[id, ...other]',
- ast: {
- type: 'ArrowFunctionExpression',
- params: [
- {
- type: 'ArrayPattern',
- },
- ],
- },
- },
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'index',
- },
- index: undefined,
- })
- })
-
- test('v-for aliases w/ complex expressions', () => {
- const { code, ir } = compileWithVFor(
- `<div v-for="({ foo = bar, baz: [qux = quux] }) in list">
- {{ foo + bar + baz + qux + quux }}
- </div>`,
- )
- expect(code).matchSnapshot()
- expect(code).toContain(`_getDefaultValue(_for_item0.value.foo, _ctx.bar)`)
- expect(code).toContain(
- `_getDefaultValue(_for_item0.value.baz[0], _ctx.quux)`,
- )
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'list',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo = bar, baz: [qux = quux] }',
- ast: {
- type: 'ArrowFunctionExpression',
- params: [
- {
- type: 'ObjectPattern',
- },
- ],
- },
- },
- key: undefined,
- index: undefined,
- })
- })
-})
+++ /dev/null
-import { BindingTypes, DOMErrorCodes, NodeTypes } from '@vue/compiler-dom'
-import {
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformVHtml,
-} from '../../src'
-import { makeCompile } from './_utils'
-
-const compileWithVHtml = makeCompile({
- nodeTransforms: [transformElement, transformChildren],
- directiveTransforms: {
- html: transformVHtml,
- },
-})
-
-describe('v-html', () => {
- test('should convert v-html to innerHTML', () => {
- const { code, ir, helpers } = compileWithVHtml(
- `<div v-html="code"></div>`,
- {
- bindingMetadata: {
- code: BindingTypes.SETUP_REF,
- },
- },
- )
-
- expect(helpers).contains('setHtml')
-
- expect(ir.block.operation).toMatchObject([])
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'code',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_HTML,
- element: 0,
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'code',
- isStatic: false,
- },
- },
- ],
- },
- ])
-
- expect(code).matchSnapshot()
- })
-
- test('should raise error and ignore children when v-html is present', () => {
- const onError = vi.fn()
- const { code, ir, helpers } = compileWithVHtml(
- `<div v-html="test">hello</div>`,
- {
- onError,
- },
- )
-
- expect(helpers).contains('setHtml')
-
- // children should have been removed
- expect(ir.template).toEqual(['<div></div>'])
-
- expect(ir.block.operation).toMatchObject([])
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_HTML,
- element: 0,
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- },
- ],
- },
- ])
-
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_V_HTML_WITH_CHILDREN }],
- ])
-
- expect(code).matchSnapshot()
- // children should have been removed
- expect(code).contains('template("<div></div>", true)')
- })
-
- test('should raise error if has no expression', () => {
- const onError = vi.fn()
- const { code } = compileWithVHtml(`<div v-html></div>`, {
- onError,
- })
- expect(code).matchSnapshot()
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_V_HTML_NO_EXPRESSION }],
- ])
- })
-})
+++ /dev/null
-import { makeCompile } from './_utils'
-import {
- IRNodeTypes,
- type IfIRNode,
- transformChildren,
- transformComment,
- transformElement,
- transformText,
- transformVIf,
- transformVOnce,
- transformVText,
-} from '../../src'
-import { NodeTypes } from '@vue/compiler-dom'
-
-const compileWithVIf = makeCompile({
- nodeTransforms: [
- transformVOnce,
- transformVIf,
- transformText,
- transformElement,
- transformComment,
- transformChildren,
- ],
- directiveTransforms: {
- text: transformVText,
- },
-})
-
-describe('compiler: v-if', () => {
- test('basic v-if', () => {
- const { code, helpers, ir } = compileWithVIf(`<div v-if="ok">{{msg}}</div>`)
-
- expect(helpers).contains('createIf')
-
- expect(ir.template).toEqual(['<div> </div>'])
-
- const op = ir.block.dynamic.children[0].operation
- expect(op).toMatchObject({
- type: IRNodeTypes.IF,
- id: 0,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'ok',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- })
- expect(ir.block.returns).toEqual([0])
-
- expect(ir.block.dynamic).toMatchObject({
- children: [{ id: 0 }],
- })
-
- expect(ir.block.effect).toEqual([])
- expect((op as IfIRNode).positive.effect).lengthOf(1)
-
- expect(code).matchSnapshot()
- })
-
- test('template v-if', () => {
- const { code, ir } = compileWithVIf(
- `<template v-if="ok"><div/>hello<p v-text="msg"/></template>`,
- )
- expect(code).matchSnapshot()
-
- expect(ir.template).toEqual(['<div></div>', 'hello', '<p> </p>'])
- expect(ir.block.effect).toEqual([])
- const op = ir.block.dynamic.children[0].operation as IfIRNode
- expect(op.positive.effect).toMatchObject([
- {
- operations: [
- {
- type: IRNodeTypes.SET_TEXT,
- element: 4,
- values: [
- {
- content: 'msg',
- type: NodeTypes.SIMPLE_EXPRESSION,
- isStatic: false,
- },
- ],
- },
- ],
- },
- ])
- expect(op.positive.dynamic).toMatchObject({
- id: 1,
- children: {
- 2: {
- id: 4,
- },
- },
- })
- })
-
- test('dedupe same template', () => {
- const { code, ir } = compileWithVIf(
- `<div v-if="ok">hello</div><div v-if="ok">hello</div>`,
- )
- expect(code).matchSnapshot()
- expect(ir.template).toEqual(['<div>hello</div>'])
- expect(ir.block.returns).toEqual([0, 3])
- })
-
- test.todo('v-if with v-once')
- test.todo('component v-if')
-
- test('v-if + v-else', () => {
- const { code, ir, helpers } = compileWithVIf(`<div v-if="ok"/><p v-else/>`)
- expect(code).matchSnapshot()
- expect(ir.template).toEqual(['<div></div>', '<p></p>'])
-
- expect(helpers).contains('createIf')
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.IF,
- id: 0,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'ok',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- negative: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
- },
- })
- expect(ir.block.returns).toEqual([0])
- })
-
- test('v-if + v-else-if', () => {
- const { code, ir } = compileWithVIf(
- `<div v-if="ok"/><p v-else-if="orNot"/>`,
- )
- expect(code).matchSnapshot()
- expect(ir.template).toEqual(['<div></div>', '<p></p>'])
-
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.IF,
- id: 0,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'ok',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- negative: {
- type: IRNodeTypes.IF,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'orNot',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
- },
- },
- })
- expect(ir.block.returns).toEqual([0])
- })
-
- test('v-if + v-else-if + v-else', () => {
- const { code, ir } = compileWithVIf(
- `<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`,
- )
- expect(code).matchSnapshot()
- expect(ir.template).toEqual(['<div></div>', '<p></p>', 'fine'])
-
- expect(ir.block.returns).toEqual([0])
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.IF,
- id: 0,
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- negative: {
- type: IRNodeTypes.IF,
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
- },
- negative: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 2 }],
- },
- },
- },
- })
- })
-
- test('v-if + v-if / v-else[-if]', () => {
- const { code } = compileWithVIf(
- `<div>
- <span v-if="foo">foo</span>
- <span v-if="bar">bar</span>
- <span v-else>baz</span>
- </div>`,
- )
- expect(code).toMatchSnapshot()
- })
-
- test('comment between branches', () => {
- const { code, ir } = compileWithVIf(`
- <div v-if="ok"/>
- <!--foo-->
- <p v-else-if="orNot"/>
- <!--bar-->
- <template v-else>fine</template>
- <div v-text="text" />
- `)
- expect(code).matchSnapshot()
- expect(ir.template).toEqual([
- '<div></div>',
- '<!--foo-->',
- '<p></p>',
- '<!--bar-->',
- 'fine',
-
- '<div> </div>',
- ])
- })
-
- describe.todo('errors')
- describe.todo('codegen')
- test.todo('v-on with v-if')
-})
+++ /dev/null
-import { makeCompile } from './_utils'
-import {
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformVModel,
-} from '../../src'
-import { BindingTypes, DOMErrorCodes } from '@vue/compiler-dom'
-
-const compileWithVModel = makeCompile({
- nodeTransforms: [transformElement, transformChildren],
- directiveTransforms: {
- model: transformVModel,
- },
-})
-
-describe('compiler: vModel transform', () => {
- test('should support simple expression', () => {
- const { code, helpers } = compileWithVModel('<input v-model="model" />')
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('applyTextModel')
- })
-
- test('should support input (text)', () => {
- const { code, helpers } = compileWithVModel(
- '<input type="text" v-model="model" />',
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('applyTextModel')
- })
-
- test('should support input (radio)', () => {
- const { code, helpers } = compileWithVModel(
- '<input type="radio" v-model="model" />',
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('applyRadioModel')
- })
-
- test('should support input (checkbox)', () => {
- const { code, helpers } = compileWithVModel(
- '<input type="checkbox" v-model="model" />',
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('applyCheckboxModel')
- })
-
- test('should support select', () => {
- const { code, helpers } = compileWithVModel('<select v-model="model" />')
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('applySelectModel')
- })
-
- test('should support textarea', () => {
- const { code, helpers } = compileWithVModel('<textarea v-model="model" />')
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('applyTextModel')
- })
-
- test('should support input (dynamic type)', () => {
- const { code, helpers } = compileWithVModel(
- '<input :type="foo" v-model="model" />',
- )
- expect(code).toMatchSnapshot()
- expect(helpers).toContain('applyDynamicModel')
- })
-
- test('should support w/ dynamic v-bind', () => {
- const root1 = compileWithVModel('<input v-bind="obj" v-model="model" />')
- expect(root1.code).toMatchSnapshot()
- expect(root1.helpers).toContain('applyDynamicModel')
-
- const root2 = compileWithVModel(
- '<input v-bind:[key]="val" v-model="model" />',
- )
- expect(root2.code).toMatchSnapshot()
- expect(root2.helpers).toContain('applyDynamicModel')
- })
-
- describe('errors', () => {
- test('invalid element', () => {
- const onError = vi.fn()
- compileWithVModel('<span v-model="model" />', { onError })
-
- expect(onError).toHaveBeenCalledTimes(1)
- expect(onError).toHaveBeenCalledWith(
- expect.objectContaining({
- code: DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
- }),
- )
- })
-
- test('plain elements with argument', () => {
- const onError = vi.fn()
- compileWithVModel('<input v-model:value="model" />', { onError })
-
- expect(onError).toHaveBeenCalledTimes(1)
- expect(onError).toHaveBeenCalledWith(
- expect.objectContaining({
- code: DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
- }),
- )
- })
-
- // TODO: component
- test.todo('should allow usage on custom element', () => {
- const onError = vi.fn()
- const root = compileWithVModel('<my-input v-model="model" />', {
- onError,
- isCustomElement: tag => tag.startsWith('my-'),
- })
- expect(root.helpers).toContain('applyTextModel')
- expect(onError).not.toHaveBeenCalled()
- })
-
- test('should raise error if used file input element', () => {
- const onError = vi.fn()
- compileWithVModel(`<input type="file" v-model="test"/>`, {
- onError,
- })
- expect(onError).toHaveBeenCalledWith(
- expect.objectContaining({
- code: DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT,
- }),
- )
- })
-
- test('should error on dynamic value binding alongside v-model', () => {
- const onError = vi.fn()
- compileWithVModel(`<input v-model="test" :value="test" />`, {
- onError,
- })
- expect(onError).toHaveBeenCalledWith(
- expect.objectContaining({
- code: DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE,
- }),
- )
- })
-
- // #3596
- test('should NOT error on static value binding alongside v-model', () => {
- const onError = vi.fn()
- compileWithVModel(`<input v-model="test" value="test" />`, {
- onError,
- })
- expect(onError).not.toHaveBeenCalled()
- })
- })
-
- describe('modifiers', () => {
- test('.number', () => {
- const { code } = compileWithVModel('<input v-model.number="model" />')
-
- expect(code).toMatchSnapshot()
- })
-
- test('.trim', () => {
- const { code } = compileWithVModel('<input v-model.trim="model" />')
-
- expect(code).toMatchSnapshot()
- })
-
- test('.lazy', () => {
- const { code } = compileWithVModel('<input v-model.lazy="model" />')
-
- expect(code).toMatchSnapshot()
- })
- })
-
- test('should support member expression', () => {
- const { code } = compileWithVModel(
- '<input v-model="setupRef.child" /><input v-model="setupLet.child" /><input v-model="setupMaybeRef.child" />',
- {
- bindingMetadata: {
- setupRef: BindingTypes.SETUP_REF,
- setupLet: BindingTypes.SETUP_LET,
- setupMaybeRef: BindingTypes.SETUP_MAYBE_REF,
- },
- },
- )
-
- expect(code).toMatchSnapshot()
- })
-
- test('should support member expression w/ inline', () => {
- const { code } = compileWithVModel(
- '<input v-model="setupRef.child" /><input v-model="setupLet.child" /><input v-model="setupMaybeRef.child" />',
- {
- bindingMetadata: {
- setupRef: BindingTypes.SETUP_REF,
- setupLet: BindingTypes.SETUP_LET,
- setupMaybeRef: BindingTypes.SETUP_MAYBE_REF,
- },
- inline: true,
- },
- )
-
- expect(code).toMatchSnapshot()
- })
-
- describe('component', () => {
- test('v-model for component should work', () => {
- const { code, ir } = compileWithVModel('<Comp v-model="foo" />')
- expect(code).toMatchSnapshot()
- expect(code).contains(`modelValue: () => (_ctx.foo),`)
- expect(code).contains(
- `"onUpdate:modelValue": () => _value => (_ctx.foo = _value)`,
- )
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'modelValue', isStatic: true },
- model: true,
- modelModifiers: [],
- values: [{ content: 'foo', isStatic: false }],
- },
- ],
- ],
- })
- })
-
- test('v-model with arguments for component should work', () => {
- const { code, ir } = compileWithVModel('<Comp v-model:bar="foo" />')
- expect(code).toMatchSnapshot()
- expect(code).contains(`bar: () => (_ctx.foo),`)
- expect(code).contains(
- `"onUpdate:bar": () => _value => (_ctx.foo = _value)`,
- )
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'bar', isStatic: true },
- model: true,
- modelModifiers: [],
- values: [{ content: 'foo', isStatic: false }],
- },
- ],
- ],
- })
- })
-
- test('v-model with dynamic arguments for component should work', () => {
- const { code, ir } = compileWithVModel('<Comp v-model:[arg]="foo" />')
- expect(code).toMatchSnapshot()
- expect(code).contains(
- `[_ctx.arg]: _ctx.foo,
- ["onUpdate:" + _ctx.arg]: () => _value => (_ctx.foo = _value)`,
- )
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- {
- key: { content: 'arg', isStatic: false },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: [],
- },
- ],
- })
- })
-
- test('v-model for component should generate modelModifiers', () => {
- const { code, ir } = compileWithVModel(
- '<Comp v-model.trim.bar-baz="foo" />',
- )
- expect(code).toMatchSnapshot()
- expect(code).contain(
- `modelModifiers: () => ({ trim: true, "bar-baz": true })`,
- )
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'modelValue', isStatic: true },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: ['trim', 'bar-baz'],
- },
- ],
- ],
- })
- })
-
- test('v-model with arguments for component should generate modelModifiers', () => {
- const { code, ir } = compileWithVModel(
- '<Comp v-model:foo.trim="foo" v-model:bar.number="bar" />',
- )
- expect(code).toMatchSnapshot()
- expect(code).contain(`fooModifiers: () => ({ trim: true })`)
- expect(code).contain(`barModifiers: () => ({ number: true })`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'foo', isStatic: true },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: ['trim'],
- },
- {
- key: { content: 'bar', isStatic: true },
- values: [{ content: 'bar', isStatic: false }],
- model: true,
- modelModifiers: ['number'],
- },
- ],
- ],
- })
- })
-
- test('v-model with dynamic arguments for component should generate modelModifiers ', () => {
- const { code, ir } = compileWithVModel(
- '<Comp v-model:[foo].trim="foo" v-model:[bar].number="bar" />',
- )
- expect(code).toMatchSnapshot()
- expect(code).contain(`[_ctx.foo + "Modifiers"]: () => ({ trim: true })`)
- expect(code).contain(`[_ctx.bar + "Modifiers"]: () => ({ number: true })`)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- {
- key: { content: 'foo', isStatic: false },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: ['trim'],
- },
- {
- key: { content: 'bar', isStatic: false },
- values: [{ content: 'bar', isStatic: false }],
- model: true,
- modelModifiers: ['number'],
- },
- ],
- })
- })
- })
-})
+++ /dev/null
-import { BindingTypes, ErrorCodes, NodeTypes } from '@vue/compiler-dom'
-import {
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformVOn,
-} from '../../src'
-import { makeCompile } from './_utils'
-
-const compileWithVOn = makeCompile({
- nodeTransforms: [transformElement, transformChildren],
- directiveTransforms: {
- on: transformVOn,
- },
-})
-
-describe('v-on', () => {
- test('simple expression', () => {
- const { code, ir, helpers } = compileWithVOn(
- `<div @click="handleClick"></div>`,
- {
- bindingMetadata: {
- handleClick: BindingTypes.SETUP_CONST,
- },
- },
- )
-
- expect(code).matchSnapshot()
- expect(helpers).not.contains('delegate') // optimized as direct attachment
- expect(ir.block.effect).toEqual([])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- element: 0,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'click',
- isStatic: true,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'handleClick',
- isStatic: false,
- },
- modifiers: { keys: [], nonKeys: [], options: [] },
- keyOverride: undefined,
- delegate: true,
- },
- ])
- })
-
- test('event modifier', () => {
- const { code } = compileWithVOn(
- `<a @click.stop="handleEvent"></a>
- <form @submit.prevent="handleEvent"></form>
- <a @click.stop.prevent="handleEvent"></a>
- <div @click.self="handleEvent"></div>
- <div @click.capture="handleEvent"></div>
- <a @click.once="handleEvent"></a>
- <div @scroll.passive="handleEvent"></div>
- <input @click.right="handleEvent" />
- <input @click.left="handleEvent" />
- <input @click.middle="handleEvent" />
- <input @click.enter.right="handleEvent" />
- <input @keyup.enter="handleEvent" />
- <input @keyup.tab="handleEvent" />
- <input @keyup.delete="handleEvent" />
- <input @keyup.esc="handleEvent" />
- <input @keyup.space="handleEvent" />
- <input @keyup.up="handleEvent" />
- <input @keyup.down="handleEvent" />
- <input @keyup.left="handleEvent" />
- <input @keyup.middle="submit" />
- <input @keyup.middle.self="submit" />
- <input @keyup.self.enter="handleEvent" />`,
- {
- bindingMetadata: {
- handleEvent: BindingTypes.SETUP_CONST,
- },
- },
- )
- expect(code).matchSnapshot()
- })
-
- test('dynamic arg', () => {
- const { code, ir, helpers } = compileWithVOn(
- `<div v-on:[event]="handler"/>`,
- )
-
- expect(helpers).contains('on')
- expect(helpers).contains('renderEffect')
- expect(ir.block.operation).toMatchObject([])
-
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_EVENT,
- element: 0,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'event',
- isStatic: false,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'handler',
- isStatic: false,
- },
- })
-
- expect(code).matchSnapshot()
- })
-
- test('dynamic arg with prefixing', () => {
- const { code } = compileWithVOn(`<div v-on:[event]="handler"/>`, {
- prefixIdentifiers: true,
- })
-
- expect(code).matchSnapshot()
- })
-
- test('dynamic arg with complex exp prefixing', () => {
- const { ir, code, helpers } = compileWithVOn(
- `<div v-on:[event(foo)]="handler"/>`,
- {
- prefixIdentifiers: true,
- },
- )
-
- expect(helpers).contains('on')
- expect(helpers).contains('renderEffect')
- expect(ir.block.operation).toMatchObject([])
-
- expect(ir.block.effect[0].operations[0]).toMatchObject({
- type: IRNodeTypes.SET_EVENT,
- element: 0,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'event(foo)',
- isStatic: false,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'handler',
- isStatic: false,
- },
- })
-
- expect(code).matchSnapshot()
- })
-
- test('should wrap as function if expression is inline statement', () => {
- const { code, ir, helpers } = compileWithVOn(`<div @click="i++"/>`)
-
- expect(code).matchSnapshot()
- expect(helpers).not.contains('delegate')
- expect(ir.block.effect).toEqual([])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- element: 0,
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'i++',
- isStatic: false,
- },
- delegate: true,
- },
- ])
- expect(code).contains(`n0.$evtclick = () => (_ctx.i++)`)
- })
-
- test('should wrap in unref if identifier is setup-maybe-ref w/ inline: true', () => {
- const { code, helpers } = compileWithVOn(
- `<div @click="x=y"/><div @click="x++"/><div @click="{ x } = y"/>`,
- {
- mode: 'module',
- inline: true,
- bindingMetadata: {
- x: BindingTypes.SETUP_MAYBE_REF,
- y: BindingTypes.SETUP_MAYBE_REF,
- },
- },
- )
- expect(code).matchSnapshot()
- expect(helpers).contains('unref')
- expect(code).contains(`n0.$evtclick = () => (x.value=_unref(y))`)
- expect(code).contains(`n1.$evtclick = () => (x.value++)`)
- expect(code).contains(`n2.$evtclick = () => ({ x: x.value } = _unref(y))`)
- })
-
- test('should handle multiple inline statement', () => {
- const { ir, code } = compileWithVOn(`<div @click="foo();bar()"/>`)
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: 'foo();bar()' },
- },
- ])
- // should wrap with `{` for multiple statements
- // in this case the return value is discarded and the behavior is
- // consistent with 2.x
- expect(code).contains(`n0.$evtclick = () => {_ctx.foo();_ctx.bar()}`)
- })
-
- test('should handle multi-line statement', () => {
- const { code, ir } = compileWithVOn(`<div @click="\nfoo();\nbar()\n"/>`)
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: '\nfoo();\nbar()\n' },
- },
- ])
- // should wrap with `{` for multiple statements
- // in this case the return value is discarded and the behavior is
- // consistent with 2.x
- expect(code).contains(`n0.$evtclick = () => {\n_ctx.foo();\n_ctx.bar()\n}`)
- })
-
- test('inline statement w/ prefixIdentifiers: true', () => {
- const { code, ir } = compileWithVOn(`<div @click="foo($event)"/>`, {
- prefixIdentifiers: true,
- })
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: 'foo($event)' },
- },
- ])
- // should NOT prefix $event
- expect(code).contains(`n0.$evtclick = $event => (_ctx.foo($event))`)
- })
-
- test('multiple inline statements w/ prefixIdentifiers: true', () => {
- const { ir, code } = compileWithVOn(`<div @click="foo($event);bar()"/>`, {
- prefixIdentifiers: true,
- })
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: 'foo($event);bar()' },
- },
- ])
- // should NOT prefix $event
- expect(code).contains(
- `n0.$evtclick = $event => {_ctx.foo($event);_ctx.bar()}`,
- )
- })
-
- test('should NOT wrap as function if expression is already function expression', () => {
- const { code, ir } = compileWithVOn(`<div @click="$event => foo($event)"/>`)
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: '$event => foo($event)' },
- },
- ])
- expect(code).contains(`n0.$evtclick = $event => _ctx.foo($event)`)
- })
-
- test('should NOT wrap as function if expression is already function expression (with Typescript)', () => {
- const { ir, code } = compileWithVOn(
- `<div @click="(e: any): any => foo(e)"/>`,
- { expressionPlugins: ['typescript'] },
- )
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: '(e: any): any => foo(e)' },
- },
- ])
- expect(code).contains(`n0.$evtclick = (e: any): any => _ctx.foo(e)`)
- })
-
- test('should NOT wrap as function if expression is already function expression (with newlines)', () => {
- const { ir, code } = compileWithVOn(
- `<div @click="
- $event => {
- foo($event)
- }
- "/>`,
- )
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: {
- content: `
- $event => {
- foo($event)
- }
- `,
- },
- },
- ])
- })
-
- test('should NOT add a prefix to $event if the expression is a function expression', () => {
- const { ir, code } = compileWithVOn(
- `<div @click="$event => {i++;foo($event)}"></div>`,
- {
- prefixIdentifiers: true,
- },
- )
-
- expect(ir.block.operation[0]).toMatchObject({
- type: IRNodeTypes.SET_EVENT,
- value: { content: '$event => {i++;foo($event)}' },
- })
-
- expect(code).matchSnapshot()
- })
-
- test('should NOT wrap as function if expression is complex member expression', () => {
- const { ir, code } = compileWithVOn(`<div @click="a['b' + c]"/>`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: `a['b' + c]` },
- },
- ])
-
- expect(code).matchSnapshot()
- })
-
- test('complex member expression w/ prefixIdentifiers: true', () => {
- const { ir, code } = compileWithVOn(`<div @click="a['b' + c]"/>`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: `a['b' + c]` },
- },
- ])
-
- expect(code).matchSnapshot()
- expect(code).contains(`n0.$evtclick = e => _ctx.a['b' + _ctx.c](e)`)
- })
-
- test('function expression w/ prefixIdentifiers: true', () => {
- const { code, ir } = compileWithVOn(`<div @click="e => foo(e)"/>`, {
- prefixIdentifiers: true,
- })
-
- expect(code).matchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: { content: `e => foo(e)` },
- },
- ])
- expect(code).contains(`n0.$evtclick = e => _ctx.foo(e)`)
- })
-
- test('should error if no expression AND no modifier', () => {
- const onError = vi.fn()
- compileWithVOn(`<div v-on:click />`, { onError })
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_ON_NO_EXPRESSION,
- loc: {
- start: {
- line: 1,
- column: 6,
- },
- end: {
- line: 1,
- column: 16,
- },
- },
- })
- })
-
- test('should NOT error if no expression but has modifier', () => {
- const onError = vi.fn()
- compileWithVOn(`<div v-on:click.prevent />`, { onError })
- expect(onError).not.toHaveBeenCalled()
- })
-
- test('should support multiple modifiers and event options w/ prefixIdentifiers: true', () => {
- const { code, ir, helpers } = compileWithVOn(
- `<div @click.stop.prevent.capture.once="test"/>`,
- {
- prefixIdentifiers: true,
- },
- )
-
- expect(code).matchSnapshot()
- expect(helpers).contains('on')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- modifiers: {
- keys: [],
- nonKeys: ['stop', 'prevent'],
- options: ['capture', 'once'],
- },
- keyOverride: undefined,
- delegate: false,
- },
- ])
- expect(code).contains(
- `_on(n0, "click", _withModifiers(e => _ctx.test(e), ["stop","prevent"]), {
- capture: true,
- once: true
- })`,
- )
- })
-
- test('should support multiple events and modifiers options w/ prefixIdentifiers: true', () => {
- const { code, ir } = compileWithVOn(
- `<div @click.stop="test" @keyup.enter="test" />`,
- {
- prefixIdentifiers: true,
- },
- )
-
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'click',
- isStatic: true,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- modifiers: {
- keys: [],
- nonKeys: ['stop'],
- options: [],
- },
- },
- {
- type: IRNodeTypes.SET_EVENT,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'keyup',
- isStatic: true,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- modifiers: {
- keys: ['enter'],
- nonKeys: [],
- options: [],
- },
- },
- ])
-
- expect(code).matchSnapshot()
- expect(code).contains(
- `n0.$evtclick = _withModifiers(e => _ctx.test(e), ["stop"])
- n0.$evtkeyup = _withKeys(e => _ctx.test(e), ["enter"])`,
- )
- })
-
- test('should wrap keys guard for keyboard events or dynamic events', () => {
- const { code, ir } = compileWithVOn(
- `<div @keydown.stop.capture.ctrl.a="test"/>`,
- {
- prefixIdentifiers: true,
- },
- )
-
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- element: 0,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'keydown',
- isStatic: true,
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- modifiers: {
- keys: ['a'],
- nonKeys: ['stop', 'ctrl'],
- options: ['capture'],
- },
- },
- ])
-
- expect(code).matchSnapshot()
- })
-
- test('should not wrap keys guard if no key modifier is present', () => {
- const { code, ir } = compileWithVOn(`<div @keyup.exact="test"/>`, {
- prefixIdentifiers: true,
- })
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- modifiers: { nonKeys: ['exact'] },
- },
- ])
-
- expect(code).matchSnapshot()
- })
-
- test('should wrap keys guard for static key event w/ left/right modifiers', () => {
- const { code, ir } = compileWithVOn(`<div @keyup.left="test"/>`, {
- prefixIdentifiers: true,
- })
-
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- modifiers: {
- keys: ['left'],
- nonKeys: [],
- options: [],
- },
- },
- ])
-
- expect(code).matchSnapshot()
- })
-
- test('should wrap both for dynamic key event w/ left/right modifiers', () => {
- const { code, ir } = compileWithVOn(`<div @[e].left="test"/>`, {
- prefixIdentifiers: true,
- })
-
- expect(ir.block.effect[0].operations).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'e',
- isStatic: false,
- },
- modifiers: {
- keys: ['left'],
- nonKeys: ['left'],
- options: [],
- },
- },
- ])
-
- expect(code).matchSnapshot()
- })
-
- test('should transform click.right', () => {
- const { code, ir } = compileWithVOn(`<div @click.right="test"/>`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'contextmenu',
- isStatic: true,
- },
- modifiers: { nonKeys: ['right'] },
- keyOverride: undefined,
- },
- ])
-
- expect(code).matchSnapshot()
- expect(code).contains('"contextmenu"')
-
- // dynamic
- const { code: code2, ir: ir2 } = compileWithVOn(
- `<div @[event].right="test"/>`,
- )
- expect(ir2.block.effect[0].operations).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'event',
- isStatic: false,
- },
- modifiers: { nonKeys: ['right'] },
- keyOverride: ['click', 'contextmenu'],
- },
- ])
-
- expect(code2).matchSnapshot()
- expect(code2).contains(
- '(_ctx.event) === "click" ? "contextmenu" : (_ctx.event)',
- )
- })
-
- test('should transform click.middle', () => {
- const { code, ir } = compileWithVOn(`<div @click.middle="test"/>`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'mouseup',
- isStatic: true,
- },
- modifiers: { nonKeys: ['middle'] },
- keyOverride: undefined,
- },
- ])
-
- expect(code).matchSnapshot()
- expect(code).contains('"mouseup"')
-
- // dynamic
- const { code: code2, ir: ir2 } = compileWithVOn(
- `<div @[event].middle="test"/>`,
- )
-
- expect(ir2.block.effect[0].operations).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'event',
- isStatic: false,
- },
- modifiers: { nonKeys: ['middle'] },
- keyOverride: ['click', 'mouseup'],
- },
- ])
-
- expect(code2).matchSnapshot()
- expect(code2).contains(
- '(_ctx.event) === "click" ? "mouseup" : (_ctx.event)',
- )
- })
-
- test('should not prefix member expression', () => {
- const { code } = compileWithVOn(`<div @click="foo.bar"/>`, {
- prefixIdentifiers: true,
- })
-
- expect(code).matchSnapshot()
- expect(code).contains(`n0.$evtclick = e => _ctx.foo.bar(e)`)
- })
-
- test('should delegate event', () => {
- const { code, ir, helpers } = compileWithVOn(`<div @click="test"/>`)
-
- expect(code).matchSnapshot()
- expect(code).contains('_delegateEvents("click")')
- expect(helpers).contains('delegateEvents')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_EVENT,
- delegate: true,
- },
- ])
- })
-
- test('should use delegate helper when have multiple events of same name', () => {
- const { code, helpers } = compileWithVOn(
- `<div @click="test" @click.stop="test" />`,
- )
- expect(helpers).contains('delegate')
- expect(code).toMatchSnapshot()
- expect(code).contains('_delegate(n0, "click", e => _ctx.test(e))')
- expect(code).contains(
- '_delegate(n0, "click", _withModifiers(e => _ctx.test(e), ["stop"]))',
- )
- })
-
- test('expression with type', () => {
- const { code } = compileWithVOn(
- `<div @click="(<number>handleClick as any)"></div>`,
- {
- bindingMetadata: {
- handleClick: BindingTypes.SETUP_CONST,
- },
- },
- )
- expect(code).matchSnapshot()
- expect(code).include('n0.$evtclick = e => _ctx.handleClick(e)')
- })
-})
+++ /dev/null
-import { BindingTypes, NodeTypes } from '@vue/compiler-dom'
-import { IRNodeTypes } from '../../src'
-import { getBaseTransformPreset } from '../../src/compile'
-import { makeCompile } from './_utils'
-
-const [nodeTransforms, directiveTransforms] = getBaseTransformPreset()
-const compileWithOnce = makeCompile({
- nodeTransforms,
- directiveTransforms,
-})
-
-describe('compiler: v-once', () => {
- test('basic', () => {
- const { ir, code } = compileWithOnce(
- `<div v-once>
- {{ msg }}
- <span :class="clz" />
- </div>`,
- {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- clz: BindingTypes.SETUP_REF,
- },
- },
- )
-
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_TEXT,
- element: 0,
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'msg',
- isStatic: false,
- },
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: ' ',
- isStatic: true,
- },
- ],
- },
- {
- element: 1,
- type: IRNodeTypes.SET_PROP,
- prop: {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'class',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'clz',
- isStatic: false,
- },
- ],
- },
- },
- ])
- })
-
- test('as root node', () => {
- const { ir, code } = compileWithOnce(`<div :id="foo" v-once />`)
-
- expect(code).toMatchSnapshot()
-
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_PROP,
- element: 0,
- prop: {
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: false,
- },
- ],
- },
- },
- ])
- expect(code).not.contains('effect')
- })
-
- test('on nested plain element', () => {
- const { ir, code } = compileWithOnce(`<div><div :id="foo" v-once /></div>`)
-
- expect(code).toMatchSnapshot()
-
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SET_PROP,
- element: 0,
- prop: {
- runtimeCamelize: false,
- key: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
- isStatic: true,
- },
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: false,
- },
- ],
- },
- },
- ])
- })
-
- test('on component', () => {
- const { ir, code } = compileWithOnce(`<div><Comp :id="foo" v-once /></div>`)
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.dynamic.children[0].children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 0,
- tag: 'Comp',
- once: true,
- parent: 1,
- })
- })
-
- test.todo('on slot outlet')
-
- test('inside v-once', () => {
- const { ir, code } = compileWithOnce(`<div v-once><div v-once/></div>`)
-
- expect(code).toMatchSnapshot()
-
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).lengthOf(0)
- })
-
- test.todo('with hoistStatic: true')
-
- test('with v-if', () => {
- const { ir, code } = compileWithOnce(`<div v-if="expr" v-once />`)
- expect(code).toMatchSnapshot()
-
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.IF,
- id: 0,
- once: true,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'expr',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- })
- })
-
- test('with v-if/else', () => {
- const { ir, code } = compileWithOnce(
- `<div v-if="expr" v-once /><p v-else/>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.IF,
- id: 0,
- once: true,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'expr',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- negative: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
- },
- })
- })
-
- test('with v-for', () => {
- const { ir, code } = compileWithOnce(`<div v-for="i in list" v-once />`)
- expect(code).toMatchSnapshot()
- expect(ir.block.effect).lengthOf(0)
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.FOR,
- id: 0,
- once: true,
- })
- })
-})
+++ /dev/null
-import { makeCompile } from './_utils'
-import { transformChildren, transformElement, transformVShow } from '../../src'
-import { DOMErrorCodes } from '@vue/compiler-dom'
-
-const compileWithVShow = makeCompile({
- nodeTransforms: [transformElement, transformChildren],
- directiveTransforms: {
- show: transformVShow,
- },
-})
-
-describe('compiler: v-show transform', () => {
- test('simple expression', () => {
- const { code } = compileWithVShow(`<div v-show="foo"/>`)
- expect(code).toMatchSnapshot()
- })
-
- test('should raise error if has no expression', () => {
- const onError = vi.fn()
- compileWithVShow(`<div v-show/>`, { onError })
-
- expect(onError).toHaveBeenCalledTimes(1)
- expect(onError).toHaveBeenCalledWith(
- expect.objectContaining({
- code: DOMErrorCodes.X_V_SHOW_NO_EXPRESSION,
- }),
- )
- })
-})
+++ /dev/null
-import { ErrorCodes, NodeTypes } from '@vue/compiler-dom'
-import {
- IRNodeTypes,
- IRSlotType,
- transformChildren,
- transformElement,
- transformSlotOutlet,
- transformText,
- transformVBind,
- transformVFor,
- transformVIf,
- transformVOn,
- transformVSlot,
-} from '../../src'
-import { makeCompile } from './_utils'
-
-const compileWithSlots = makeCompile({
- nodeTransforms: [
- transformText,
- transformVIf,
- transformVFor,
- transformSlotOutlet,
- transformElement,
- transformVSlot,
- transformChildren,
- ],
- directiveTransforms: {
- bind: transformVBind,
- on: transformVOn,
- },
-})
-
-describe('compiler: transform slot', () => {
- test('implicit default slot', () => {
- const { ir, code } = compileWithSlots(`<Comp><div/></Comp>`)
- expect(code).toMatchSnapshot()
-
- expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 1,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- },
- },
- ],
- })
- expect(ir.block.returns).toEqual([1])
- expect(ir.block.dynamic).toMatchObject({
- children: [{ id: 1 }],
- })
- })
-
- test('on-component default slot', () => {
- const { ir, code } = compileWithSlots(
- `<Comp v-slot="{ foo }">{{ foo + bar }}</Comp>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(code).contains(`"default": (_slotProps0) =>`)
- expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
-
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- ast: {
- type: 'ArrowFunctionExpression',
- params: [{ type: 'ObjectPattern' }],
- },
- },
- },
- },
- },
- ],
- })
- })
-
- test('on component named slot', () => {
- const { ir, code } = compileWithSlots(
- `<Comp v-slot:named="{ foo }">{{ foo + bar }}</Comp>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(code).contains(`"named": (_slotProps0) =>`)
- expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
-
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- named: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- },
- },
- },
- },
- ],
- })
- })
-
- test('on component dynamically named slot', () => {
- const { ir, code } = compileWithSlots(
- `<Comp v-slot:[named]="{ foo }">{{ foo + bar }}</Comp>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(code).contains(`fn: (_slotProps0) =>`)
- expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
-
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'named',
- isStatic: false,
- },
- fn: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- },
- },
- },
- ],
- })
- })
-
- test('named slots w/ implicit default slot', () => {
- const { ir, code } = compileWithSlots(
- `<Comp>
- <template #one>foo</template>bar<span/>
- </Comp>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(ir.template).toEqual(['foo', 'bar', '<span></span>'])
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 4,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- one: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- default: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{}, { template: 1 }, { template: 2 }],
- },
- },
- },
- },
- ],
- })
- })
-
- test('nested slots scoping', () => {
- const { ir, code } = compileWithSlots(
- `<Comp>
- <template #default="{ foo }">
- <Inner v-slot="{ bar }">
- {{ foo + bar + baz }}
- </Inner>
- {{ foo + bar + baz }}
- </template>
- </Comp>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(code).contains(`"default": (_slotProps0) =>`)
- expect(code).contains(`"default": (_slotProps1) =>`)
- expect(code).contains(`_slotProps0["foo"] + _slotProps1["bar"] + _ctx.baz`)
- expect(code).contains(`_slotProps0["foo"] + _ctx.bar + _ctx.baz`)
-
- const outerOp = ir.block.dynamic.children[0].operation
- expect(outerOp).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- },
- },
- },
- },
- ],
- })
- expect(
- (outerOp as any).slots[0].slots.default.dynamic.children[0].operation,
- ).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Inner',
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ bar }',
- },
- },
- },
- },
- ],
- })
- })
-
- test('dynamic slots name', () => {
- const { ir, code } = compileWithSlots(
- `<Comp>
- <template #[name]>foo</template>
- </Comp>`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'name',
- isStatic: false,
- },
- fn: { type: IRNodeTypes.BLOCK },
- },
- ],
- })
- })
-
- test('dynamic slots name w/ v-for', () => {
- const { ir, code } = compileWithSlots(
- `<Comp>
- <template v-for="item in list" #[item]="{ bar }">{{ bar }}</template>
- </Comp>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(code).contains(`fn: (_slotProps0) =>`)
- expect(code).contains(`_setText(n0, _toDisplayString(_slotProps0["bar"]))`)
-
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'item',
- isStatic: false,
- },
- fn: { type: IRNodeTypes.BLOCK },
- loop: {
- source: { content: 'list' },
- value: { content: 'item' },
- index: undefined,
- },
- },
- ],
- })
- })
-
- test('dynamic slots name w/ v-for and provide absent key', () => {
- const { ir, code } = compileWithSlots(
- `<Comp>
- <template v-for="(,,index) in list" #[index]>foo</template>
- </Comp>`,
- )
- expect(code).toMatchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'index',
- isStatic: false,
- },
- fn: { type: IRNodeTypes.BLOCK },
- loop: {
- source: { content: 'list' },
- value: undefined,
- index: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- },
- },
- },
- ],
- })
- })
-
- test('dynamic slots name w/ v-if / v-else[-if]', () => {
- const { ir, code } = compileWithSlots(
- `<Comp>
- <template v-if="condition" #condition>condition slot</template>
- <template v-else-if="anotherCondition" #condition="{ foo, bar }">another condition</template>
- <template v-else #condition>else condition</template>
- </Comp>`,
- )
- expect(code).toMatchSnapshot()
-
- expect(code).contains(`fn: (_slotProps0) =>`)
-
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- slotType: IRSlotType.CONDITIONAL,
- condition: { content: 'condition' },
- positive: {
- slotType: IRSlotType.DYNAMIC,
- },
- negative: {
- slotType: IRSlotType.CONDITIONAL,
- condition: { content: 'anotherCondition' },
- positive: {
- slotType: IRSlotType.DYNAMIC,
- },
- negative: { slotType: IRSlotType.DYNAMIC },
- },
- },
- ],
- })
- })
-
- test('slot + v-if / v-else[-if] should not cause error', () => {
- const { code } = compileWithSlots(
- `<div>
- <slot name="foo"></slot>
- <Foo v-if="true"></Foo>
- <Bar v-else />
- </div>`,
- )
- expect(code).toMatchSnapshot()
- })
-
- test('quote slot name', () => {
- const { code } = compileWithSlots(
- `<Comp><template #nav-bar-title-before></template></Comp>`,
- )
- expect(code).toMatchSnapshot()
- expect(code).contains(`"nav-bar-title-before"`)
- })
-
- test('nested component slot', () => {
- const { ir, code } = compileWithSlots(`<A><B/></A>`)
- expect(code).toMatchSnapshot()
- expect(ir.block.dynamic.children[0].operation).toMatchObject({
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'A',
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [
- {
- operation: {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'B',
- slots: [],
- },
- },
- ],
- },
- },
- },
- },
- ],
- })
- })
-
- describe('errors', () => {
- test('error on extraneous children w/ named default slot', () => {
- const onError = vi.fn()
- const source = `<Comp><template #default>foo</template>bar</Comp>`
- compileWithSlots(source, { onError })
- const index = source.indexOf('bar')
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN,
- loc: {
- start: {
- offset: index,
- line: 1,
- column: index + 1,
- },
- end: {
- offset: index + 3,
- line: 1,
- column: index + 4,
- },
- },
- })
- })
-
- test('error on duplicated slot names', () => {
- const onError = vi.fn()
- const source = `<Comp><template #foo></template><template #foo></template></Comp>`
- compileWithSlots(source, { onError })
- const index = source.lastIndexOf('#foo')
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_SLOT_DUPLICATE_SLOT_NAMES,
- loc: {
- start: {
- offset: index,
- line: 1,
- column: index + 1,
- },
- end: {
- offset: index + 4,
- line: 1,
- column: index + 5,
- },
- },
- })
- })
-
- test('error on invalid mixed slot usage', () => {
- const onError = vi.fn()
- const source = `<Comp v-slot="foo"><template #foo></template></Comp>`
- compileWithSlots(source, { onError })
- const index = source.lastIndexOf('v-slot="foo"')
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE,
- loc: {
- start: {
- offset: index,
- line: 1,
- column: index + 1,
- },
- end: {
- offset: index + 12,
- line: 1,
- column: index + 13,
- },
- },
- })
- })
-
- test('error on v-slot usage on plain elements', () => {
- const onError = vi.fn()
- const source = `<div v-slot/>`
- compileWithSlots(source, { onError })
- const index = source.indexOf('v-slot')
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_SLOT_MISPLACED,
- loc: {
- start: {
- offset: index,
- line: 1,
- column: index + 1,
- },
- end: {
- offset: index + 6,
- line: 1,
- column: index + 7,
- },
- },
- })
- })
- })
-
- describe(`with whitespace: 'preserve'`, () => {
- test('named default slot + implicit whitespace content', () => {
- const source = `
- <Comp>
- <template #header> Header </template>
- <template #default> Default </template>
- </Comp>
- `
- const { code } = compileWithSlots(source, {
- whitespace: 'preserve',
- })
-
- expect(
- `Extraneous children found when component already has explicitly named default slot.`,
- ).not.toHaveBeenWarned()
- expect(code).toMatchSnapshot()
- })
-
- test('implicit default slot', () => {
- const source = `
- <Comp>
- <template #header> Header </template>
- <p/>
- </Comp>
- `
- const { code } = compileWithSlots(source, {
- whitespace: 'preserve',
- })
-
- expect(
- `Extraneous children found when component already has explicitly named default slot.`,
- ).not.toHaveBeenWarned()
- expect(code).toMatchSnapshot()
- })
-
- test('should not generate whitespace only default slot', () => {
- const source = `
- <Comp>
- <template #header> Header </template>
- <template #footer> Footer </template>
- </Comp>
- `
- const { code, ir } = compileWithSlots(source, {
- whitespace: 'preserve',
- })
-
- const slots = (ir.block.dynamic.children[0].operation as any).slots[0]
- .slots
- // should be: header, footer (no default)
- expect(Object.keys(slots).length).toBe(2)
- expect(!!slots['default']).toBe(false)
-
- expect(code).toMatchSnapshot()
- })
- })
-})
+++ /dev/null
-import { BindingTypes, DOMErrorCodes, NodeTypes } from '@vue/compiler-dom'
-import {
- IRNodeTypes,
- transformChildren,
- transformElement,
- transformVText,
-} from '../../src'
-import { makeCompile } from './_utils'
-
-const compileWithVText = makeCompile({
- nodeTransforms: [transformElement, transformChildren],
- directiveTransforms: {
- text: transformVText,
- },
-})
-
-describe('v-text', () => {
- test('should convert v-text to setText', () => {
- const { code, ir, helpers } = compileWithVText(`<div v-text="str"></div>`, {
- bindingMetadata: {
- str: BindingTypes.SETUP_REF,
- },
- })
-
- expect(helpers).contains('setText')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.GET_TEXT_CHILD,
- parent: 0,
- },
- ])
-
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'str',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_TEXT,
- element: 0,
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'str',
- isStatic: false,
- },
- ],
- },
- ],
- },
- ])
-
- expect(code).matchSnapshot()
- })
-
- test('should raise error and ignore children when v-text is present', () => {
- const onError = vi.fn()
- const { code, ir } = compileWithVText(`<div v-text="test">hello</div>`, {
- onError,
- })
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_V_TEXT_WITH_CHILDREN }],
- ])
-
- // children should have been removed
- expect(ir.template).toEqual(['<div> </div>'])
-
- expect(ir.block.effect).toMatchObject([
- {
- expressions: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- ],
- operations: [
- {
- type: IRNodeTypes.SET_TEXT,
- element: 0,
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'test',
- isStatic: false,
- },
- ],
- },
- ],
- },
- ])
-
- expect(code).matchSnapshot()
- // children should have been removed
- expect(code).contains('template("<div> </div>", true)')
- })
-
- test('should raise error if has no expression', () => {
- const onError = vi.fn()
- const { code } = compileWithVText(`<div v-text></div>`, { onError })
- expect(code).matchSnapshot()
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_V_TEXT_NO_EXPRESSION }],
- ])
- })
-})
+++ /dev/null
-{
- "name": "@vue/compiler-vapor",
- "version": "3.5.13",
- "description": "@vue/compiler-vapor",
- "main": "dist/compiler-vapor.cjs.js",
- "module": "dist/compiler-vapor.esm-bundler.js",
- "types": "dist/compiler-vapor.d.ts",
- "files": [
- "dist"
- ],
- "sideEffects": false,
- "exports": {
- ".": {
- "types": "./dist/compiler-vapor.d.ts",
- "node": "./dist/compiler-vapor.cjs.js",
- "module": "./dist/compiler-vapor.esm-browser.js",
- "import": "./dist/compiler-vapor.esm-browser.js",
- "require": "./dist/compiler-vapor.cjs.js"
- },
- "./*": "./*"
- },
- "buildOptions": {
- "formats": [
- "cjs",
- "esm-browser"
- ],
- "prod": false,
- "enableNonBrowserBranches": true
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vuejs/core.git",
- "directory": "packages/compiler-vapor"
- },
- "keywords": [
- "vue"
- ],
- "author": "Evan You",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/vuejs/core/issues"
- },
- "homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-vapor#readme",
- "dependencies": {
- "@vue/compiler-dom": "workspace:*",
- "@vue/shared": "workspace:*",
- "source-map-js": "catalog:"
- }
-}
+++ /dev/null
-import {
- type CompilerOptions as BaseCompilerOptions,
- type RootNode,
- parse,
-} from '@vue/compiler-dom'
-import { extend, isString } from '@vue/shared'
-import {
- type DirectiveTransform,
- type NodeTransform,
- transform,
-} from './transform'
-import { type VaporCodegenResult, generate } from './generate'
-import { transformChildren } from './transforms/transformChildren'
-import { transformVOnce } from './transforms/vOnce'
-import { transformElement } from './transforms/transformElement'
-import { transformVHtml } from './transforms/vHtml'
-import { transformVText } from './transforms/vText'
-import { transformVBind } from './transforms/vBind'
-import { transformVOn } from './transforms/vOn'
-import { transformVShow } from './transforms/vShow'
-import { transformTemplateRef } from './transforms/transformTemplateRef'
-import { transformText } from './transforms/transformText'
-import { transformVModel } from './transforms/vModel'
-import { transformVIf } from './transforms/vIf'
-import { transformVFor } from './transforms/vFor'
-import { transformComment } from './transforms/transformComment'
-import { transformSlotOutlet } from './transforms/transformSlotOutlet'
-import { transformVSlot } from './transforms/vSlot'
-import type { HackOptions } from './ir'
-
-export { wrapTemplate } from './transforms/utils'
-
-// code/AST -> IR (transform) -> JS (generate)
-export function compile(
- source: string | RootNode,
- options: CompilerOptions = {},
-): VaporCodegenResult {
- const resolvedOptions = extend({}, options)
- const ast = isString(source) ? parse(source, resolvedOptions) : source
- const [nodeTransforms, directiveTransforms] = getBaseTransformPreset()
-
- if (options.isTS) {
- const { expressionPlugins } = options
- if (!expressionPlugins || !expressionPlugins.includes('typescript')) {
- resolvedOptions.expressionPlugins = [
- ...(expressionPlugins || []),
- 'typescript',
- ]
- }
- }
-
- const ir = transform(
- ast,
- extend({}, resolvedOptions, {
- nodeTransforms: [
- ...nodeTransforms,
- ...(options.nodeTransforms || []), // user transforms
- ],
- directiveTransforms: extend(
- {},
- directiveTransforms,
- options.directiveTransforms || {}, // user transforms
- ),
- }),
- )
-
- return generate(ir, resolvedOptions)
-}
-
-export type CompilerOptions = HackOptions<BaseCompilerOptions>
-export type TransformPreset = [
- NodeTransform[],
- Record<string, DirectiveTransform>,
-]
-
-export function getBaseTransformPreset(): TransformPreset {
- return [
- [
- transformVOnce,
- transformVIf,
- transformVFor,
- transformSlotOutlet,
- transformTemplateRef,
- transformElement,
- transformText,
- transformVSlot,
- transformComment,
- transformChildren,
- ],
- {
- bind: transformVBind,
- on: transformVOn,
- html: transformVHtml,
- text: transformVText,
- show: transformVShow,
- model: transformVModel,
- },
- ]
-}
+++ /dev/null
-import {
- type CompilerError,
- type SourceLocation,
- createCompilerError,
-} from '@vue/compiler-dom'
-
-export interface VaporCompilerError extends CompilerError {
- code: VaporErrorCodes
-}
-
-export function createVaporCompilerError(
- code: VaporErrorCodes,
- loc?: SourceLocation,
-) {
- return createCompilerError(
- code,
- loc,
- VaporErrorMessages,
- ) as VaporCompilerError
-}
-
-export enum VaporErrorCodes {
- X_V_PLACEHOLDER = 100,
- __EXTEND_POINT__,
-}
-
-export const VaporErrorMessages: Record<VaporErrorCodes, string> = {
- [VaporErrorCodes.X_V_PLACEHOLDER]: `[placeholder]`,
-
- // just to fulfill types
- [VaporErrorCodes.__EXTEND_POINT__]: ``,
-}
+++ /dev/null
-import type {
- CodegenOptions as BaseCodegenOptions,
- BaseCodegenResult,
- SimpleExpressionNode,
-} from '@vue/compiler-dom'
-import type { BlockIRNode, CoreHelper, RootIRNode, VaporHelper } from './ir'
-import { extend, remove } from '@vue/shared'
-import { genBlockContent } from './generators/block'
-import { genTemplates } from './generators/template'
-import {
- type CodeFragment,
- INDENT_END,
- INDENT_START,
- LF,
- NEWLINE,
- buildCodeFragment,
- codeFragmentToString,
- genCall,
-} from './generators/utils'
-import { setTemplateRefIdent } from './generators/templateRef'
-
-export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'>
-
-export class CodegenContext {
- options: Required<CodegenOptions>
-
- helpers: Set<string> = new Set<string>([])
-
- helper = (name: CoreHelper | VaporHelper) => {
- this.helpers.add(name)
- return `_${name}`
- }
-
- delegates: Set<string> = new Set<string>()
-
- identifiers: Record<string, (string | SimpleExpressionNode)[]> =
- Object.create(null)
-
- seenInlineHandlerNames: Record<string, number> = Object.create(null)
-
- block: BlockIRNode
- withId<T>(
- fn: () => T,
- map: Record<string, string | SimpleExpressionNode | null>,
- ): T {
- const { identifiers } = this
- const ids = Object.keys(map)
-
- for (const id of ids) {
- identifiers[id] ||= []
- identifiers[id].unshift(map[id] || id)
- }
-
- const ret = fn()
- ids.forEach(id => remove(identifiers[id], map[id] || id))
-
- return ret
- }
-
- enterBlock(block: BlockIRNode) {
- const parent = this.block
- this.block = block
- return (): BlockIRNode => (this.block = parent)
- }
-
- scopeLevel: number = 0
- enterScope(): [level: number, exit: () => number] {
- return [this.scopeLevel++, () => this.scopeLevel--] as const
- }
-
- constructor(
- public ir: RootIRNode,
- options: CodegenOptions,
- ) {
- const defaultOptions: Required<CodegenOptions> = {
- mode: 'module',
- prefixIdentifiers: true,
- sourceMap: false,
- filename: `template.vue.html`,
- scopeId: null,
- runtimeGlobalName: `Vue`,
- runtimeModuleName: `vue`,
- ssrRuntimeModuleName: 'vue/server-renderer',
- ssr: false,
- isTS: false,
- inSSR: false,
- inline: false,
- bindingMetadata: {},
- expressionPlugins: [],
- }
- this.options = extend(defaultOptions, options)
- this.block = ir.block
- }
-}
-
-export interface VaporCodegenResult extends BaseCodegenResult {
- ast: RootIRNode
- helpers: Set<string>
-}
-
-// IR -> JS codegen
-export function generate(
- ir: RootIRNode,
- options: CodegenOptions = {},
-): VaporCodegenResult {
- const [frag, push] = buildCodeFragment()
- const context = new CodegenContext(ir, options)
- const { helpers } = context
- const { inline, bindingMetadata } = options
- const functionName = 'render'
-
- const args = ['_ctx']
- if (bindingMetadata && !inline) {
- // binding optimization args
- args.push('$props', '$emit', '$attrs', '$slots')
- }
- const signature = (options.isTS ? args.map(arg => `${arg}: any`) : args).join(
- ', ',
- )
-
- if (!inline) {
- push(NEWLINE, `export function ${functionName}(${signature}) {`)
- }
-
- push(INDENT_START)
- if (ir.hasTemplateRef) {
- push(
- NEWLINE,
- `const ${setTemplateRefIdent} = ${context.helper('createTemplateRefSetter')}()`,
- )
- }
- push(...genBlockContent(ir.block, context, true))
- push(INDENT_END, NEWLINE)
-
- if (!inline) {
- push('}')
- }
-
- const delegates = genDelegates(context)
- const templates = genTemplates(ir.template, ir.rootTemplateIndex, context)
- const imports = genHelperImports(context)
- const preamble = imports + templates + delegates
-
- const newlineCount = [...preamble].filter(c => c === '\n').length
- if (newlineCount && !inline) {
- frag.unshift(...new Array<CodeFragment>(newlineCount).fill(LF))
- }
-
- let [code, map] = codeFragmentToString(frag, context)
- if (!inline) {
- code = preamble + code
- }
-
- return {
- code,
- ast: ir,
- preamble,
- map: map && map.toJSON(),
- helpers,
- }
-}
-
-function genDelegates({ delegates, helper }: CodegenContext) {
- return delegates.size
- ? genCall(
- helper('delegateEvents'),
- ...Array.from(delegates).map(v => `"${v}"`),
- ).join('') + '\n'
- : ''
-}
-
-function genHelperImports({ helpers, helper, options }: CodegenContext) {
- let imports = ''
- if (helpers.size) {
- imports += `import { ${[...helpers]
- .map(h => `${h} as _${h}`)
- .join(', ')} } from '${options.runtimeModuleName}';\n`
- }
- return imports
-}
+++ /dev/null
-import type { BlockIRNode, CoreHelper } from '../ir'
-import {
- type CodeFragment,
- DELIMITERS_ARRAY,
- INDENT_END,
- INDENT_START,
- NEWLINE,
- buildCodeFragment,
- genCall,
- genMulti,
-} from './utils'
-import type { CodegenContext } from '../generate'
-import { genEffects, genOperations } from './operation'
-import { genChildren, genSelf } from './template'
-import { toValidAssetId } from '@vue/compiler-dom'
-
-export function genBlock(
- oper: BlockIRNode,
- context: CodegenContext,
- args: CodeFragment[] = [],
- root?: boolean,
- customReturns?: (returns: CodeFragment[]) => CodeFragment[],
-): CodeFragment[] {
- return [
- '(',
- ...args,
- ') => {',
- INDENT_START,
- ...genBlockContent(oper, context, root, customReturns),
- INDENT_END,
- NEWLINE,
- '}',
- ]
-}
-
-export function genBlockContent(
- block: BlockIRNode,
- context: CodegenContext,
- root?: boolean,
- customReturns?: (returns: CodeFragment[]) => CodeFragment[],
-): CodeFragment[] {
- const [frag, push] = buildCodeFragment()
- const { dynamic, effect, operation, returns } = block
- const resetBlock = context.enterBlock(block)
-
- if (root) {
- for (let name of context.ir.component) {
- const id = toValidAssetId(name, 'component')
- const maybeSelfReference = name.endsWith('__self')
- if (maybeSelfReference) name = name.slice(0, -6)
- push(
- NEWLINE,
- `const ${id} = `,
- ...genCall(
- context.helper('resolveComponent'),
- JSON.stringify(name),
- // pass additional `maybeSelfReference` flag
- maybeSelfReference ? 'true' : undefined,
- ),
- )
- }
- genResolveAssets('directive', 'resolveDirective')
- }
-
- for (const child of dynamic.children) {
- push(...genSelf(child, context))
- }
- for (const child of dynamic.children) {
- push(...genChildren(child, context, push, `n${child.id!}`))
- }
-
- push(...genOperations(operation, context))
- push(...genEffects(effect, context))
-
- push(NEWLINE, `return `)
-
- const returnNodes = returns.map(n => `n${n}`)
- const returnsCode: CodeFragment[] =
- returnNodes.length > 1
- ? genMulti(DELIMITERS_ARRAY, ...returnNodes)
- : [returnNodes[0] || 'null']
- push(...(customReturns ? customReturns(returnsCode) : returnsCode))
-
- resetBlock()
- return frag
-
- function genResolveAssets(
- kind: 'component' | 'directive',
- helper: CoreHelper,
- ) {
- for (const name of context.ir[kind]) {
- push(
- NEWLINE,
- `const ${toValidAssetId(name, kind)} = `,
- ...genCall(context.helper(helper), JSON.stringify(name)),
- )
- }
- }
-}
+++ /dev/null
-import { camelize, extend, isArray } from '@vue/shared'
-import type { CodegenContext } from '../generate'
-import {
- type CreateComponentIRNode,
- IRDynamicPropsKind,
- type IRProp,
- type IRProps,
- type IRPropsStatic,
- type IRSlotDynamic,
- type IRSlotDynamicBasic,
- type IRSlotDynamicConditional,
- type IRSlotDynamicLoop,
- IRSlotType,
- type IRSlots,
- type IRSlotsStatic,
- type SlotBlockIRNode,
-} from '../ir'
-import {
- type CodeFragment,
- DELIMITERS_ARRAY_NEWLINE,
- DELIMITERS_OBJECT,
- DELIMITERS_OBJECT_NEWLINE,
- INDENT_END,
- INDENT_START,
- NEWLINE,
- genCall,
- genMulti,
-} from './utils'
-import { genExpression } from './expression'
-import { genPropKey, genPropValue } from './prop'
-import {
- type SimpleExpressionNode,
- createSimpleExpression,
- isMemberExpression,
- toValidAssetId,
- walkIdentifiers,
-} from '@vue/compiler-dom'
-import { genEventHandler } from './event'
-import { genDirectiveModifiers, genDirectivesForElement } from './directive'
-import { genBlock } from './block'
-import { genModelHandler } from './vModel'
-
-export function genCreateComponent(
- operation: CreateComponentIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
-
- const tag = genTag()
- const { root, props, slots, once } = operation
- const rawSlots = genRawSlots(slots, context)
- const [ids, handlers] = processInlineHandlers(props, context)
- const rawProps = context.withId(() => genRawProps(props, context), ids)
-
- const inlineHandlers: CodeFragment[] = handlers.reduce<CodeFragment[]>(
- (acc, { name, value }) => {
- const handler = genEventHandler(context, value, undefined, false)
- return [...acc, `const ${name} = `, ...handler, NEWLINE]
- },
- [],
- )
-
- return [
- NEWLINE,
- ...inlineHandlers,
- `const n${operation.id} = `,
- ...genCall(
- operation.dynamic && !operation.dynamic.isStatic
- ? helper('createDynamicComponent')
- : operation.asset
- ? helper('createComponentWithFallback')
- : helper('createComponent'),
- tag,
- rawProps,
- rawSlots,
- root ? 'true' : false,
- once && 'true',
- ),
- ...genDirectivesForElement(operation.id, context),
- ]
-
- function genTag() {
- if (operation.dynamic) {
- if (operation.dynamic.isStatic) {
- return genCall(
- helper('resolveDynamicComponent'),
- genExpression(operation.dynamic, context),
- )
- } else {
- return ['() => (', ...genExpression(operation.dynamic, context), ')']
- }
- } else if (operation.asset) {
- return toValidAssetId(operation.tag, 'component')
- } else {
- return genExpression(
- extend(createSimpleExpression(operation.tag, false), { ast: null }),
- context,
- )
- }
- }
-}
-
-function getUniqueHandlerName(context: CodegenContext, name: string): string {
- const { seenInlineHandlerNames } = context
- const count = seenInlineHandlerNames[name] || 0
- seenInlineHandlerNames[name] = count + 1
- return count === 0 ? name : `${name}${count}`
-}
-
-type InlineHandler = {
- name: string
- value: SimpleExpressionNode
-}
-
-function processInlineHandlers(
- props: IRProps[],
- context: CodegenContext,
-): [Record<string, null>, InlineHandler[]] {
- const ids: Record<string, null> = Object.create(null)
- const handlers: InlineHandler[] = []
- const staticProps = props[0]
- if (isArray(staticProps)) {
- for (let i = 0; i < staticProps.length; i++) {
- const prop = staticProps[i]
- if (!prop.handler) continue
- prop.values.forEach((value, i) => {
- const isMemberExp = isMemberExpression(value, context.options)
- // cache inline handlers (fn expression or inline statement)
- if (!isMemberExp) {
- const name = getUniqueHandlerName(context, `_on_${prop.key.content}`)
- handlers.push({ name, value })
- ids[name] = null
- // replace the original prop value with the handler name
- prop.values[i] = extend({ ast: null }, createSimpleExpression(name))
- }
- })
- }
- }
- return [ids, handlers]
-}
-
-export function genRawProps(
- props: IRProps[],
- context: CodegenContext,
-): CodeFragment[] | undefined {
- const staticProps = props[0]
- if (isArray(staticProps)) {
- if (!staticProps.length && props.length === 1) {
- return
- }
- return genStaticProps(
- staticProps,
- context,
- genDynamicProps(props.slice(1), context),
- )
- } else if (props.length) {
- // all dynamic
- return genStaticProps([], context, genDynamicProps(props, context))
- }
-}
-
-function genStaticProps(
- props: IRPropsStatic,
- context: CodegenContext,
- dynamicProps?: CodeFragment[],
-): CodeFragment[] {
- const args = props.map(prop => genProp(prop, context, true))
- if (dynamicProps) {
- args.push([`$: `, ...dynamicProps])
- }
- return genMulti(
- args.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT,
- ...args,
- )
-}
-
-function genDynamicProps(
- props: IRProps[],
- context: CodegenContext,
-): CodeFragment[] | undefined {
- const { helper } = context
- const frags: CodeFragment[][] = []
- for (const p of props) {
- let expr: CodeFragment[]
- if (isArray(p)) {
- if (p.length) {
- frags.push(genStaticProps(p, context))
- }
- continue
- } else {
- if (p.kind === IRDynamicPropsKind.ATTRIBUTE)
- expr = genMulti(DELIMITERS_OBJECT, genProp(p, context))
- else {
- expr = genExpression(p.value, context)
- if (p.handler) expr = genCall(helper('toHandlers'), expr)
- }
- }
- frags.push(['() => (', ...expr, ')'])
- }
- if (frags.length) {
- return genMulti(DELIMITERS_ARRAY_NEWLINE, ...frags)
- }
-}
-
-function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
- const values = genPropValue(prop.values, context)
- return [
- ...genPropKey(prop, context),
- ': ',
- ...(prop.handler
- ? genEventHandler(
- context,
- prop.values[0],
- undefined,
- true /* wrap handlers passed to components */,
- )
- : isStatic
- ? ['() => (', ...values, ')']
- : values),
- ...(prop.model
- ? [...genModelEvent(prop, context), ...genModelModifiers(prop, context)]
- : []),
- ]
-}
-
-function genModelEvent(prop: IRProp, context: CodegenContext): CodeFragment[] {
- const name = prop.key.isStatic
- ? [JSON.stringify(`onUpdate:${camelize(prop.key.content)}`)]
- : ['["onUpdate:" + ', ...genExpression(prop.key, context), ']']
- const handler = genModelHandler(prop.values[0], context)
-
- return [',', NEWLINE, ...name, ': () => ', ...handler]
-}
-
-function genModelModifiers(
- prop: IRProp,
- context: CodegenContext,
-): CodeFragment[] {
- const { key, modelModifiers } = prop
- if (!modelModifiers || !modelModifiers.length) return []
-
- const modifiersKey = key.isStatic
- ? key.content === 'modelValue'
- ? [`modelModifiers`]
- : [`${key.content}Modifiers`]
- : ['[', ...genExpression(key, context), ' + "Modifiers"]']
-
- const modifiersVal = genDirectiveModifiers(modelModifiers)
- return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`]
-}
-
-function genRawSlots(slots: IRSlots[], context: CodegenContext) {
- if (!slots.length) return
- const staticSlots = slots[0]
- if (staticSlots.slotType === IRSlotType.STATIC) {
- // single static slot
- return genStaticSlots(
- staticSlots,
- context,
- slots.length > 1 ? slots.slice(1) : undefined,
- )
- } else {
- return genStaticSlots(
- { slotType: IRSlotType.STATIC, slots: {} },
- context,
- slots,
- )
- }
-}
-
-function genStaticSlots(
- { slots }: IRSlotsStatic,
- context: CodegenContext,
- dynamicSlots?: IRSlots[],
-) {
- const args = Object.keys(slots).map(name => [
- `${JSON.stringify(name)}: `,
- ...genSlotBlockWithProps(slots[name], context),
- ])
- if (dynamicSlots) {
- args.push([`$: `, ...genDynamicSlots(dynamicSlots, context)])
- }
- return genMulti(DELIMITERS_OBJECT_NEWLINE, ...args)
-}
-
-function genDynamicSlots(
- slots: IRSlots[],
- context: CodegenContext,
-): CodeFragment[] {
- return genMulti(
- DELIMITERS_ARRAY_NEWLINE,
- ...slots.map(slot =>
- slot.slotType === IRSlotType.STATIC
- ? genStaticSlots(slot, context)
- : slot.slotType === IRSlotType.EXPRESSION
- ? slot.slots.content
- : genDynamicSlot(slot, context, true),
- ),
- )
-}
-
-function genDynamicSlot(
- slot: IRSlotDynamic,
- context: CodegenContext,
- withFunction = false,
-): CodeFragment[] {
- let frag: CodeFragment[]
- switch (slot.slotType) {
- case IRSlotType.DYNAMIC:
- frag = genBasicDynamicSlot(slot, context)
- break
- case IRSlotType.LOOP:
- frag = genLoopSlot(slot, context)
- break
- case IRSlotType.CONDITIONAL:
- frag = genConditionalSlot(slot, context)
- break
- }
- return withFunction ? ['() => (', ...frag, ')'] : frag
-}
-
-function genBasicDynamicSlot(
- slot: IRSlotDynamicBasic,
- context: CodegenContext,
-): CodeFragment[] {
- const { name, fn } = slot
- return genMulti(
- DELIMITERS_OBJECT_NEWLINE,
- ['name: ', ...genExpression(name, context)],
- ['fn: ', ...genSlotBlockWithProps(fn, context)],
- )
-}
-
-function genLoopSlot(
- slot: IRSlotDynamicLoop,
- context: CodegenContext,
-): CodeFragment[] {
- const { name, fn, loop } = slot
- const { value, key, index, source } = loop
- const rawValue = value && value.content
- const rawKey = key && key.content
- const rawIndex = index && index.content
-
- const idMap: Record<string, string> = {}
- if (rawValue) idMap[rawValue] = rawValue
- if (rawKey) idMap[rawKey] = rawKey
- if (rawIndex) idMap[rawIndex] = rawIndex
- const slotExpr = genMulti(
- DELIMITERS_OBJECT_NEWLINE,
- ['name: ', ...context.withId(() => genExpression(name, context), idMap)],
- [
- 'fn: ',
- ...context.withId(() => genSlotBlockWithProps(fn, context), idMap),
- ],
- )
- return [
- ...genCall(
- context.helper('createForSlots'),
- genExpression(source, context),
- [
- ...genMulti(
- ['(', ')', ', '],
- rawValue ? rawValue : rawKey || rawIndex ? '_' : undefined,
- rawKey ? rawKey : rawIndex ? '__' : undefined,
- rawIndex,
- ),
- ' => (',
- ...slotExpr,
- ')',
- ],
- ),
- ]
-}
-
-function genConditionalSlot(
- slot: IRSlotDynamicConditional,
- context: CodegenContext,
-): CodeFragment[] {
- const { condition, positive, negative } = slot
- return [
- ...genExpression(condition, context),
- INDENT_START,
- NEWLINE,
- '? ',
- ...genDynamicSlot(positive, context),
- NEWLINE,
- ': ',
- ...(negative ? [...genDynamicSlot(negative, context)] : ['void 0']),
- INDENT_END,
- ]
-}
-
-function genSlotBlockWithProps(oper: SlotBlockIRNode, context: CodegenContext) {
- let isDestructureAssignment = false
- let rawProps: string | undefined
- let propsName: string | undefined
- let exitScope: (() => void) | undefined
- let depth: number | undefined
- const { props } = oper
- const idsOfProps = new Set<string>()
-
- if (props) {
- rawProps = props.content
- if ((isDestructureAssignment = !!props.ast)) {
- ;[depth, exitScope] = context.enterScope()
- propsName = `_slotProps${depth}`
- walkIdentifiers(
- props.ast,
- (id, _, __, ___, isLocal) => {
- if (isLocal) idsOfProps.add(id.name)
- },
- true,
- )
- } else {
- idsOfProps.add((propsName = rawProps))
- }
- }
-
- const idMap: Record<string, string | null> = {}
-
- idsOfProps.forEach(
- id =>
- (idMap[id] = isDestructureAssignment
- ? `${propsName}[${JSON.stringify(id)}]`
- : null),
- )
- const blockFn = context.withId(
- () => genBlock(oper, context, [propsName]),
- idMap,
- )
- exitScope && exitScope()
-
- return blockFn
-}
+++ /dev/null
-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 { type DirectiveIRNode, IRNodeTypes, type OperationNode } from '../ir'
-import { genVShow } from './vShow'
-import { genVModel } from './vModel'
-
-export function genBuiltinDirective(
- oper: DirectiveIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- switch (oper.name) {
- case 'show':
- return genVShow(oper, context)
- case 'model':
- return genVModel(oper, context)
- default:
- return []
- }
-}
-
-/**
- * user directives via `withVaporDirectives`
- * TODO the compiler side is implemented but no runtime support yet
- * it was removed due to perf issues
- */
-export function genDirectivesForElement(
- id: number,
- context: CodegenContext,
-): CodeFragment[] {
- const dirs = filterCustomDirectives(id, context.block.operation)
- return dirs.length ? genCustomDirectives(dirs, context) : []
-}
-
-function genCustomDirectives(
- opers: DirectiveIRNode[],
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
-
- const element = `n${opers[0].element}`
- const directiveItems = opers.map(genDirectiveItem)
- const directives = genMulti(DELIMITERS_ARRAY, ...directiveItems)
-
- return [
- NEWLINE,
- ...genCall(helper('withVaporDirectives'), element, directives),
- ]
-
- function genDirectiveItem({
- dir,
- name,
- asset,
- }: DirectiveIRNode): CodeFragment[] {
- const directiveVar = asset
- ? toValidAssetId(name, 'directive')
- : genExpression(
- extend(createSimpleExpression(name, false), { ast: null }),
- context,
- )
- 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,
- directiveVar,
- value,
- argument,
- modifiers,
- )
- }
-}
-
-export function genDirectiveModifiers(modifiers: string[]): string {
- return modifiers
- .map(
- value =>
- `${isSimpleIdentifier(value) ? value : JSON.stringify(value)}: true`,
- )
- .join(', ')
-}
-
-function filterCustomDirectives(
- id: number,
- operations: OperationNode[],
-): DirectiveIRNode[] {
- return operations.filter(
- (oper): oper is DirectiveIRNode =>
- oper.type === IRNodeTypes.DIRECTIVE &&
- oper.element === id &&
- !oper.builtin,
- )
-}
+++ /dev/null
-import type { CodegenContext } from '../generate'
-import type { InsertNodeIRNode, PrependNodeIRNode } from '../ir'
-import { type CodeFragment, NEWLINE, genCall } from './utils'
-
-export function genInsertNode(
- { parent, elements, anchor }: InsertNodeIRNode,
- { helper }: CodegenContext,
-): CodeFragment[] {
- let element = elements.map(el => `n${el}`).join(', ')
- if (elements.length > 1) element = `[${element}]`
- return [
- NEWLINE,
- ...genCall(
- helper('insert'),
- element,
- `n${parent}`,
- anchor === undefined ? undefined : `n${anchor}`,
- ),
- ]
-}
-
-export function genPrependNode(
- oper: PrependNodeIRNode,
- { helper }: CodegenContext,
-): CodeFragment[] {
- return [
- NEWLINE,
- ...genCall(
- helper('prepend'),
- `n${oper.parent}`,
- ...oper.elements.map(el => `n${el}`),
- ),
- ]
-}
+++ /dev/null
-import {
- BindingTypes,
- type SimpleExpressionNode,
- isFnExpression,
- isMemberExpression,
-} from '@vue/compiler-dom'
-import type { CodegenContext } from '../generate'
-import {
- IRNodeTypes,
- type OperationNode,
- type SetDynamicEventsIRNode,
- type 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 { helper } = context
- const { element, key, keyOverride, value, modifiers, delegate, effect } = oper
-
- const name = genName()
- const handler = genEventHandler(context, value, modifiers)
- const eventOptions = genEventOptions()
-
- if (delegate) {
- // key is static
- context.delegates.add(key.content)
- // if this is the only delegated event of this name on this element,
- // we can generate optimized handler attachment code
- // e.g. n1.$evtclick = () => {}
- if (!context.block.operation.some(isSameDelegateEvent)) {
- return [NEWLINE, `n${element}.$evt${key.content} = `, ...handler]
- }
- }
-
- return [
- NEWLINE,
- ...genCall(
- helper(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 } = modifiers
- if (!options.length && !effect) return
-
- return genMulti(
- DELIMITERS_OBJECT_NEWLINE,
- effect && ['effect: true'],
- ...options.map((option): CodeFragment[] => [`${option}: true`]),
- )
- }
-
- function isSameDelegateEvent(op: OperationNode) {
- if (
- op.type === IRNodeTypes.SET_EVENT &&
- op !== oper &&
- op.delegate &&
- op.element === oper.element &&
- op.key.content === key.content
- ) {
- return true
- }
- }
-}
-
-export function genSetDynamicEvents(
- oper: SetDynamicEventsIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- return [
- NEWLINE,
- ...genCall(
- helper('setDynamicEvents'),
- `n${oper.element}`,
- genExpression(oper.event, context),
- ),
- ]
-}
-
-export function genEventHandler(
- context: CodegenContext,
- value: SimpleExpressionNode | undefined,
- modifiers: {
- nonKeys: string[]
- keys: string[]
- } = { nonKeys: [], keys: [] },
- // passed as component prop - need additional wrap
- extraWrap: boolean = false,
-): CodeFragment[] {
- let handlerExp: CodeFragment[] = [`() => {}`]
- if (value && value.content.trim()) {
- // Determine how the handler should be wrapped so it always reference the
- // latest value when invoked.
- if (isMemberExpression(value, context.options)) {
- // e.g. @click="foo.bar"
- handlerExp = genExpression(value, context)
- if (!isConstantBinding(value, context) && !extraWrap) {
- // non constant, wrap with invocation as `e => foo.bar(e)`
- // when passing as component handler, access is always dynamic so we
- // can skip this
- handlerExp = [`e => `, ...handlerExp, `(e)`]
- }
- } else if (isFnExpression(value, context.options)) {
- // Fn expression: @click="e => foo(e)"
- // no need to wrap in this case
- handlerExp = genExpression(value, context)
- } else {
- // inline statement
- // @click="foo($event)" ---> $event => foo($event)
- const referencesEvent = value.content.includes('$event')
- const hasMultipleStatements = value.content.includes(`;`)
- const expr = referencesEvent
- ? context.withId(() => genExpression(value, context), {
- $event: null,
- })
- : genExpression(value, context)
- handlerExp = [
- referencesEvent ? '$event => ' : '() => ',
- hasMultipleStatements ? '{' : '(',
- ...expr,
- hasMultipleStatements ? '}' : ')',
- ]
- }
- }
-
- const { keys, nonKeys } = modifiers
- if (nonKeys.length)
- handlerExp = genWithModifiers(context, handlerExp, nonKeys)
- if (keys.length) handlerExp = genWithKeys(context, handlerExp, keys)
-
- if (extraWrap) handlerExp.unshift(`() => `)
- return handlerExp
-}
-
-function genWithModifiers(
- context: CodegenContext,
- handler: CodeFragment[],
- nonKeys: string[],
-): CodeFragment[] {
- return genCall(
- context.helper('withModifiers'),
- handler,
- JSON.stringify(nonKeys),
- )
-}
-
-function genWithKeys(
- context: CodegenContext,
- handler: CodeFragment[],
- keys: string[],
-): CodeFragment[] {
- return genCall(context.helper('withKeys'), handler, JSON.stringify(keys))
-}
-
-function isConstantBinding(
- value: SimpleExpressionNode,
- context: CodegenContext,
-) {
- if (value.ast === null) {
- const bindingType = context.options.bindingMetadata[value.content]
- if (bindingType === BindingTypes.SETUP_CONST) {
- return true
- }
- }
-}
+++ /dev/null
-import {
- NOOP,
- extend,
- genPropsAccessExp,
- isGloballyAllowed,
- isString,
-} from '@vue/shared'
-import {
- BindingTypes,
- NewlineType,
- type SimpleExpressionNode,
- type SourceLocation,
- TS_NODE_TYPES,
- advancePositionWithClone,
- createSimpleExpression,
- isInDestructureAssignment,
- isStaticProperty,
- walkIdentifiers,
-} from '@vue/compiler-dom'
-import type { Identifier, Node } from '@babel/types'
-import type { CodegenContext } from '../generate'
-import { isConstantExpression } from '../utils'
-import { type CodeFragment, NEWLINE, buildCodeFragment } from './utils'
-import { type ParserOptions, parseExpression } from '@babel/parser'
-
-export function genExpression(
- node: SimpleExpressionNode,
- context: CodegenContext,
- assignment?: string,
-): CodeFragment[] {
- const { content, ast, isStatic, loc } = node
-
- if (isStatic) {
- return [[JSON.stringify(content), NewlineType.None, loc]]
- }
-
- if (
- !node.content.trim() ||
- // there was a parsing error
- ast === false ||
- isConstantExpression(node)
- ) {
- return [[content, NewlineType.None, loc], assignment && ` = ${assignment}`]
- }
-
- // the expression is a simple identifier
- if (ast === null) {
- return genIdentifier(content, context, loc, assignment)
- }
-
- const ids: Identifier[] = []
- const parentStackMap = new Map<Identifier, Node[]>()
- const parentStack: Node[] = []
- walkIdentifiers(
- ast!,
- id => {
- ids.push(id)
- parentStackMap.set(id, parentStack.slice())
- },
- false,
- parentStack,
- )
-
- let hasMemberExpression = false
- if (ids.length) {
- const [frag, push] = buildCodeFragment()
- const isTSNode = ast && TS_NODE_TYPES.includes(ast.type)
- ids
- .sort((a, b) => a.start! - b.start!)
- .forEach((id, i) => {
- // range is offset by -1 due to the wrapping parens when parsed
- const start = id.start! - 1
- const end = id.end! - 1
- const last = ids[i - 1]
-
- if (!(isTSNode && i === 0)) {
- const leadingText = content.slice(last ? last.end! - 1 : 0, start)
- if (leadingText.length) push([leadingText, NewlineType.Unknown])
- }
-
- const source = content.slice(start, end)
- const parentStack = parentStackMap.get(id)!
- const parent = parentStack[parentStack.length - 1]
-
- hasMemberExpression ||=
- parent &&
- (parent.type === 'MemberExpression' ||
- parent.type === 'OptionalMemberExpression')
-
- push(
- ...genIdentifier(
- source,
- context,
- {
- start: advancePositionWithClone(node.loc.start, source, start),
- end: advancePositionWithClone(node.loc.start, source, end),
- source,
- },
- hasMemberExpression ? undefined : assignment,
- id,
- parent,
- parentStack,
- ),
- )
-
- if (i === ids.length - 1 && end < content.length && !isTSNode) {
- push([content.slice(end), NewlineType.Unknown])
- }
- })
-
- if (assignment && hasMemberExpression) {
- push(` = ${assignment}`)
- }
- return frag
- } else {
- return [[content, NewlineType.Unknown, loc]]
- }
-}
-
-function genIdentifier(
- raw: string,
- context: CodegenContext,
- loc?: SourceLocation,
- assignment?: string,
- id?: Identifier,
- parent?: Node,
- parentStack?: Node[],
-): CodeFragment[] {
- const { options, helper, identifiers } = context
- const { inline, bindingMetadata } = options
- let name: string | undefined = raw
-
- const idMap = identifiers[raw]
- if (idMap && idMap.length) {
- const replacement = idMap[0]
- if (isString(replacement)) {
- if (parent && parent.type === 'ObjectProperty' && parent.shorthand) {
- return [[`${name}: ${replacement}`, NewlineType.None, loc]]
- } else {
- return [[replacement, NewlineType.None, loc]]
- }
- } else {
- // replacement is an expression - process it again
- return genExpression(replacement, context, assignment)
- }
- }
-
- let prefix: string | undefined
- if (isStaticProperty(parent) && parent.shorthand) {
- // property shorthand like { foo }, we need to add the key since
- // we rewrite the value
- prefix = `${raw}: `
- }
-
- const type = bindingMetadata && bindingMetadata[raw]
- if (inline) {
- switch (type) {
- case BindingTypes.SETUP_LET:
- name = raw = assignment
- ? `_isRef(${raw}) ? (${raw}.value = ${assignment}) : (${raw} = ${assignment})`
- : unref()
- break
- case BindingTypes.SETUP_REF:
- name = raw = withAssignment(`${raw}.value`)
- break
- case BindingTypes.SETUP_MAYBE_REF:
- // ({ x } = y)
- const isDestructureAssignment =
- parent && isInDestructureAssignment(parent, parentStack || [])
- // x = y
- const isAssignmentLVal =
- parent && parent.type === 'AssignmentExpression' && parent.left === id
- // x++
- const isUpdateArg =
- parent && parent.type === 'UpdateExpression' && parent.argument === id
- // const binding that may or may not be ref
- // if it's not a ref, then assignments don't make sense -
- // so we ignore the non-ref assignment case and generate code
- // that assumes the value to be a ref for more efficiency
- raw =
- isAssignmentLVal || isUpdateArg || isDestructureAssignment
- ? (name = `${raw}.value`)
- : assignment
- ? `${helper('isRef')}(${raw}) ? (${raw}.value = ${assignment}) : null`
- : unref()
- break
- case BindingTypes.PROPS:
- raw = genPropsAccessExp(raw)
- break
- case BindingTypes.PROPS_ALIASED:
- raw = genPropsAccessExp(bindingMetadata.__propsAliases![raw])
- break
- default:
- raw = withAssignment(raw)
- }
- } else {
- if (canPrefix(raw)) {
- if (type === BindingTypes.PROPS_ALIASED) {
- raw = `$props['${bindingMetadata.__propsAliases![raw]}']`
- } else {
- raw = `${type === BindingTypes.PROPS ? '$props' : '_ctx'}.${raw}`
- }
- }
- raw = withAssignment(raw)
- }
- return [prefix, [raw, NewlineType.None, loc, name]]
-
- function withAssignment(s: string) {
- return assignment ? `${s} = ${assignment}` : s
- }
- function unref() {
- return `${helper('unref')}(${raw})`
- }
-}
-
-function canPrefix(name: string) {
- // skip whitelisted globals
- if (isGloballyAllowed(name)) {
- return false
- }
- if (
- // special case for webpack compilation
- name === 'require' ||
- name === '$props' ||
- name === '$emit' ||
- name === '$attrs' ||
- name === '$slots'
- )
- return false
- return true
-}
-
-type DeclarationResult = {
- ids: Record<string, string>
- frag: CodeFragment[]
-}
-type DeclarationValue = {
- name: string
- isIdentifier?: boolean
- value: SimpleExpressionNode
- rawName?: string
- exps?: Set<SimpleExpressionNode>
- seenCount?: number
-}
-
-export function processExpressions(
- context: CodegenContext,
- expressions: SimpleExpressionNode[],
-): DeclarationResult {
- // analyze variables
- const {
- seenVariable,
- variableToExpMap,
- expToVariableMap,
- seenIdentifier,
- updatedVariable,
- } = analyzeExpressions(expressions)
-
- // process repeated identifiers and member expressions
- // e.g., `foo[baz]` will be transformed into `foo_baz`
- const varDeclarations = processRepeatedVariables(
- context,
- seenVariable,
- variableToExpMap,
- expToVariableMap,
- seenIdentifier,
- updatedVariable,
- )
-
- // process duplicate expressions after identifier and member expression handling.
- // e.g., `foo + bar` will be transformed into `foo_bar`
- const expDeclarations = processRepeatedExpressions(
- context,
- expressions,
- varDeclarations,
- updatedVariable,
- expToVariableMap,
- )
-
- return genDeclarations([...varDeclarations, ...expDeclarations], context)
-}
-
-function analyzeExpressions(expressions: SimpleExpressionNode[]) {
- const seenVariable: Record<string, number> = Object.create(null)
- const variableToExpMap = new Map<string, Set<SimpleExpressionNode>>()
- const expToVariableMap = new Map<
- SimpleExpressionNode,
- Array<{
- name: string
- loc?: { start: number; end: number }
- }>
- >()
- const seenIdentifier = new Set<string>()
- const updatedVariable = new Set<string>()
-
- const registerVariable = (
- name: string,
- exp: SimpleExpressionNode,
- isIdentifier: boolean,
- loc?: { start: number; end: number },
- parentStack: Node[] = [],
- ) => {
- if (isIdentifier) seenIdentifier.add(name)
- seenVariable[name] = (seenVariable[name] || 0) + 1
- variableToExpMap.set(
- name,
- (variableToExpMap.get(name) || new Set()).add(exp),
- )
-
- const variables = expToVariableMap.get(exp) || []
- variables.push({ name, loc })
- expToVariableMap.set(exp, variables)
-
- if (
- parentStack.some(
- p => p.type === 'UpdateExpression' || p.type === 'AssignmentExpression',
- )
- ) {
- updatedVariable.add(name)
- }
- }
-
- for (const exp of expressions) {
- if (!exp.ast) {
- exp.ast === null && registerVariable(exp.content, exp, true)
- continue
- }
-
- walkIdentifiers(exp.ast, (currentNode, parent, parentStack) => {
- if (parent && isMemberExpression(parent)) {
- const memberExp = extractMemberExpression(parent, id => {
- registerVariable(id.name, exp, true, {
- start: id.start!,
- end: id.end!,
- })
- })
- registerVariable(
- memberExp,
- exp,
- false,
- { start: parent.start!, end: parent.end! },
- parentStack,
- )
- } else if (!parentStack.some(isMemberExpression)) {
- registerVariable(
- currentNode.name,
- exp,
- true,
- { start: currentNode.start!, end: currentNode.end! },
- parentStack,
- )
- }
- })
- }
-
- return {
- seenVariable,
- seenIdentifier,
- variableToExpMap,
- expToVariableMap,
- updatedVariable,
- }
-}
-
-function processRepeatedVariables(
- context: CodegenContext,
- seenVariable: Record<string, number>,
- variableToExpMap: Map<string, Set<SimpleExpressionNode>>,
- expToVariableMap: Map<
- SimpleExpressionNode,
- Array<{ name: string; loc?: { start: number; end: number } }>
- >,
- seenIdentifier: Set<string>,
- updatedVariable: Set<string>,
-): DeclarationValue[] {
- const declarations: DeclarationValue[] = []
- const expToReplacementMap = new Map<
- SimpleExpressionNode,
- Array<{
- name: string
- locs: { start: number; end: number }[]
- }>
- >()
-
- for (const [name, exps] of variableToExpMap) {
- if (updatedVariable.has(name)) continue
- if (seenVariable[name] > 1 && exps.size > 0) {
- const isIdentifier = seenIdentifier.has(name)
- const varName = isIdentifier ? name : genVarName(name)
-
- // replaces all non-identifiers with the new name. if node content
- // includes only one member expression, it will become an identifier,
- // e.g., foo[baz] -> foo_baz.
- // for identifiers, we don't need to replace the content - they will be
- // replaced during context.withId(..., ids)
- exps.forEach(node => {
- if (node.ast && varName !== name) {
- const replacements = expToReplacementMap.get(node) || []
- replacements.push({
- name: varName,
- locs: expToVariableMap.get(node)!.reduce(
- (locs, v) => {
- if (v.name === name && v.loc) locs.push(v.loc)
- return locs
- },
- [] as { start: number; end: number }[],
- ),
- })
- expToReplacementMap.set(node, replacements)
- }
- })
-
- if (
- !declarations.some(d => d.name === varName) &&
- (!isIdentifier || shouldDeclareVariable(name, expToVariableMap, exps))
- ) {
- declarations.push({
- name: varName,
- isIdentifier,
- value: extend(
- { ast: isIdentifier ? null : parseExp(context, name) },
- createSimpleExpression(name),
- ),
- rawName: name,
- exps,
- seenCount: seenVariable[name],
- })
- }
- }
- }
-
- for (const [exp, replacements] of expToReplacementMap) {
- replacements
- .flatMap(({ name, locs }) =>
- locs.map(({ start, end }) => ({ start, end, name })),
- )
- .sort((a, b) => b.end - a.end)
- .forEach(({ start, end, name }) => {
- exp.content =
- exp.content.slice(0, start - 1) + name + exp.content.slice(end - 1)
- })
-
- // re-parse the expression
- exp.ast = parseExp(context, exp.content)
- }
-
- return declarations
-}
-
-function shouldDeclareVariable(
- name: string,
- expToVariableMap: Map<
- SimpleExpressionNode,
- Array<{ name: string; loc?: { start: number; end: number } }>
- >,
- exps: Set<SimpleExpressionNode>,
-): boolean {
- const vars = Array.from(exps, exp =>
- expToVariableMap.get(exp)!.map(v => v.name),
- )
- // assume name equals to `foo`
- // if each expression only references `foo`, declaration is needed
- // to avoid reactivity tracking
- // e.g., [[foo],[foo]]
- if (vars.every(v => v.length === 1)) {
- return true
- }
-
- // if `foo` appears multiple times in one array, declaration is needed
- // e.g., [[foo,foo]]
- if (vars.some(v => v.filter(e => e === name).length > 1)) {
- return true
- }
-
- const first = vars[0]
- // if arrays have different lengths, declaration is needed
- // e.g., [[foo],[foo,bar]]
- if (vars.some(v => v.length !== first.length)) {
- // special case, no declaration needed if one array is a subset of the other
- // because they will be treated as repeated expressions
- // e.g., [[foo,bar],[foo,foo,bar]] -> const foo_bar = _ctx.foo + _ctx.bar
- if (
- vars.some(
- v => v.length > first.length && v.every(e => first.includes(e)),
- ) ||
- vars.some(v => first.length > v.length && first.every(e => v.includes(e)))
- ) {
- return false
- }
- return true
- }
- // if arrays share common elements, no declaration needed
- // because they will be treat as repeated expressions
- // e.g., [[foo,bar],[foo,bar]] -> const foo_bar = _ctx.foo + _ctx.bar
- if (vars.some(v => v.some(e => first.includes(e)))) {
- return false
- }
-
- return true
-}
-
-function processRepeatedExpressions(
- context: CodegenContext,
- expressions: SimpleExpressionNode[],
- varDeclarations: DeclarationValue[],
- updatedVariable: Set<string>,
- expToVariableMap: Map<
- SimpleExpressionNode,
- Array<{ name: string; loc?: { start: number; end: number } }>
- >,
-): DeclarationValue[] {
- const declarations: DeclarationValue[] = []
- const seenExp = expressions.reduce(
- (acc, exp) => {
- const variables = expToVariableMap.get(exp)!.map(v => v.name)
- // only handle expressions that are not identifiers
- if (
- exp.ast &&
- exp.ast.type !== 'Identifier' &&
- !(variables && variables.some(v => updatedVariable.has(v)))
- ) {
- acc[exp.content] = (acc[exp.content] || 0) + 1
- }
- return acc
- },
- Object.create(null) as Record<string, number>,
- )
-
- Object.entries(seenExp).forEach(([content, count]) => {
- if (count > 1) {
- // foo + baz -> foo_baz
- const varName = genVarName(content)
- if (!declarations.some(d => d.name === varName)) {
- // if foo and baz have no other references, we don't need to declare separate variables
- // instead of:
- // const foo = _ctx.foo
- // const baz = _ctx.baz
- // const foo_baz = foo + baz
- // we can generate:
- // const foo_baz = _ctx.foo + _ctx.baz
- const delVars: Record<string, string> = {}
- for (let i = varDeclarations.length - 1; i >= 0; i--) {
- const item = varDeclarations[i]
- if (!item.exps || !item.seenCount) continue
-
- const shouldRemove = [...item.exps].every(
- node => node.content === content && item.seenCount === count,
- )
- if (shouldRemove) {
- delVars[item.name] = item.rawName!
- varDeclarations.splice(i, 1)
- }
- }
- const value = extend(
- {},
- expressions.find(exp => exp.content === content)!,
- )
- Object.keys(delVars).forEach(name => {
- value.content = value.content.replace(name, delVars[name])
- if (value.ast) value.ast = parseExp(context, value.content)
- })
- declarations.push({
- name: varName,
- value: value,
- })
- }
-
- // assume content equals to `foo + baz`
- expressions.forEach(exp => {
- // foo + baz -> foo_baz
- if (exp.content === content) {
- exp.content = varName
- // ast is no longer needed since it becomes an identifier.
- exp.ast = null
- }
- // foo + foo + baz -> foo + foo_baz
- else if (exp.content.includes(content)) {
- exp.content = exp.content.replace(
- new RegExp(escapeRegExp(content), 'g'),
- varName,
- )
- // re-parse the expression
- exp.ast = parseExp(context, exp.content)
- }
- })
- }
- })
-
- return declarations
-}
-
-function genDeclarations(
- declarations: DeclarationValue[],
- context: CodegenContext,
-): DeclarationResult {
- const [frag, push] = buildCodeFragment()
- const ids: Record<string, string> = Object.create(null)
-
- // process identifiers first as expressions may rely on them
- declarations.forEach(({ name, isIdentifier, value }) => {
- if (isIdentifier) {
- const varName = (ids[name] = `_${name}`)
- push(`const ${varName} = `, ...genExpression(value, context), NEWLINE)
- }
- })
-
- // process expressions
- declarations.forEach(({ name, isIdentifier, value }) => {
- if (!isIdentifier) {
- const varName = (ids[name] = `_${name}`)
- push(
- `const ${varName} = `,
- ...context.withId(() => genExpression(value, context), ids),
- NEWLINE,
- )
- }
- })
-
- return { ids, frag }
-}
-
-function escapeRegExp(string: string) {
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
-}
-
-function parseExp(context: CodegenContext, content: string): Node {
- const plugins = context.options.expressionPlugins
- const options: ParserOptions = {
- plugins: plugins ? [...plugins, 'typescript'] : ['typescript'],
- }
- return parseExpression(`(${content})`, options)
-}
-
-function genVarName(exp: string): string {
- return `${exp
- .replace(/[^a-zA-Z0-9]/g, '_')
- .replace(/_+/g, '_')
- .replace(/_+$/, '')}`
-}
-
-function extractMemberExpression(
- exp: Node,
- onIdentifier: (id: Identifier) => void,
-): string {
- if (!exp) return ''
- switch (exp.type) {
- case 'Identifier': // foo[bar]
- onIdentifier(exp)
- return exp.name
- case 'StringLiteral': // foo['bar']
- return exp.extra ? (exp.extra.raw as string) : exp.value
- case 'NumericLiteral': // foo[0]
- return exp.value.toString()
- case 'BinaryExpression': // foo[bar + 1]
- return `${extractMemberExpression(exp.left, onIdentifier)} ${exp.operator} ${extractMemberExpression(exp.right, onIdentifier)}`
- case 'CallExpression': // foo[bar(baz)]
- return `${extractMemberExpression(exp.callee, onIdentifier)}(${exp.arguments.map(arg => extractMemberExpression(arg, onIdentifier)).join(', ')})`
- case 'MemberExpression': // foo[bar.baz]
- case 'OptionalMemberExpression': // foo?.bar
- const object = extractMemberExpression(exp.object, onIdentifier)
- const prop = exp.computed
- ? `[${extractMemberExpression(exp.property, onIdentifier)}]`
- : `.${extractMemberExpression(exp.property, NOOP)}`
- return `${object}${prop}`
- default:
- return ''
- }
-}
-
-const isMemberExpression = (node: Node) => {
- return (
- node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression'
- )
-}
+++ /dev/null
-import {
- type SimpleExpressionNode,
- createSimpleExpression,
- walkIdentifiers,
-} from '@vue/compiler-dom'
-import { genBlock } from './block'
-import { genExpression } from './expression'
-import type { CodegenContext } from '../generate'
-import type { ForIRNode } from '../ir'
-import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils'
-import type { Identifier } from '@babel/types'
-import { parseExpression } from '@babel/parser'
-import { VaporVForFlags } from '../../../shared/src/vaporFlags'
-
-export function genFor(
- oper: ForIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- const {
- source,
- value,
- key,
- index,
- render,
- keyProp,
- once,
- id,
- component,
- onlyChild,
- } = oper
-
- let rawValue: string | null = null
- const rawKey = key && key.content
- const rawIndex = index && index.content
-
- const sourceExpr = ['() => (', ...genExpression(source, context), ')']
- const idToPathMap = parseValueDestructure()
-
- const [depth, exitScope] = context.enterScope()
- const idMap: Record<string, string | SimpleExpressionNode | null> = {}
-
- const itemVar = `_for_item${depth}`
- idMap[itemVar] = null
-
- idToPathMap.forEach((pathInfo, id) => {
- let path = `${itemVar}.value${pathInfo ? pathInfo.path : ''}`
- if (pathInfo) {
- if (pathInfo.helper) {
- idMap[pathInfo.helper] = null
- path = `${pathInfo.helper}(${path}, ${pathInfo.helperArgs})`
- }
- if (pathInfo.dynamic) {
- const node = (idMap[id] = createSimpleExpression(path))
- const plugins = context.options.expressionPlugins
- node.ast = parseExpression(`(${path})`, {
- plugins: plugins ? [...plugins, 'typescript'] : ['typescript'],
- })
- } else {
- idMap[id] = path
- }
- } else {
- idMap[id] = path
- }
- })
-
- const args = [itemVar]
- if (rawKey) {
- const keyVar = `_for_key${depth}`
- args.push(`, ${keyVar}`)
- idMap[rawKey] = `${keyVar}.value`
- idMap[keyVar] = null
- }
- if (rawIndex) {
- const indexVar = `_for_index${depth}`
- args.push(`, ${indexVar}`)
- idMap[rawIndex] = `${indexVar}.value`
- idMap[indexVar] = null
- }
-
- const blockFn = context.withId(() => genBlock(render, context, args), idMap)
- exitScope()
-
- let flags = 0
- if (onlyChild) {
- flags |= VaporVForFlags.FAST_REMOVE
- }
- if (component) {
- flags |= VaporVForFlags.IS_COMPONENT
- }
- if (once) {
- flags |= VaporVForFlags.ONCE
- }
-
- return [
- NEWLINE,
- `const n${id} = `,
- ...genCall(
- helper('createFor'),
- sourceExpr,
- blockFn,
- genCallback(keyProp),
- flags ? String(flags) : undefined,
- // todo: hydrationNode
- ),
- ]
-
- // construct a id -> accessor path map.
- // e.g. `{ x: { y: [z] }}` -> `Map{ 'z' => '.x.y[0]' }`
- function parseValueDestructure() {
- const map = new Map<
- string,
- {
- path: string
- dynamic: boolean
- helper?: string
- helperArgs?: string
- } | null
- >()
- if (value) {
- rawValue = value && value.content
- if (value.ast) {
- walkIdentifiers(
- value.ast,
- (id, _, parentStack, ___, isLocal) => {
- if (isLocal) {
- let path = ''
- let isDynamic = false
- let helper
- let helperArgs
- for (let i = 0; i < parentStack.length; i++) {
- const parent = parentStack[i]
- const child = parentStack[i + 1] || id
-
- if (
- parent.type === 'ObjectProperty' &&
- parent.value === child
- ) {
- if (parent.key.type === 'StringLiteral') {
- path += `[${JSON.stringify(parent.key.value)}]`
- } else if (parent.computed) {
- isDynamic = true
- path += `[${value.content.slice(
- parent.key.start! - 1,
- parent.key.end! - 1,
- )}]`
- } else {
- // non-computed, can only be identifier
- path += `.${(parent.key as Identifier).name}`
- }
- } else if (parent.type === 'ArrayPattern') {
- const index = parent.elements.indexOf(child as any)
- if (child.type === 'RestElement') {
- path += `.slice(${index})`
- } else {
- path += `[${index}]`
- }
- } else if (
- parent.type === 'ObjectPattern' &&
- child.type === 'RestElement'
- ) {
- helper = context.helper('getRestElement')
- helperArgs =
- '[' +
- parent.properties
- .filter(p => p.type === 'ObjectProperty')
- .map(p => {
- if (p.key.type === 'StringLiteral') {
- return JSON.stringify(p.key.value)
- } else if (p.computed) {
- isDynamic = true
- return value.content.slice(
- p.key.start! - 1,
- p.key.end! - 1,
- )
- } else {
- return JSON.stringify((p.key as Identifier).name)
- }
- })
- .join(', ') +
- ']'
- }
-
- // default value
- if (
- child.type === 'AssignmentPattern' &&
- (parent.type === 'ObjectProperty' ||
- parent.type === 'ArrayPattern')
- ) {
- isDynamic = true
- helper = context.helper('getDefaultValue')
- helperArgs = value.content.slice(
- child.right.start! - 1,
- child.right.end! - 1,
- )
- }
- }
- map.set(id.name, { path, dynamic: isDynamic, helper, helperArgs })
- }
- },
- true,
- )
- } else {
- map.set(rawValue, null)
- }
- }
- return map
- }
-
- function genCallback(expr: SimpleExpressionNode | undefined) {
- if (!expr) return false
- const res = context.withId(
- () => genExpression(expr, context),
- genSimpleIdMap(),
- )
- return [
- ...genMulti(
- ['(', ')', ', '],
- rawValue ? rawValue : rawKey || rawIndex ? '_' : undefined,
- rawKey ? rawKey : rawIndex ? '__' : undefined,
- rawIndex,
- ),
- ' => (',
- ...res,
- ')',
- ]
- }
-
- function genSimpleIdMap() {
- const idMap: Record<string, null> = {}
- if (rawKey) idMap[rawKey] = null
- if (rawIndex) idMap[rawIndex] = null
- idToPathMap.forEach((_, id) => (idMap[id] = null))
- return idMap
- }
-}
+++ /dev/null
-import type { CodegenContext } from '../generate'
-import type { SetHtmlIRNode } from '../ir'
-import { genExpression } from './expression'
-import { type CodeFragment, NEWLINE, genCall } from './utils'
-
-export function genSetHtml(
- oper: SetHtmlIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- const { value, element } = oper
- return [
- NEWLINE,
- ...genCall(helper('setHtml'), `n${element}`, genExpression(value, context)),
- ]
-}
+++ /dev/null
-import type { CodegenContext } from '../generate'
-import { IRNodeTypes, type IfIRNode } from '../ir'
-import { genBlock } from './block'
-import { genExpression } from './expression'
-import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
-
-export function genIf(
- oper: IfIRNode,
- context: CodegenContext,
- isNested = false,
-): CodeFragment[] {
- const { helper } = context
- const { condition, positive, negative, once } = oper
- const [frag, push] = buildCodeFragment()
-
- const conditionExpr: CodeFragment[] = [
- '() => (',
- ...genExpression(condition, context),
- ')',
- ]
-
- let positiveArg = genBlock(positive, context)
- let negativeArg: false | CodeFragment[] = false
-
- if (negative) {
- if (negative.type === IRNodeTypes.BLOCK) {
- negativeArg = genBlock(negative, context)
- } else {
- negativeArg = ['() => ', ...genIf(negative!, context, true)]
- }
- }
-
- if (!isNested) push(NEWLINE, `const n${oper.id} = `)
- push(
- ...genCall(
- helper('createIf'),
- conditionExpr,
- positiveArg,
- negativeArg,
- once && 'true',
- ),
- )
-
- return frag
-}
+++ /dev/null
-import {
- type IREffect,
- IRNodeTypes,
- type InsertionStateTypes,
- type OperationNode,
- isBlockOperation,
-} from '../ir'
-import type { CodegenContext } from '../generate'
-import { genInsertNode, genPrependNode } from './dom'
-import { genSetDynamicEvents, genSetEvent } from './event'
-import { genFor } from './for'
-import { genSetHtml } from './html'
-import { genIf } from './if'
-import { genDynamicProps, genSetProp } from './prop'
-import { genDeclareOldRef, genSetTemplateRef } from './templateRef'
-import { genGetTextChild, genSetText } from './text'
-import {
- type CodeFragment,
- INDENT_END,
- INDENT_START,
- NEWLINE,
- buildCodeFragment,
- genCall,
-} from './utils'
-import { genCreateComponent } from './component'
-import { genSlotOutlet } from './slotOutlet'
-import { processExpressions } from './expression'
-import { genBuiltinDirective } from './directive'
-
-export function genOperations(
- opers: OperationNode[],
- context: CodegenContext,
-): CodeFragment[] {
- const [frag, push] = buildCodeFragment()
- for (const operation of opers) {
- push(...genOperationWithInsertionState(operation, context))
- }
- return frag
-}
-
-export function genOperationWithInsertionState(
- oper: OperationNode,
- context: CodegenContext,
-): CodeFragment[] {
- const [frag, push] = buildCodeFragment()
- if (isBlockOperation(oper) && oper.parent) {
- push(...genInsertionState(oper, context))
- }
- push(...genOperation(oper, context))
- return frag
-}
-
-export function genOperation(
- oper: OperationNode,
- context: CodegenContext,
-): CodeFragment[] {
- switch (oper.type) {
- case IRNodeTypes.SET_PROP:
- return genSetProp(oper, context)
- case IRNodeTypes.SET_DYNAMIC_PROPS:
- return genDynamicProps(oper, context)
- case IRNodeTypes.SET_TEXT:
- return genSetText(oper, context)
- case IRNodeTypes.SET_EVENT:
- return genSetEvent(oper, context)
- case IRNodeTypes.SET_DYNAMIC_EVENTS:
- return genSetDynamicEvents(oper, context)
- case IRNodeTypes.SET_HTML:
- return genSetHtml(oper, context)
- case IRNodeTypes.SET_TEMPLATE_REF:
- return genSetTemplateRef(oper, context)
- case IRNodeTypes.INSERT_NODE:
- return genInsertNode(oper, context)
- case IRNodeTypes.PREPEND_NODE:
- return genPrependNode(oper, context)
- case IRNodeTypes.IF:
- return genIf(oper, context)
- case IRNodeTypes.FOR:
- return genFor(oper, context)
- case IRNodeTypes.CREATE_COMPONENT_NODE:
- return genCreateComponent(oper, context)
- case IRNodeTypes.DECLARE_OLD_REF:
- return genDeclareOldRef(oper)
- case IRNodeTypes.SLOT_OUTLET_NODE:
- return genSlotOutlet(oper, context)
- case IRNodeTypes.DIRECTIVE:
- return genBuiltinDirective(oper, context)
- case IRNodeTypes.GET_TEXT_CHILD:
- return genGetTextChild(oper, context)
- default:
- const exhaustiveCheck: never = oper
- throw new Error(
- `Unhandled operation type in genOperation: ${exhaustiveCheck}`,
- )
- }
-}
-
-export function genEffects(
- effects: IREffect[],
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- const expressions = effects.flatMap(effect => effect.expressions)
- const [frag, push, unshift] = buildCodeFragment()
- let operationsCount = 0
- const { ids, frag: declarationFrags } = processExpressions(
- context,
- expressions,
- )
- push(...declarationFrags)
- for (let i = 0; i < effects.length; i++) {
- const effect = effects[i]
- operationsCount += effect.operations.length
- const frags = context.withId(() => genEffect(effect, context), ids)
- i > 0 && push(NEWLINE)
- if (frag[frag.length - 1] === ')' && frags[0] === '(') {
- push(';')
- }
- push(...frags)
- }
-
- const newLineCount = frag.filter(frag => frag === NEWLINE).length
- if (newLineCount > 1 || operationsCount > 1 || declarationFrags.length > 0) {
- unshift(`{`, INDENT_START, NEWLINE)
- push(INDENT_END, NEWLINE, '}')
- }
-
- if (effects.length) {
- unshift(NEWLINE, `${helper('renderEffect')}(() => `)
- push(`)`)
- }
-
- return frag
-}
-
-export function genEffect(
- { operations }: IREffect,
- context: CodegenContext,
-): CodeFragment[] {
- const [frag, push] = buildCodeFragment()
- const operationsExps = genOperations(operations, context)
- const newlineCount = operationsExps.filter(frag => frag === NEWLINE).length
-
- if (newlineCount > 1) {
- push(...operationsExps)
- } else {
- push(...operationsExps.filter(frag => frag !== NEWLINE))
- }
-
- return frag
-}
-
-function genInsertionState(
- operation: InsertionStateTypes,
- context: CodegenContext,
-): CodeFragment[] {
- return [
- NEWLINE,
- ...genCall(
- context.helper('setInsertionState'),
- `n${operation.parent}`,
- operation.anchor == null
- ? undefined
- : operation.anchor === -1 // -1 indicates prepend
- ? `0` // runtime anchor value for prepend
- : `n${operation.anchor}`,
- ),
- ]
-}
+++ /dev/null
-import {
- NewlineType,
- type SimpleExpressionNode,
- isSimpleIdentifier,
-} from '@vue/compiler-dom'
-import type { CodegenContext } from '../generate'
-import {
- IRDynamicPropsKind,
- type IRProp,
- type SetDynamicPropsIRNode,
- type SetPropIRNode,
- type VaporHelper,
-} from '../ir'
-import { genExpression } from './expression'
-import {
- type CodeFragment,
- DELIMITERS_ARRAY,
- DELIMITERS_OBJECT,
- NEWLINE,
- genCall,
- genMulti,
-} from './utils'
-import {
- canSetValueDirectly,
- capitalize,
- isSVGTag,
- shouldSetAsAttr,
- toHandlerKey,
-} from '@vue/shared'
-
-export type HelperConfig = {
- name: VaporHelper
- needKey?: boolean
- acceptRoot?: boolean
-}
-
-// this should be kept in sync with runtime-vapor/src/dom/prop.ts
-const helpers = {
- setText: { name: 'setText' },
- setHtml: { name: 'setHtml' },
- setClass: { name: 'setClass' },
- setStyle: { name: 'setStyle' },
- setValue: { name: 'setValue' },
- setAttr: { name: 'setAttr', needKey: true },
- setProp: { name: 'setProp', needKey: true },
- setDOMProp: { name: 'setDOMProp', needKey: true },
- setDynamicProps: { name: 'setDynamicProps' },
-} as const satisfies Partial<Record<VaporHelper, HelperConfig>>
-
-// only the static key prop will reach here
-export function genSetProp(
- oper: SetPropIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- const {
- prop: { key, values, modifier },
- tag,
- } = oper
- const resolvedHelper = getRuntimeHelper(tag, key.content, modifier)
- const propValue = genPropValue(values, context)
- return [
- NEWLINE,
- ...genCall(
- [helper(resolvedHelper.name), null],
- `n${oper.element}`,
- resolvedHelper.needKey ? genExpression(key, context) : false,
- propValue,
- ),
- ]
-}
-
-// dynamic key props and v-bind="{}" will reach here
-export function genDynamicProps(
- oper: SetDynamicPropsIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- const values = oper.props.map(props =>
- Array.isArray(props)
- ? genLiteralObjectProps(props, context) // static and dynamic arg props
- : props.kind === IRDynamicPropsKind.ATTRIBUTE
- ? genLiteralObjectProps([props], context) // dynamic arg props
- : genExpression(props.value, context),
- ) // v-bind=""
- return [
- NEWLINE,
- ...genCall(
- helper('setDynamicProps'),
- `n${oper.element}`,
- genMulti(DELIMITERS_ARRAY, ...values),
- oper.root && 'true',
- ),
- ]
-}
-
-function genLiteralObjectProps(
- props: IRProp[],
- context: CodegenContext,
-): CodeFragment[] {
- return genMulti(
- DELIMITERS_OBJECT,
- ...props.map(prop => [
- ...genPropKey(prop, context),
- `: `,
- ...genPropValue(prop.values, context),
- ]),
- )
-}
-
-export function genPropKey(
- { key: node, modifier, runtimeCamelize, handler, handlerModifiers }: IRProp,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
-
- const handlerModifierPostfix = handlerModifiers
- ? handlerModifiers.map(capitalize).join('')
- : ''
- // static arg was transformed by v-bind transformer
- if (node.isStatic) {
- // only quote keys if necessary
- const keyName =
- (handler ? toHandlerKey(node.content) : node.content) +
- handlerModifierPostfix
- return [
- [
- isSimpleIdentifier(keyName) ? keyName : JSON.stringify(keyName),
- NewlineType.None,
- node.loc,
- ],
- ]
- }
-
- let key = genExpression(node, context)
- if (runtimeCamelize) {
- key = genCall(helper('camelize'), key)
- }
- if (handler) {
- key = genCall(helper('toHandlerKey'), key)
- }
- return [
- '[',
- modifier && `${JSON.stringify(modifier)} + `,
- ...key,
- handlerModifierPostfix
- ? ` + ${JSON.stringify(handlerModifierPostfix)}`
- : undefined,
- ']',
- ]
-}
-
-export function genPropValue(
- values: SimpleExpressionNode[],
- context: CodegenContext,
-): CodeFragment[] {
- if (values.length === 1) {
- return genExpression(values[0], context)
- }
- return genMulti(
- DELIMITERS_ARRAY,
- ...values.map(expr => genExpression(expr, context)),
- )
-}
-
-function getRuntimeHelper(
- tag: string,
- key: string,
- modifier: '.' | '^' | undefined,
-): HelperConfig {
- const tagName = tag.toUpperCase()
- if (modifier) {
- if (modifier === '.') {
- return getSpecialHelper(key, tagName) || helpers.setDOMProp
- } else {
- return helpers.setAttr
- }
- }
-
- // 1. special handling for value / style / class / textContent / innerHTML
- const helper = getSpecialHelper(key, tagName)
- if (helper) {
- return helper
- }
-
- // 2. Aria DOM properties shared between all Elements in
- // https://developer.mozilla.org/en-US/docs/Web/API/Element
- if (/aria[A-Z]/.test(key)) {
- return helpers.setDOMProp
- }
-
- // 3. SVG: always attribute
- if (isSVGTag(tag)) {
- // TODO pass svg flag
- return helpers.setAttr
- }
-
- // 4. respect shouldSetAsAttr used in vdom and setDynamicProp for consistency
- // also fast path for presence of hyphen (covers data-* and aria-*)
- if (shouldSetAsAttr(tagName, key) || key.includes('-')) {
- return helpers.setAttr
- }
-
- // 5. Fallback to setDOMProp, which has a runtime `key in el` check to
- // ensure behavior consistency with vdom
- return helpers.setProp
-}
-
-function getSpecialHelper(
- keyName: string,
- tagName: string,
-): HelperConfig | undefined {
- // special case for 'value' property
- if (keyName === 'value' && canSetValueDirectly(tagName)) {
- return helpers.setValue
- } else if (keyName === 'class') {
- return helpers.setClass
- } else if (keyName === 'style') {
- return helpers.setStyle
- } else if (keyName === 'innerHTML') {
- return helpers.setHtml
- } else if (keyName === 'textContent') {
- return helpers.setText
- }
-}
+++ /dev/null
-import type { CodegenContext } from '../generate'
-import type { SlotOutletIRNode } from '../ir'
-import { genBlock } from './block'
-import { genExpression } from './expression'
-import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
-import { genRawProps } from './component'
-
-export function genSlotOutlet(
- oper: SlotOutletIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- const { id, name, fallback } = oper
- const [frag, push] = buildCodeFragment()
-
- const nameExpr = name.isStatic
- ? genExpression(name, context)
- : ['() => (', ...genExpression(name, context), ')']
-
- let fallbackArg: CodeFragment[] | undefined
- if (fallback) {
- fallbackArg = genBlock(fallback, context)
- }
-
- push(
- NEWLINE,
- `const n${id} = `,
- ...genCall(
- helper('createSlot'),
- nameExpr,
- genRawProps(oper.props, context) || 'null',
- fallbackArg,
- ),
- )
-
- return frag
-}
+++ /dev/null
-import type { CodegenContext } from '../generate'
-import { DynamicFlag, type IRDynamicInfo } from '../ir'
-import { genDirectivesForElement } from './directive'
-import { genOperationWithInsertionState } from './operation'
-import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
-
-export function genTemplates(
- templates: string[],
- rootIndex: number | undefined,
- { helper }: CodegenContext,
-): string {
- return templates
- .map(
- (template, i) =>
- `const t${i} = ${helper('template')}(${JSON.stringify(
- template,
- )}${i === rootIndex ? ', true' : ''})\n`,
- )
- .join('')
-}
-
-export function genSelf(
- dynamic: IRDynamicInfo,
- context: CodegenContext,
-): CodeFragment[] {
- const [frag, push] = buildCodeFragment()
- const { id, template, operation } = dynamic
-
- if (id !== undefined && template !== undefined) {
- push(NEWLINE, `const n${id} = t${template}()`)
- push(...genDirectivesForElement(id, context))
- }
-
- if (operation) {
- push(...genOperationWithInsertionState(operation, context))
- }
-
- return frag
-}
-
-export function genChildren(
- dynamic: IRDynamicInfo,
- context: CodegenContext,
- pushBlock: (...items: CodeFragment[]) => number,
- from: string = `n${dynamic.id}`,
-): CodeFragment[] {
- const { helper } = context
- const [frag, push] = buildCodeFragment()
- const { children } = dynamic
-
- let offset = 0
- let prev: [variable: string, elementIndex: number] | undefined
- const childrenToGen: [IRDynamicInfo, string][] = []
-
- for (const [index, child] of children.entries()) {
- if (child.flags & DynamicFlag.NON_TEMPLATE) {
- offset--
- }
-
- const id =
- child.flags & DynamicFlag.REFERENCED
- ? child.flags & DynamicFlag.INSERT
- ? child.anchor
- : child.id
- : undefined
-
- if (id === undefined && !child.hasDynamicChild) {
- push(...genSelf(child, context))
- continue
- }
-
- const elementIndex = Number(index) + offset
- // p for "placeholder" variables that are meant for possible reuse by
- // other access paths
- const variable = id === undefined ? `p${context.block.tempId++}` : `n${id}`
- pushBlock(NEWLINE, `const ${variable} = `)
-
- if (prev) {
- if (elementIndex - prev[1] === 1) {
- pushBlock(...genCall(helper('next'), prev[0]))
- } else {
- pushBlock(...genCall(helper('nthChild'), from, String(elementIndex)))
- }
- } else {
- if (elementIndex === 0) {
- pushBlock(...genCall(helper('child'), from))
- } else {
- // check if there's a node that we can reuse from
- let init = genCall(helper('child'), from)
- if (elementIndex === 1) {
- init = genCall(helper('next'), init)
- } else if (elementIndex > 1) {
- init = genCall(helper('nthChild'), from, String(elementIndex))
- }
- pushBlock(...init)
- }
- }
-
- if (id === child.anchor) {
- push(...genSelf(child, context))
- }
-
- if (id !== undefined) {
- push(...genDirectivesForElement(id, context))
- }
-
- prev = [variable, elementIndex]
- childrenToGen.push([child, variable])
- }
-
- if (childrenToGen.length) {
- for (const [child, from] of childrenToGen) {
- push(...genChildren(child, context, pushBlock, from))
- }
- }
-
- return frag
-}
+++ /dev/null
-import { genExpression } from './expression'
-import type { CodegenContext } from '../generate'
-import type { DeclareOldRefIRNode, SetTemplateRefIRNode } from '../ir'
-import { type CodeFragment, NEWLINE, genCall } from './utils'
-import { BindingTypes, type SimpleExpressionNode } from '@vue/compiler-dom'
-
-export const setTemplateRefIdent = `_setTemplateRef`
-
-export function genSetTemplateRef(
- oper: SetTemplateRefIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- return [
- NEWLINE,
- oper.effect && `r${oper.element} = `,
- ...genCall(
- setTemplateRefIdent, // will be generated in root scope
- `n${oper.element}`,
- genRefValue(oper.value, context),
- oper.effect ? `r${oper.element}` : oper.refFor ? 'void 0' : undefined,
- oper.refFor && 'true',
- ),
- ]
-}
-
-export function genDeclareOldRef(oper: DeclareOldRefIRNode): CodeFragment[] {
- return [NEWLINE, `let r${oper.id}`]
-}
-
-function genRefValue(value: SimpleExpressionNode, context: CodegenContext) {
- // in inline mode there is no setupState object, so we can't use string
- // keys to set the ref. Instead, we need to transform it to pass the
- // actual ref instead.
- if (!__BROWSER__ && value && context.options.inline) {
- const binding = context.options.bindingMetadata[value.content]
- if (
- binding === BindingTypes.SETUP_LET ||
- binding === BindingTypes.SETUP_REF ||
- binding === BindingTypes.SETUP_MAYBE_REF
- ) {
- return [value.content]
- }
- }
- return genExpression(value, context)
-}
+++ /dev/null
-import type { SimpleExpressionNode } from '@vue/compiler-dom'
-import type { CodegenContext } from '../generate'
-import type { GetTextChildIRNode, SetTextIRNode } from '../ir'
-import { getLiteralExpressionValue } from '../utils'
-import { genExpression } from './expression'
-import { type CodeFragment, NEWLINE, genCall } from './utils'
-
-export function genSetText(
- oper: SetTextIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const { helper } = context
- const { element, values, generated, jsx } = oper
- const texts = combineValues(values, context, jsx)
- return [
- NEWLINE,
- ...genCall(helper('setText'), `${generated ? 'x' : 'n'}${element}`, texts),
- ]
-}
-
-function combineValues(
- values: SimpleExpressionNode[],
- context: CodegenContext,
- jsx?: boolean,
-): CodeFragment[] {
- return values.flatMap((value, i) => {
- let exp = genExpression(value, context)
- if (!jsx && getLiteralExpressionValue(value) == null) {
- // dynamic, wrap with toDisplayString
- exp = genCall(context.helper('toDisplayString'), exp)
- }
- if (i > 0) {
- exp.unshift(jsx ? ', ' : ' + ')
- }
- return exp
- })
-}
-
-export function genGetTextChild(
- oper: GetTextChildIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- return [
- NEWLINE,
- `const x${oper.parent} = ${context.helper('child')}(n${oper.parent})`,
- ]
-}
+++ /dev/null
-import { SourceMapGenerator } from 'source-map-js'
-import {
- type CodegenSourceMapGenerator,
- NewlineType,
- type Position,
- type SourceLocation,
- advancePositionWithMutation,
- locStub,
-} from '@vue/compiler-dom'
-import { isArray, isString } from '@vue/shared'
-import type { CodegenContext } from '../generate'
-
-export const NEWLINE: unique symbol = Symbol(__DEV__ ? `newline` : ``)
-/** increase offset but don't push actual code */
-export const LF: unique symbol = Symbol(__DEV__ ? `line feed` : ``)
-export const INDENT_START: unique symbol = Symbol(__DEV__ ? `indent start` : ``)
-export const INDENT_END: unique symbol = Symbol(__DEV__ ? `indent end` : ``)
-
-type FalsyValue = false | null | undefined
-export type CodeFragment =
- | typeof NEWLINE
- | typeof LF
- | typeof INDENT_START
- | typeof INDENT_END
- | string
- | [code: string, newlineIndex?: number, loc?: SourceLocation, name?: string]
- | FalsyValue
-export type CodeFragments = Exclude<CodeFragment, any[]> | CodeFragment[]
-
-export function buildCodeFragment(
- ...frag: CodeFragment[]
-): [
- CodeFragment[],
- (...items: CodeFragment[]) => number,
- (...items: CodeFragment[]) => number,
-] {
- const push = frag.push.bind(frag)
- const unshift = frag.unshift.bind(frag)
- return [frag, push, unshift]
-}
-
-export type CodeFragmentDelimiters = [
- left: CodeFragments,
- right: CodeFragments,
- delimiter: CodeFragments,
- placeholder?: CodeFragments,
-]
-
-export function genMulti(
- [left, right, seg, placeholder]: CodeFragmentDelimiters,
- ...frags: CodeFragments[]
-): CodeFragment[] {
- if (placeholder) {
- while (frags.length > 0 && !frags[frags.length - 1]) {
- frags.pop()
- }
- frags = frags.map(frag => frag || placeholder)
- } else {
- frags = frags.filter(Boolean)
- }
-
- const frag: CodeFragment[] = []
- push(left)
- for (let [i, fn] of (
- frags as Array<Exclude<CodeFragments, FalsyValue>>
- ).entries()) {
- push(fn)
- if (i < frags.length - 1) push(seg)
- }
- push(right)
- return frag
-
- function push(fn: CodeFragments) {
- if (!isArray(fn)) fn = [fn]
- frag.push(...fn)
- }
-}
-export const DELIMITERS_ARRAY: CodeFragmentDelimiters = ['[', ']', ', ']
-export const DELIMITERS_ARRAY_NEWLINE: CodeFragmentDelimiters = [
- ['[', INDENT_START, NEWLINE],
- [INDENT_END, NEWLINE, ']'],
- [', ', NEWLINE],
-]
-export const DELIMITERS_OBJECT: CodeFragmentDelimiters = ['{ ', ' }', ', ']
-export const DELIMITERS_OBJECT_NEWLINE: CodeFragmentDelimiters = [
- ['{', INDENT_START, NEWLINE],
- [INDENT_END, NEWLINE, '}'],
- [', ', NEWLINE],
-]
-
-export function genCall(
- name: string | [name: string, placeholder?: CodeFragments],
- ...frags: CodeFragments[]
-): CodeFragment[] {
- const hasPlaceholder = isArray(name)
- const fnName = hasPlaceholder ? name[0] : name
- const placeholder = hasPlaceholder ? name[1] : 'null'
- return [fnName, ...genMulti(['(', ')', ', ', placeholder], ...frags)]
-}
-
-export function codeFragmentToString(
- code: CodeFragment[],
- context: CodegenContext,
-): [code: string, map: CodegenSourceMapGenerator | undefined] {
- const {
- options: { filename, sourceMap },
- } = context
-
- let map: CodegenSourceMapGenerator | undefined
- if (sourceMap) {
- // lazy require source-map implementation, only in non-browser builds
- map = new SourceMapGenerator() as unknown as CodegenSourceMapGenerator
- map.setSourceContent(filename, context.ir.source)
- map._sources.add(filename)
- }
-
- let codegen = ''
- const pos = { line: 1, column: 1, offset: 0 }
- let indentLevel = 0
-
- for (let frag of code) {
- if (!frag) continue
-
- if (frag === NEWLINE) {
- frag = [`\n${` `.repeat(indentLevel)}`, NewlineType.Start]
- } else if (frag === INDENT_START) {
- indentLevel++
- continue
- } else if (frag === INDENT_END) {
- indentLevel--
- continue
- } else if (frag === LF) {
- pos.line++
- pos.column = 0
- pos.offset++
- continue
- }
-
- if (isString(frag)) frag = [frag]
-
- let [code, newlineIndex = NewlineType.None, loc, name] = frag
- codegen += code
-
- if (map) {
- if (loc) addMapping(loc.start, name)
- if (newlineIndex === NewlineType.Unknown) {
- // multiple newlines, full iteration
- advancePositionWithMutation(pos, code)
- } else {
- // fast paths
- pos.offset += code.length
- if (newlineIndex === NewlineType.None) {
- // no newlines; fast path to avoid newline detection
- if (__TEST__ && code.includes('\n')) {
- throw new Error(
- `CodegenContext.push() called newlineIndex: none, but contains` +
- `newlines: ${code.replace(/\n/g, '\\n')}`,
- )
- }
- pos.column += code.length
- } else {
- // single newline at known index
- if (newlineIndex === NewlineType.End) {
- newlineIndex = code.length - 1
- }
- if (
- __TEST__ &&
- (code.charAt(newlineIndex) !== '\n' ||
- code.slice(0, newlineIndex).includes('\n') ||
- code.slice(newlineIndex + 1).includes('\n'))
- ) {
- throw new Error(
- `CodegenContext.push() called with newlineIndex: ${newlineIndex} ` +
- `but does not conform: ${code.replace(/\n/g, '\\n')}`,
- )
- }
- pos.line++
- pos.column = code.length - newlineIndex
- }
- }
- if (loc && loc !== locStub) {
- addMapping(loc.end)
- }
- }
- }
-
- return [codegen, map]
-
- function addMapping(loc: Position, name: string | null = null) {
- // we use the private property to directly add the mapping
- // because the addMapping() implementation in source-map-js has a bunch of
- // unnecessary arg and validation checks that are pure overhead in our case.
- const { _names, _mappings } = map!
- if (name !== null && !_names.has(name)) _names.add(name)
- _mappings.add({
- originalLine: loc.line,
- originalColumn: loc.column - 1, // source-map column is 0 based
- generatedLine: pos.line,
- generatedColumn: pos.column - 1,
- source: filename,
- name,
- })
- }
-}
+++ /dev/null
-import type { CodegenContext } from '../generate'
-import type { DirectiveIRNode } from '../ir'
-import { type CodeFragment, NEWLINE, genCall } from './utils'
-import { genExpression } from './expression'
-import type { SimpleExpressionNode } from '@vue/compiler-dom'
-
-const helperMap = {
- text: 'applyTextModel',
- radio: 'applyRadioModel',
- checkbox: 'applyCheckboxModel',
- select: 'applySelectModel',
- dynamic: 'applyDynamicModel',
-} as const
-
-// This is only for built-in v-model on native elements.
-export function genVModel(
- oper: DirectiveIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- const {
- modelType,
- element,
- dir: { exp, modifiers },
- } = oper
-
- return [
- NEWLINE,
- ...genCall(
- context.helper(helperMap[modelType!]),
- `n${element}`,
- // getter
- [`() => (`, ...genExpression(exp!, context), `)`],
- // setter
- genModelHandler(exp!, context),
- // modifiers
- modifiers.length
- ? `{ ${modifiers.map(e => e.content + ': true').join(',')} }`
- : undefined,
- ),
- ]
-}
-
-export function genModelHandler(
- exp: SimpleExpressionNode,
- context: CodegenContext,
-): CodeFragment[] {
- return [
- `${context.options.isTS ? `(_value: any)` : `_value`} => (`,
- ...genExpression(exp, context, '_value'),
- ')',
- ]
-}
+++ /dev/null
-import type { CodegenContext } from '../generate'
-import type { DirectiveIRNode } from '../ir'
-import { genExpression } from './expression'
-import { type CodeFragment, NEWLINE, genCall } from './utils'
-
-export function genVShow(
- oper: DirectiveIRNode,
- context: CodegenContext,
-): CodeFragment[] {
- return [
- NEWLINE,
- ...genCall(context.helper('applyVShow'), `n${oper.element}`, [
- `() => (`,
- ...genExpression(oper.dir.exp!, context),
- `)`,
- ]),
- ]
-}
+++ /dev/null
-export { parse } from '@vue/compiler-dom'
-export {
- transform,
- createStructuralDirectiveTransform,
- type TransformContext,
- type NodeTransform,
- type StructuralDirectiveTransform,
- type DirectiveTransform,
-} from './transform'
-export {
- generate,
- CodegenContext,
- type CodegenOptions,
- type VaporCodegenResult,
-} from './generate'
-export {
- genCall,
- genMulti,
- buildCodeFragment,
- codeFragmentToString,
- type CodeFragment,
-} from './generators/utils'
-export {
- wrapTemplate,
- compile,
- type CompilerOptions,
- type TransformPreset,
-} from './compile'
-export * from './ir'
-export {
- VaporErrorCodes,
- VaporErrorMessages,
- createVaporCompilerError,
- type VaporCompilerError,
-} from './errors'
-
-export { transformElement } from './transforms/transformElement'
-export { transformChildren } from './transforms/transformChildren'
-export { transformTemplateRef } from './transforms/transformTemplateRef'
-export { transformText } from './transforms/transformText'
-export { transformVBind } from './transforms/vBind'
-export { transformVHtml } from './transforms/vHtml'
-export { transformVOn } from './transforms/vOn'
-export { transformVOnce } from './transforms/vOnce'
-export { transformVShow } from './transforms/vShow'
-export { transformVText } from './transforms/vText'
-export { transformVIf } from './transforms/vIf'
-export { transformVFor } from './transforms/vFor'
-export { transformVModel } from './transforms/vModel'
-export { transformComment } from './transforms/transformComment'
-export { transformSlotOutlet } from './transforms/transformSlotOutlet'
-export { transformVSlot } from './transforms/vSlot'
+++ /dev/null
-import type { SimpleExpressionNode } from '@vue/compiler-dom'
-import type { DirectiveTransformResult } from '../transform'
-import type { BlockIRNode, IRFor } from './index'
-
-// props
-export interface IRProp extends Omit<DirectiveTransformResult, 'value'> {
- values: SimpleExpressionNode[]
-}
-
-export enum IRDynamicPropsKind {
- EXPRESSION, // v-bind="value"
- ATTRIBUTE, // v-bind:[foo]="value"
-}
-
-export type IRPropsStatic = IRProp[]
-export interface IRPropsDynamicExpression {
- kind: IRDynamicPropsKind.EXPRESSION
- value: SimpleExpressionNode
- handler?: boolean
-}
-export interface IRPropsDynamicAttribute extends IRProp {
- kind: IRDynamicPropsKind.ATTRIBUTE
-}
-export type IRProps =
- | IRPropsStatic
- | IRPropsDynamicAttribute
- | IRPropsDynamicExpression
-
-// slots
-export interface SlotBlockIRNode extends BlockIRNode {
- props?: SimpleExpressionNode
-}
-
-export enum IRSlotType {
- STATIC,
- DYNAMIC,
- LOOP,
- CONDITIONAL,
- EXPRESSION, // JSX only
-}
-export type IRSlotsStatic = {
- slotType: IRSlotType.STATIC
- slots: Record<string, SlotBlockIRNode>
-}
-export interface IRSlotDynamicBasic {
- slotType: IRSlotType.DYNAMIC
- name: SimpleExpressionNode
- fn: SlotBlockIRNode
-}
-export interface IRSlotDynamicLoop {
- slotType: IRSlotType.LOOP
- name: SimpleExpressionNode
- fn: SlotBlockIRNode
- loop: IRFor
-}
-export interface IRSlotDynamicConditional {
- slotType: IRSlotType.CONDITIONAL
- condition: SimpleExpressionNode
- positive: IRSlotDynamicBasic
- negative?: IRSlotDynamicBasic | IRSlotDynamicConditional
-}
-export interface IRSlotsExpression {
- slotType: IRSlotType.EXPRESSION
- slots: SimpleExpressionNode
-}
-
-export type IRSlotDynamic =
- | IRSlotDynamicBasic
- | IRSlotDynamicLoop
- | IRSlotDynamicConditional
-export type IRSlots = IRSlotsStatic | IRSlotDynamic | IRSlotsExpression
+++ /dev/null
-import type {
- CompoundExpressionNode,
- DirectiveNode,
- RootNode,
- SimpleExpressionNode,
- TemplateChildNode,
-} from '@vue/compiler-dom'
-import type { Prettify } from '@vue/shared'
-import type { DirectiveTransform, NodeTransform } from '../transform'
-import type { IRProp, IRProps, IRSlots } from './component'
-
-export * from './component'
-
-export enum IRNodeTypes {
- ROOT,
- BLOCK,
-
- SET_PROP,
- SET_DYNAMIC_PROPS,
- SET_TEXT,
- SET_EVENT,
- SET_DYNAMIC_EVENTS,
- SET_HTML,
- SET_TEMPLATE_REF,
-
- INSERT_NODE,
- PREPEND_NODE,
- CREATE_COMPONENT_NODE,
- SLOT_OUTLET_NODE,
-
- DIRECTIVE,
- DECLARE_OLD_REF, // consider make it more general
-
- IF,
- FOR,
-
- GET_TEXT_CHILD,
-}
-
-export interface BaseIRNode {
- type: IRNodeTypes
-}
-
-export type CoreHelper = keyof typeof import('packages/runtime-dom/src')
-
-export type VaporHelper = keyof typeof import('packages/runtime-vapor/src')
-
-export interface BlockIRNode extends BaseIRNode {
- type: IRNodeTypes.BLOCK
- node: RootNode | TemplateChildNode
- dynamic: IRDynamicInfo
- tempId: number
- effect: IREffect[]
- operation: OperationNode[]
- returns: number[]
-}
-
-export interface RootIRNode {
- type: IRNodeTypes.ROOT
- node: RootNode
- source: string
- template: string[]
- rootTemplateIndex?: number
- component: Set<string>
- directive: Set<string>
- block: BlockIRNode
- hasTemplateRef: boolean
-}
-
-export interface IfIRNode extends BaseIRNode {
- type: IRNodeTypes.IF
- id: number
- condition: SimpleExpressionNode
- positive: BlockIRNode
- negative?: BlockIRNode | IfIRNode
- once?: boolean
- parent?: number
- anchor?: number
-}
-
-export interface IRFor {
- source: SimpleExpressionNode
- value?: SimpleExpressionNode
- key?: SimpleExpressionNode
- index?: SimpleExpressionNode
-}
-
-export interface ForIRNode extends BaseIRNode, IRFor {
- type: IRNodeTypes.FOR
- id: number
- keyProp?: SimpleExpressionNode
- render: BlockIRNode
- once: boolean
- component: boolean
- onlyChild: boolean
- parent?: number
- anchor?: number
-}
-
-export interface SetPropIRNode extends BaseIRNode {
- type: IRNodeTypes.SET_PROP
- element: number
- prop: IRProp
- root: boolean
- tag: string
-}
-
-export interface SetDynamicPropsIRNode extends BaseIRNode {
- type: IRNodeTypes.SET_DYNAMIC_PROPS
- element: number
- props: IRProps[]
- root: boolean
-}
-
-export interface SetDynamicEventsIRNode extends BaseIRNode {
- type: IRNodeTypes.SET_DYNAMIC_EVENTS
- element: number
- event: SimpleExpressionNode
-}
-
-export interface SetTextIRNode extends BaseIRNode {
- type: IRNodeTypes.SET_TEXT
- element: number
- values: SimpleExpressionNode[]
- generated?: boolean // whether this is a generated empty text node by `processTextLikeContainer`
- jsx?: boolean
-}
-
-export type KeyOverride = [find: string, replacement: string]
-export interface SetEventIRNode extends BaseIRNode {
- type: IRNodeTypes.SET_EVENT
- element: number
- key: SimpleExpressionNode
- value?: SimpleExpressionNode
- modifiers: {
- // modifiers for addEventListener() options, e.g. .passive & .capture
- options: string[]
- // modifiers that needs runtime guards, withKeys
- keys: string[]
- // modifiers that needs runtime guards, withModifiers
- nonKeys: string[]
- }
- keyOverride?: KeyOverride
- delegate: boolean
- /** Whether it's in effect */
- effect: boolean
-}
-
-export interface SetHtmlIRNode extends BaseIRNode {
- type: IRNodeTypes.SET_HTML
- element: number
- value: SimpleExpressionNode
-}
-
-export interface SetTemplateRefIRNode extends BaseIRNode {
- type: IRNodeTypes.SET_TEMPLATE_REF
- element: number
- value: SimpleExpressionNode
- refFor: boolean
- effect: boolean
-}
-
-export interface InsertNodeIRNode extends BaseIRNode {
- type: IRNodeTypes.INSERT_NODE
- elements: number[]
- parent: number
- anchor?: number
-}
-
-export interface PrependNodeIRNode extends BaseIRNode {
- type: IRNodeTypes.PREPEND_NODE
- elements: number[]
- parent: number
-}
-
-export interface DirectiveIRNode extends BaseIRNode {
- type: IRNodeTypes.DIRECTIVE
- element: number
- dir: VaporDirectiveNode
- name: string
- builtin?: boolean
- asset?: boolean
- modelType?: 'text' | 'dynamic' | 'radio' | 'checkbox' | 'select'
-}
-
-export interface CreateComponentIRNode extends BaseIRNode {
- type: IRNodeTypes.CREATE_COMPONENT_NODE
- id: number
- tag: string
- props: IRProps[]
- slots: IRSlots[]
- asset: boolean
- root: boolean
- once: boolean
- dynamic?: SimpleExpressionNode
- parent?: number
- anchor?: number
-}
-
-export interface DeclareOldRefIRNode extends BaseIRNode {
- type: IRNodeTypes.DECLARE_OLD_REF
- id: number
-}
-
-export interface SlotOutletIRNode extends BaseIRNode {
- type: IRNodeTypes.SLOT_OUTLET_NODE
- id: number
- name: SimpleExpressionNode
- props: IRProps[]
- fallback?: BlockIRNode
- parent?: number
- anchor?: number
-}
-
-export interface GetTextChildIRNode extends BaseIRNode {
- type: IRNodeTypes.GET_TEXT_CHILD
- parent: number
-}
-
-export type IRNode = OperationNode | RootIRNode
-export type OperationNode =
- | SetPropIRNode
- | SetDynamicPropsIRNode
- | SetTextIRNode
- | SetEventIRNode
- | SetDynamicEventsIRNode
- | SetHtmlIRNode
- | SetTemplateRefIRNode
- | InsertNodeIRNode
- | PrependNodeIRNode
- | DirectiveIRNode
- | IfIRNode
- | ForIRNode
- | CreateComponentIRNode
- | DeclareOldRefIRNode
- | SlotOutletIRNode
- | GetTextChildIRNode
-
-export enum DynamicFlag {
- NONE = 0,
- /**
- * This node is referenced and needs to be saved as a variable.
- */
- REFERENCED = 1,
- /**
- * This node is not generated from template, but is generated dynamically.
- */
- NON_TEMPLATE = 1 << 1,
- /**
- * This node needs to be inserted back into the template.
- */
- INSERT = 1 << 2,
-}
-
-export interface IRDynamicInfo {
- id?: number
- flags: DynamicFlag
- anchor?: number
- children: IRDynamicInfo[]
- template?: number
- hasDynamicChild?: boolean
- operation?: OperationNode
-}
-
-export interface IREffect {
- expressions: SimpleExpressionNode[]
- operations: OperationNode[]
-}
-
-type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> &
- Pick<U, Extract<keyof U, keyof T>>
-
-export type HackOptions<T> = Prettify<
- Overwrite<
- T,
- {
- nodeTransforms?: NodeTransform[]
- directiveTransforms?: Record<string, DirectiveTransform | undefined>
- }
- >
->
-
-export type VaporDirectiveNode = Overwrite<
- DirectiveNode,
- {
- exp: Exclude<DirectiveNode['exp'], CompoundExpressionNode>
- arg: Exclude<DirectiveNode['arg'], CompoundExpressionNode>
- }
->
-
-export type InsertionStateTypes =
- | IfIRNode
- | ForIRNode
- | SlotOutletIRNode
- | CreateComponentIRNode
-
-export function isBlockOperation(op: OperationNode): op is InsertionStateTypes {
- const type = op.type
- return (
- type === IRNodeTypes.CREATE_COMPONENT_NODE ||
- type === IRNodeTypes.SLOT_OUTLET_NODE ||
- type === IRNodeTypes.IF ||
- type === IRNodeTypes.FOR
- )
-}
+++ /dev/null
-import {
- type AllNode,
- type TransformOptions as BaseTransformOptions,
- type CommentNode,
- type CompilerCompatOptions,
- type ElementNode,
- ElementTypes,
- NodeTypes,
- type RootNode,
- type SimpleExpressionNode,
- type TemplateChildNode,
- defaultOnError,
- defaultOnWarn,
- getSelfName,
- isVSlot,
-} from '@vue/compiler-dom'
-import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
-import {
- type BlockIRNode,
- DynamicFlag,
- type HackOptions,
- type IRDynamicInfo,
- IRNodeTypes,
- type IRSlots,
- type OperationNode,
- type RootIRNode,
- type VaporDirectiveNode,
-} from './ir'
-import { isConstantExpression, isStaticExpression } from './utils'
-import { newBlock, newDynamic } from './transforms/utils'
-
-export type NodeTransform = (
- node: RootNode | TemplateChildNode,
- context: TransformContext<RootNode | TemplateChildNode>,
-) => void | (() => void) | (() => void)[]
-
-export type DirectiveTransform = (
- dir: VaporDirectiveNode,
- node: ElementNode,
- context: TransformContext<ElementNode>,
-) => DirectiveTransformResult | void
-
-export interface DirectiveTransformResult {
- key: SimpleExpressionNode
- value: SimpleExpressionNode
- modifier?: '.' | '^'
- runtimeCamelize?: boolean
- handler?: boolean
- handlerModifiers?: string[]
- model?: boolean
- modelModifiers?: string[]
-}
-
-// A structural directive transform is technically also a NodeTransform;
-// Only v-if and v-for fall into this category.
-export type StructuralDirectiveTransform = (
- node: ElementNode,
- dir: VaporDirectiveNode,
- context: TransformContext<ElementNode>,
-) => void | (() => void)
-
-export type TransformOptions = HackOptions<BaseTransformOptions>
-
-export class TransformContext<T extends AllNode = AllNode> {
- selfName: string | null = null
- parent: TransformContext<RootNode | ElementNode> | null = null
- root: TransformContext<RootNode>
- index: number = 0
-
- block: BlockIRNode = this.ir.block
- options: Required<
- Omit<TransformOptions, 'filename' | keyof CompilerCompatOptions>
- >
-
- template: string = ''
- childrenTemplate: (string | null)[] = []
- dynamic: IRDynamicInfo = this.ir.block.dynamic
-
- inVOnce: boolean = false
- inVFor: number = 0
-
- comment: CommentNode[] = []
- component: Set<string> = this.ir.component
- directive: Set<string> = this.ir.directive
-
- slots: IRSlots[] = []
-
- private globalId = 0
-
- constructor(
- public ir: RootIRNode,
- public node: T,
- options: TransformOptions = {},
- ) {
- this.options = extend({}, defaultOptions, options)
- this.root = this as TransformContext<RootNode>
- if (options.filename) this.selfName = getSelfName(options.filename)
- }
-
- enterBlock(ir: BlockIRNode, isVFor: boolean = false): () => void {
- const { block, template, dynamic, childrenTemplate, slots } = this
- this.block = ir
- this.dynamic = ir.dynamic
- this.template = ''
- this.childrenTemplate = []
- this.slots = []
- isVFor && this.inVFor++
- return () => {
- // exit
- this.registerTemplate()
- this.block = block
- this.template = template
- this.dynamic = dynamic
- this.childrenTemplate = childrenTemplate
- this.slots = slots
- isVFor && this.inVFor--
- }
- }
-
- increaseId = (): number => this.globalId++
- reference(): number {
- if (this.dynamic.id !== undefined) return this.dynamic.id
- this.dynamic.flags |= DynamicFlag.REFERENCED
- return (this.dynamic.id = this.increaseId())
- }
-
- pushTemplate(content: string): number {
- const existing = this.ir.template.findIndex(
- template => template === content,
- )
- if (existing !== -1) return existing
- this.ir.template.push(content)
- return this.ir.template.length - 1
- }
- registerTemplate(): number {
- if (!this.template) return -1
- const id = this.pushTemplate(this.template)
- return (this.dynamic.template = id)
- }
-
- registerEffect(
- expressions: SimpleExpressionNode[],
- operation: OperationNode | OperationNode[],
- getIndex = (): number => this.block.effect.length,
- ): void {
- const operations = [operation].flat()
- expressions = expressions.filter(exp => !isConstantExpression(exp))
- if (
- this.inVOnce ||
- expressions.length === 0 ||
- expressions.every(e =>
- isStaticExpression(e, this.root.options.bindingMetadata),
- )
- ) {
- return this.registerOperation(...operations)
- }
-
- this.block.effect.splice(getIndex(), 0, {
- expressions,
- operations,
- })
- }
-
- registerOperation(...node: OperationNode[]): void {
- this.block.operation.push(...node)
- }
-
- create<T extends TemplateChildNode>(
- node: T,
- index: number,
- ): TransformContext<T> {
- return Object.assign(Object.create(TransformContext.prototype), this, {
- node,
- parent: this as any,
- index,
-
- template: '',
- childrenTemplate: [],
- dynamic: newDynamic(),
- } satisfies Partial<TransformContext<T>>)
- }
-}
-
-const defaultOptions = {
- filename: '',
- prefixIdentifiers: true,
- hoistStatic: false,
- hmr: false,
- cacheHandlers: false,
- nodeTransforms: [],
- directiveTransforms: {},
- transformHoist: null,
- isBuiltInComponent: NOOP,
- isCustomElement: NOOP,
- expressionPlugins: [],
- scopeId: null,
- slotted: true,
- ssr: false,
- inSSR: false,
- ssrCssVars: ``,
- bindingMetadata: EMPTY_OBJ,
- inline: false,
- isTS: false,
- onError: defaultOnError,
- onWarn: defaultOnWarn,
-}
-
-// AST -> IR
-export function transform(
- node: RootNode,
- options: TransformOptions = {},
-): RootIRNode {
- const ir: RootIRNode = {
- type: IRNodeTypes.ROOT,
- node,
- source: node.source,
- template: [],
- component: new Set(),
- directive: new Set(),
- block: newBlock(node),
- hasTemplateRef: false,
- }
-
- const context = new TransformContext(ir, node, options)
-
- transformNode(context)
-
- return ir
-}
-
-export function transformNode(
- context: TransformContext<RootNode | TemplateChildNode>,
-): void {
- let { node } = context
-
- // apply transform plugins
- const { nodeTransforms } = context.options
- const exitFns = []
- for (const nodeTransform of nodeTransforms) {
- const onExit = nodeTransform(node, context)
- if (onExit) {
- if (isArray(onExit)) {
- exitFns.push(...onExit)
- } else {
- exitFns.push(onExit)
- }
- }
- if (!context.node) {
- // node was removed
- return
- } else {
- // node may have been replaced
- node = context.node
- }
- }
-
- // exit transforms
- context.node = node
- let i = exitFns.length
- while (i--) {
- exitFns[i]()
- }
-
- if (context.node.type === NodeTypes.ROOT) {
- context.registerTemplate()
- }
-}
-
-export function createStructuralDirectiveTransform(
- name: string | string[],
- fn: StructuralDirectiveTransform,
-): NodeTransform {
- const matches = (n: string) =>
- isString(name) ? n === name : name.includes(n)
-
- return (node, context) => {
- if (node.type === NodeTypes.ELEMENT) {
- const { props } = node
- // structural directive transforms are not concerned with slots
- // as they are handled separately in vSlot.ts
- if (node.tagType === ElementTypes.TEMPLATE && props.some(isVSlot)) {
- return
- }
- const exitFns = []
- for (const prop of props) {
- if (prop.type === NodeTypes.DIRECTIVE && matches(prop.name)) {
- const onExit = fn(
- node,
- prop as VaporDirectiveNode,
- context as TransformContext<ElementNode>,
- )
- if (onExit) exitFns.push(onExit)
- }
- }
- return exitFns
- }
- }
-}
+++ /dev/null
-import { type ElementNode, ElementTypes, NodeTypes } from '@vue/compiler-dom'
-import {
- type NodeTransform,
- type TransformContext,
- transformNode,
-} from '../transform'
-import {
- DynamicFlag,
- type IRDynamicInfo,
- IRNodeTypes,
- isBlockOperation,
-} from '../ir'
-
-export const transformChildren: NodeTransform = (node, context) => {
- const isFragment =
- node.type === NodeTypes.ROOT ||
- (node.type === NodeTypes.ELEMENT &&
- (node.tagType === ElementTypes.TEMPLATE ||
- node.tagType === ElementTypes.COMPONENT))
-
- if (!isFragment && node.type !== NodeTypes.ELEMENT) return
-
- for (const [i, child] of node.children.entries()) {
- const childContext = context.create(child, i)
- transformNode(childContext)
-
- const childDynamic = childContext.dynamic
-
- if (isFragment) {
- childContext.reference()
- childContext.registerTemplate()
-
- if (
- !(childDynamic.flags & DynamicFlag.NON_TEMPLATE) ||
- childDynamic.flags & DynamicFlag.INSERT
- ) {
- context.block.returns.push(childContext.dynamic.id!)
- }
- } else {
- context.childrenTemplate.push(childContext.template)
- }
-
- if (
- childDynamic.hasDynamicChild ||
- childDynamic.id !== undefined ||
- childDynamic.flags & DynamicFlag.NON_TEMPLATE ||
- childDynamic.flags & DynamicFlag.INSERT
- ) {
- context.dynamic.hasDynamicChild = true
- }
-
- context.dynamic.children[i] = childDynamic
- }
-
- if (!isFragment) {
- processDynamicChildren(context as TransformContext<ElementNode>)
- }
-}
-
-function processDynamicChildren(context: TransformContext<ElementNode>) {
- let prevDynamics: IRDynamicInfo[] = []
- let hasStaticTemplate = false
- const children = context.dynamic.children
-
- for (const [index, child] of children.entries()) {
- if (child.flags & DynamicFlag.INSERT) {
- prevDynamics.push(child)
- }
-
- if (!(child.flags & DynamicFlag.NON_TEMPLATE)) {
- if (prevDynamics.length) {
- if (hasStaticTemplate) {
- context.childrenTemplate[index - prevDynamics.length] = `<!>`
- prevDynamics[0].flags -= DynamicFlag.NON_TEMPLATE
- const anchor = (prevDynamics[0].anchor = context.increaseId())
- registerInsertion(prevDynamics, context, anchor)
- } else {
- registerInsertion(prevDynamics, context, -1 /* prepend */)
- }
- prevDynamics = []
- }
- hasStaticTemplate = true
- }
- }
-
- if (prevDynamics.length) {
- registerInsertion(prevDynamics, context)
- }
-}
-
-function registerInsertion(
- dynamics: IRDynamicInfo[],
- context: TransformContext,
- anchor?: number,
-) {
- for (const child of dynamics) {
- if (child.template != null) {
- // template node due to invalid nesting - generate actual insertion
- context.registerOperation({
- type: IRNodeTypes.INSERT_NODE,
- elements: dynamics.map(child => child.id!),
- parent: context.reference(),
- anchor,
- })
- } else if (child.operation && isBlockOperation(child.operation)) {
- // block types
- child.operation.parent = context.reference()
- child.operation.anchor = anchor
- }
- }
-}
+++ /dev/null
-import {
- type CommentNode,
- type ElementNode,
- NodeTypes,
- type TemplateChildNode,
-} from '@vue/compiler-dom'
-import type { NodeTransform, TransformContext } from '../transform'
-import { DynamicFlag } from '../ir'
-
-export const transformComment: NodeTransform = (node, context) => {
- if (node.type !== NodeTypes.COMMENT) return
-
- if (getSiblingIf(context as TransformContext<CommentNode>)) {
- context.comment.push(node)
- context.dynamic.flags |= DynamicFlag.NON_TEMPLATE
- } else {
- context.template += `<!--${node.content}-->`
- }
-}
-
-export function getSiblingIf(
- context: TransformContext<TemplateChildNode>,
- reverse?: boolean,
-): ElementNode | undefined {
- const parent = context.parent
- if (!parent) return
-
- const siblings = parent.node.children
- let sibling: TemplateChildNode | undefined
- let i = siblings.indexOf(context.node)
- while (reverse ? --i >= 0 : ++i < siblings.length) {
- sibling = siblings[i]
- if (!isCommentLike(sibling)) {
- break
- }
- }
-
- if (
- sibling &&
- sibling.type === NodeTypes.ELEMENT &&
- sibling.props.some(
- ({ type, name }) =>
- type === NodeTypes.DIRECTIVE &&
- ['else-if', reverse ? 'if' : 'else'].includes(name),
- )
- ) {
- return sibling
- }
-}
-
-function isCommentLike(node: TemplateChildNode) {
- return (
- node.type === NodeTypes.COMMENT ||
- (node.type === NodeTypes.TEXT && !node.content.trim().length)
- )
-}
+++ /dev/null
-import { isValidHTMLNesting } from '@vue/compiler-dom'
-import {
- type AttributeNode,
- type ComponentNode,
- type ElementNode,
- ElementTypes,
- ErrorCodes,
- NodeTypes,
- type PlainElementNode,
- type SimpleExpressionNode,
- createCompilerError,
- createSimpleExpression,
- isStaticArgOf,
-} from '@vue/compiler-dom'
-import {
- camelize,
- capitalize,
- extend,
- isBuiltInDirective,
- isVoidTag,
- makeMap,
-} from '@vue/shared'
-import type {
- DirectiveTransformResult,
- NodeTransform,
- TransformContext,
-} from '../transform'
-import {
- DynamicFlag,
- IRDynamicPropsKind,
- IRNodeTypes,
- type IRProp,
- type IRProps,
- type IRPropsDynamicAttribute,
- type IRPropsStatic,
- type VaporDirectiveNode,
-} from '../ir'
-import { EMPTY_EXPRESSION } from './utils'
-import { findProp } from '../utils'
-
-export const isReservedProp: (key: string) => boolean = /*#__PURE__*/ makeMap(
- // the leading comma is intentional so empty string "" is also included
- ',key,ref,ref_for,ref_key,',
-)
-
-export const transformElement: NodeTransform = (node, context) => {
- let effectIndex = context.block.effect.length
- const getEffectIndex = () => effectIndex++
- return function postTransformElement() {
- ;({ node } = context)
- if (
- !(
- node.type === NodeTypes.ELEMENT &&
- (node.tagType === ElementTypes.ELEMENT ||
- node.tagType === ElementTypes.COMPONENT)
- )
- )
- return
-
- const isComponent = node.tagType === ElementTypes.COMPONENT
- const isDynamicComponent = isComponentTag(node.tag)
- const propsResult = buildProps(
- node,
- context as TransformContext<ElementNode>,
- isComponent,
- isDynamicComponent,
- getEffectIndex,
- )
-
- let { parent } = context
- while (
- parent &&
- parent.parent &&
- parent.node.type === NodeTypes.ELEMENT &&
- parent.node.tagType === ElementTypes.TEMPLATE
- ) {
- parent = parent.parent
- }
- const singleRoot =
- context.root === parent &&
- parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
- .length === 1
-
- if (isComponent) {
- transformComponentElement(
- node as ComponentNode,
- propsResult,
- singleRoot,
- context,
- isDynamicComponent,
- )
- } else {
- transformNativeElement(
- node as PlainElementNode,
- propsResult,
- singleRoot,
- context,
- getEffectIndex,
- )
- }
- }
-}
-
-function transformComponentElement(
- node: ComponentNode,
- propsResult: PropsResult,
- singleRoot: boolean,
- context: TransformContext,
- isDynamicComponent: boolean,
-) {
- const dynamicComponent = isDynamicComponent
- ? resolveDynamicComponent(node)
- : undefined
-
- let { tag } = node
- let asset = true
-
- if (!dynamicComponent) {
- const fromSetup = resolveSetupReference(tag, context)
- if (fromSetup) {
- tag = fromSetup
- asset = false
- }
-
- const dotIndex = tag.indexOf('.')
- if (dotIndex > 0) {
- const ns = resolveSetupReference(tag.slice(0, dotIndex), context)
- if (ns) {
- tag = ns + tag.slice(dotIndex)
- asset = false
- }
- }
-
- if (asset) {
- // self referencing component (inferred from filename)
- if (context.selfName && capitalize(camelize(tag)) === context.selfName) {
- // generators/block.ts has special check for __self postfix when generating
- // component imports, which will pass additional `maybeSelfReference` flag
- // to `resolveComponent`.
- tag += `__self`
- }
- context.component.add(tag)
- }
- }
-
- context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
- context.dynamic.operation = {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: context.reference(),
- tag,
- props: propsResult[0] ? propsResult[1] : [propsResult[1]],
- asset,
- root: singleRoot && !context.inVFor,
- slots: [...context.slots],
- once: context.inVOnce,
- dynamic: dynamicComponent,
- }
- context.slots = []
-}
-
-function resolveDynamicComponent(node: ComponentNode) {
- const isProp = findProp(node, 'is', false, true /* allow empty */)
- if (!isProp) return
-
- if (isProp.type === NodeTypes.ATTRIBUTE) {
- return isProp.value && createSimpleExpression(isProp.value.content, true)
- } else {
- return (
- isProp.exp ||
- // #10469 handle :is shorthand
- extend(createSimpleExpression(`is`, false, isProp.arg!.loc), {
- ast: null,
- })
- )
- }
-}
-
-function resolveSetupReference(name: string, context: TransformContext) {
- const bindings = context.options.bindingMetadata
- if (!bindings || bindings.__isScriptSetup === false) {
- return
- }
-
- const camelName = camelize(name)
- const PascalName = capitalize(camelName)
- return bindings[name]
- ? name
- : bindings[camelName]
- ? camelName
- : bindings[PascalName]
- ? PascalName
- : undefined
-}
-
-function transformNativeElement(
- node: PlainElementNode,
- propsResult: PropsResult,
- singleRoot: boolean,
- context: TransformContext,
- getEffectIndex: () => number,
-) {
- const { tag } = node
- const { scopeId } = context.options
-
- let template = ''
-
- template += `<${tag}`
- if (scopeId) template += ` ${scopeId}`
-
- const dynamicProps: string[] = []
- if (propsResult[0] /* dynamic props */) {
- const [, dynamicArgs, expressions] = propsResult
- context.registerEffect(
- expressions,
- {
- type: IRNodeTypes.SET_DYNAMIC_PROPS,
- element: context.reference(),
- props: dynamicArgs,
- root: singleRoot,
- },
- getEffectIndex,
- )
- } else {
- for (const prop of propsResult[1]) {
- const { key, values } = prop
- if (key.isStatic && values.length === 1 && values[0].isStatic) {
- template += ` ${key.content}`
- if (values[0].content) template += `="${values[0].content}"`
- } else {
- dynamicProps.push(key.content)
- context.registerEffect(
- values,
- {
- type: IRNodeTypes.SET_PROP,
- element: context.reference(),
- prop,
- root: singleRoot,
- tag,
- },
- getEffectIndex,
- )
- }
- }
- }
-
- template += `>` + context.childrenTemplate.join('')
- // TODO remove unnecessary close tag, e.g. if it's the last element of the template
- if (!isVoidTag(tag)) {
- template += `</${tag}>`
- }
-
- if (singleRoot) {
- context.ir.rootTemplateIndex = context.ir.template.length
- }
-
- if (
- context.parent &&
- context.parent.node.type === NodeTypes.ELEMENT &&
- !isValidHTMLNesting(context.parent.node.tag, tag)
- ) {
- context.reference()
- context.dynamic.template = context.pushTemplate(template)
- context.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE
- } else {
- context.template += template
- }
-}
-
-export type PropsResult =
- | [dynamic: true, props: IRProps[], expressions: SimpleExpressionNode[]]
- | [dynamic: false, props: IRPropsStatic]
-
-export function buildProps(
- node: ElementNode,
- context: TransformContext<ElementNode>,
- isComponent: boolean,
- isDynamicComponent?: boolean,
- getEffectIndex?: () => number,
-): PropsResult {
- const props = node.props as (VaporDirectiveNode | AttributeNode)[]
- if (props.length === 0) return [false, []]
-
- const dynamicArgs: IRProps[] = []
- const dynamicExpr: SimpleExpressionNode[] = []
- let results: DirectiveTransformResult[] = []
-
- function pushMergeArg() {
- if (results.length) {
- dynamicArgs.push(dedupeProperties(results))
- results = []
- }
- }
-
- for (const prop of props) {
- if (prop.type === NodeTypes.DIRECTIVE && !prop.arg) {
- if (prop.name === 'bind') {
- // v-bind="obj"
- if (prop.exp) {
- dynamicExpr.push(prop.exp)
- pushMergeArg()
- dynamicArgs.push({
- kind: IRDynamicPropsKind.EXPRESSION,
- value: prop.exp,
- })
- } else {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, prop.loc),
- )
- }
- continue
- } else if (prop.name === 'on') {
- // v-on="obj"
- if (prop.exp) {
- if (isComponent) {
- dynamicExpr.push(prop.exp)
- pushMergeArg()
- dynamicArgs.push({
- kind: IRDynamicPropsKind.EXPRESSION,
- value: prop.exp,
- handler: true,
- })
- } else {
- context.registerEffect(
- [prop.exp],
- {
- type: IRNodeTypes.SET_DYNAMIC_EVENTS,
- element: context.reference(),
- event: prop.exp,
- },
- getEffectIndex,
- )
- }
- } else {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, prop.loc),
- )
- }
- continue
- }
- }
-
- // exclude `is` prop for <component>
- if (
- (isDynamicComponent &&
- prop.type === NodeTypes.ATTRIBUTE &&
- prop.name === 'is') ||
- (prop.type === NodeTypes.DIRECTIVE &&
- prop.name === 'bind' &&
- isStaticArgOf(prop.arg, 'is'))
- ) {
- continue
- }
-
- const result = transformProp(prop, node, context)
- if (result) {
- dynamicExpr.push(result.key, result.value)
- if (isComponent && !result.key.isStatic) {
- // v-bind:[name]="value" or v-on:[name]="value"
- pushMergeArg()
- dynamicArgs.push(
- extend(resolveDirectiveResult(result), {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- }) as IRPropsDynamicAttribute,
- )
- } else {
- // other static props
- results.push(result)
- }
- }
- }
-
- // has dynamic key or v-bind="{}"
- if (dynamicArgs.length || results.some(({ key }) => !key.isStatic)) {
- // take rest of props as dynamic props
- pushMergeArg()
- return [true, dynamicArgs, dynamicExpr]
- }
-
- const irProps = dedupeProperties(results)
- return [false, irProps]
-}
-
-function transformProp(
- prop: VaporDirectiveNode | AttributeNode,
- node: ElementNode,
- context: TransformContext<ElementNode>,
-): DirectiveTransformResult | void {
- let { name } = prop
-
- if (prop.type === NodeTypes.ATTRIBUTE) {
- if (isReservedProp(name)) return
- return {
- key: createSimpleExpression(prop.name, true, prop.nameLoc),
- value: prop.value
- ? createSimpleExpression(prop.value.content, true, prop.value.loc)
- : EMPTY_EXPRESSION,
- }
- }
-
- const directiveTransform = context.options.directiveTransforms[name]
- if (directiveTransform) {
- return directiveTransform(prop, node, context)
- }
-
- if (!isBuiltInDirective(name)) {
- const fromSetup = resolveSetupReference(`v-${name}`, context)
- if (fromSetup) {
- name = fromSetup
- } else {
- context.directive.add(name)
- }
-
- context.registerOperation({
- type: IRNodeTypes.DIRECTIVE,
- element: context.reference(),
- dir: prop,
- name,
- asset: !fromSetup,
- })
- }
-}
-
-// Dedupe props in an object literal.
-// Literal duplicated attributes would have been warned during the parse phase,
-// however, it's possible to encounter duplicated `onXXX` handlers with different
-// modifiers. We also need to merge static and dynamic class / style attributes.
-function dedupeProperties(results: DirectiveTransformResult[]): IRProp[] {
- const knownProps: Map<string, IRProp> = new Map()
- const deduped: IRProp[] = []
-
- for (const result of results) {
- const prop = resolveDirectiveResult(result)
- // dynamic keys are always allowed
- if (!prop.key.isStatic) {
- deduped.push(prop)
- continue
- }
- const name = prop.key.content
- const existing = knownProps.get(name)
- if (existing) {
- if (name === 'style' || name === 'class') {
- mergePropValues(existing, prop)
- }
- // unexpected duplicate, should have emitted error during parse
- } else {
- knownProps.set(name, prop)
- deduped.push(prop)
- }
- }
- return deduped
-}
-
-function resolveDirectiveResult(prop: DirectiveTransformResult): IRProp {
- return extend({}, prop, {
- value: undefined,
- values: [prop.value],
- })
-}
-
-function mergePropValues(existing: IRProp, incoming: IRProp) {
- const newValues = incoming.values
- existing.values.push(...newValues)
-}
-
-function isComponentTag(tag: string) {
- return tag === 'component' || tag === 'Component'
-}
+++ /dev/null
-import {
- type AttributeNode,
- type ElementNode,
- ElementTypes,
- ErrorCodes,
- NodeTypes,
- type SimpleExpressionNode,
- createCompilerError,
- createSimpleExpression,
- isStaticArgOf,
- isStaticExp,
-} from '@vue/compiler-dom'
-import type { NodeTransform, TransformContext } from '../transform'
-import {
- type BlockIRNode,
- type DirectiveIRNode,
- DynamicFlag,
- IRNodeTypes,
- type IRProps,
- type VaporDirectiveNode,
-} from '../ir'
-import { camelize, extend } from '@vue/shared'
-import { newBlock } from './utils'
-import { buildProps } from './transformElement'
-
-export const transformSlotOutlet: NodeTransform = (node, context) => {
- if (node.type !== NodeTypes.ELEMENT || node.tag !== 'slot') {
- return
- }
- const id = context.reference()
- context.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE
- const [fallback, exitBlock] = createFallback(
- node,
- context as TransformContext<ElementNode>,
- )
-
- let slotName: SimpleExpressionNode | undefined
- const slotProps: (AttributeNode | VaporDirectiveNode)[] = []
- for (const prop of node.props as (AttributeNode | VaporDirectiveNode)[]) {
- if (prop.type === NodeTypes.ATTRIBUTE) {
- if (prop.value) {
- if (prop.name === 'name') {
- slotName = createSimpleExpression(prop.value.content, true, prop.loc)
- } else {
- slotProps.push(extend({}, prop, { name: camelize(prop.name) }))
- }
- }
- } else if (prop.name === 'bind' && isStaticArgOf(prop.arg, 'name')) {
- if (prop.exp) {
- slotName = prop.exp!
- } else {
- // v-bind shorthand syntax
- slotName = createSimpleExpression(
- camelize(prop.arg!.content),
- false,
- prop.arg!.loc,
- )
- slotName.ast = null
- }
- } else {
- let slotProp = prop
- if (
- slotProp.name === 'bind' &&
- slotProp.arg &&
- isStaticExp(slotProp.arg)
- ) {
- slotProp = extend({}, prop, {
- arg: extend({}, slotProp.arg, {
- content: camelize(slotProp.arg!.content),
- }),
- })
- }
- slotProps.push(slotProp)
- }
- }
-
- slotName ||= createSimpleExpression('default', true)
- let irProps: IRProps[] = []
- if (slotProps.length) {
- const [isDynamic, props] = buildProps(
- extend({}, node, { props: slotProps }),
- context as TransformContext<ElementNode>,
- true,
- )
- irProps = isDynamic ? props : [props]
-
- const runtimeDirective = context.block.operation.find(
- (oper): oper is DirectiveIRNode =>
- oper.type === IRNodeTypes.DIRECTIVE && oper.element === id,
- )
- if (runtimeDirective) {
- context.options.onError(
- createCompilerError(
- ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
- runtimeDirective.dir.loc,
- ),
- )
- }
- }
-
- return () => {
- exitBlock && exitBlock()
- context.dynamic.operation = {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id,
- name: slotName,
- props: irProps,
- fallback,
- }
- }
-}
-
-function createFallback(
- node: ElementNode,
- context: TransformContext<ElementNode>,
-): [block?: BlockIRNode, exit?: () => void] {
- if (!node.children.length) {
- return []
- }
-
- context.node = node = extend({}, node, {
- type: NodeTypes.ELEMENT,
- tag: 'template',
- props: [],
- tagType: ElementTypes.TEMPLATE,
- children: node.children,
- })
-
- const fallback = newBlock(node)
- const exitBlock = context.enterBlock(fallback)
- context.reference()
- return [fallback, exitBlock]
-}
+++ /dev/null
-import {
- NodeTypes,
- type SimpleExpressionNode,
- createSimpleExpression,
-} from '@vue/compiler-dom'
-import type { NodeTransform } from '../transform'
-import { IRNodeTypes } from '../ir'
-import { normalizeBindShorthand } from './vBind'
-import { findProp, isConstantExpression } from '../utils'
-import { EMPTY_EXPRESSION } from './utils'
-
-export const transformTemplateRef: NodeTransform = (node, context) => {
- if (node.type !== NodeTypes.ELEMENT) return
-
- const dir = findProp(node, 'ref', false, true)
- if (!dir) return
-
- context.ir.hasTemplateRef = true
-
- let value: SimpleExpressionNode
- if (dir.type === NodeTypes.DIRECTIVE) {
- value = dir.exp || normalizeBindShorthand(dir.arg!, context)
- } else {
- value = dir.value
- ? createSimpleExpression(dir.value.content, true, dir.value.loc)
- : EMPTY_EXPRESSION
- }
-
- return () => {
- const id = context.reference()
- const effect = !isConstantExpression(value)
- effect &&
- context.registerOperation({
- type: IRNodeTypes.DECLARE_OLD_REF,
- id,
- })
- context.registerEffect([value], {
- type: IRNodeTypes.SET_TEMPLATE_REF,
- element: id,
- value,
- refFor: !!context.inVFor,
- effect,
- })
- }
-}
+++ /dev/null
-import {
- type ElementNode,
- ElementTypes,
- type InterpolationNode,
- NodeTypes,
- type RootNode,
- type SimpleExpressionNode,
- type TemplateChildNode,
- type TextNode,
- createSimpleExpression,
-} from '@vue/compiler-dom'
-import type { NodeTransform, TransformContext } from '../transform'
-import { DynamicFlag, IRNodeTypes } from '../ir'
-import {
- getLiteralExpressionValue,
- isConstantExpression,
- isStaticExpression,
-} from '../utils'
-
-type TextLike = TextNode | InterpolationNode
-const seen = new WeakMap<
- TransformContext<RootNode>,
- WeakSet<TemplateChildNode | RootNode>
->()
-
-export function markNonTemplate(
- node: TemplateChildNode,
- context: TransformContext,
-): void {
- seen.get(context.root)!.add(node)
-}
-
-export const transformText: NodeTransform = (node, context) => {
- if (!seen.has(context.root)) seen.set(context.root, new WeakSet())
- if (seen.get(context.root)!.has(node)) {
- context.dynamic.flags |= DynamicFlag.NON_TEMPLATE
- return
- }
-
- const isFragment =
- node.type === NodeTypes.ROOT ||
- (node.type === NodeTypes.ELEMENT &&
- (node.tagType === ElementTypes.TEMPLATE ||
- node.tagType === ElementTypes.COMPONENT))
-
- if (
- (isFragment ||
- (node.type === NodeTypes.ELEMENT &&
- node.tagType === ElementTypes.ELEMENT)) &&
- node.children.length
- ) {
- let hasInterp = false
- let isAllTextLike = true
- for (const c of node.children) {
- if (c.type === NodeTypes.INTERPOLATION) {
- hasInterp = true
- } else if (c.type !== NodeTypes.TEXT) {
- isAllTextLike = false
- }
- }
- // all text like with interpolation
- if (!isFragment && isAllTextLike && hasInterp) {
- processTextContainer(
- node.children as TextLike[],
- context as TransformContext<ElementNode>,
- )
- } else if (hasInterp) {
- // check if there's any text before interpolation, it needs to be merged
- for (let i = 0; i < node.children.length; i++) {
- const c = node.children[i]
- const prev = node.children[i - 1]
- if (
- c.type === NodeTypes.INTERPOLATION &&
- prev &&
- prev.type === NodeTypes.TEXT
- ) {
- // mark leading text node for skipping
- markNonTemplate(prev, context)
- }
- }
- }
- } else if (node.type === NodeTypes.INTERPOLATION) {
- processInterpolation(context as TransformContext<InterpolationNode>)
- } else if (node.type === NodeTypes.TEXT) {
- context.template += node.content
- }
-}
-
-function processInterpolation(context: TransformContext<InterpolationNode>) {
- const children = context.parent!.node.children
- const nexts = children.slice(context.index)
- const idx = nexts.findIndex(n => !isTextLike(n))
- const nodes = (idx > -1 ? nexts.slice(0, idx) : nexts) as Array<TextLike>
-
- // merge leading text
- const prev = children[context.index - 1]
- if (prev && prev.type === NodeTypes.TEXT) {
- nodes.unshift(prev)
- }
-
- context.template += ' '
- const id = context.reference()
- const values = nodes.map(node => createTextLikeExpression(node, context))
-
- const nonConstantExps = values.filter(v => !isConstantExpression(v))
- const isStatic =
- !nonConstantExps.length ||
- nonConstantExps.every(e =>
- isStaticExpression(e, context.options.bindingMetadata),
- ) ||
- context.inVOnce
-
- if (isStatic) {
- context.registerOperation({
- type: IRNodeTypes.SET_TEXT,
- element: id,
- values,
- })
- } else {
- context.registerEffect(values, {
- type: IRNodeTypes.SET_TEXT,
- element: id,
- values,
- })
- }
-}
-
-function processTextContainer(
- children: TextLike[],
- context: TransformContext<ElementNode>,
-) {
- const values = children.map(child => createTextLikeExpression(child, context))
- const literals = values.map(getLiteralExpressionValue)
- if (literals.every(l => l != null)) {
- context.childrenTemplate = literals.map(l => String(l))
- } else {
- context.childrenTemplate = [' ']
- context.registerOperation({
- type: IRNodeTypes.GET_TEXT_CHILD,
- parent: context.reference(),
- })
- context.registerEffect(values, {
- type: IRNodeTypes.SET_TEXT,
- element: context.reference(),
- values,
- // indicates this node is generated, so prefix should be "x" instead of "n"
- generated: true,
- })
- }
-}
-
-function createTextLikeExpression(node: TextLike, context: TransformContext) {
- markNonTemplate(node, context)
- if (node.type === NodeTypes.TEXT) {
- return createSimpleExpression(node.content, true, node.loc)
- } else {
- return node.content as SimpleExpressionNode
- }
-}
-
-function isTextLike(node: TemplateChildNode): node is TextLike {
- return node.type === NodeTypes.INTERPOLATION || node.type === NodeTypes.TEXT
-}
+++ /dev/null
-import {
- type AttributeNode,
- type DirectiveNode,
- type ElementNode,
- ElementTypes,
- NodeTypes,
- type SimpleExpressionNode,
- type TemplateChildNode,
- type TemplateNode,
- createSimpleExpression,
-} from '@vue/compiler-dom'
-import { extend } from '@vue/shared'
-import {
- type BlockIRNode,
- DynamicFlag,
- type IRDynamicInfo,
- IRNodeTypes,
-} from '../ir'
-
-export const newDynamic = (): IRDynamicInfo => ({
- flags: DynamicFlag.REFERENCED,
- children: [],
-})
-
-export const newBlock = (node: BlockIRNode['node']): BlockIRNode => ({
- type: IRNodeTypes.BLOCK,
- node,
- dynamic: newDynamic(),
- effect: [],
- operation: [],
- returns: [],
- tempId: 0,
-})
-
-export function wrapTemplate(node: ElementNode, dirs: string[]): TemplateNode {
- if (node.tagType === ElementTypes.TEMPLATE) {
- return node
- }
-
- const reserved: Array<AttributeNode | DirectiveNode> = []
- const pass: Array<AttributeNode | DirectiveNode> = []
- node.props.forEach(prop => {
- if (prop.type === NodeTypes.DIRECTIVE && dirs.includes(prop.name)) {
- reserved.push(prop)
- } else {
- pass.push(prop)
- }
- })
-
- return extend({}, node, {
- type: NodeTypes.ELEMENT,
- tag: 'template',
- props: reserved,
- tagType: ElementTypes.TEMPLATE,
- children: [extend({}, node, { props: pass } as TemplateChildNode)],
- } as Partial<TemplateNode>)
-}
-
-export const EMPTY_EXPRESSION: SimpleExpressionNode = createSimpleExpression(
- '',
- true,
-)
+++ /dev/null
-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()) {
- 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
- 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,
- modifier: modifiersString.includes('prop')
- ? '.'
- : modifiersString.includes('attr')
- ? '^'
- : undefined,
- }
-}
+++ /dev/null
-import {
- type ElementNode,
- ElementTypes,
- ErrorCodes,
- type SimpleExpressionNode,
- createCompilerError,
-} from '@vue/compiler-dom'
-import {
- type NodeTransform,
- type TransformContext,
- createStructuralDirectiveTransform,
-} from '../transform'
-import {
- type BlockIRNode,
- DynamicFlag,
- IRNodeTypes,
- type VaporDirectiveNode,
-} from '../ir'
-import { findProp, isStaticExpression, propToExpression } from '../utils'
-import { newBlock, wrapTemplate } from './utils'
-
-export const transformVFor: NodeTransform = createStructuralDirectiveTransform(
- 'for',
- processFor,
-)
-
-export function processFor(
- node: ElementNode,
- dir: VaporDirectiveNode,
- context: TransformContext<ElementNode>,
-) {
- if (!dir.exp) {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_FOR_NO_EXPRESSION, dir.loc),
- )
- return
- }
- const parseResult = dir.forParseResult
- if (!parseResult) {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION, dir.loc),
- )
- return
- }
-
- const { source, value, key, index } = parseResult
-
- const keyProp = findProp(node, 'key')
- const keyProperty = keyProp && propToExpression(keyProp)
- const isComponent = node.tagType === ElementTypes.COMPONENT
- context.node = node = wrapTemplate(node, ['for'])
- context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
- const id = context.reference()
- const render: BlockIRNode = newBlock(node)
- const exitBlock = context.enterBlock(render, true)
- context.reference()
-
- return (): void => {
- exitBlock()
-
- const { parent } = context
-
- // if v-for is the only child of a parent element, it can go the fast path
- // when the entire list is emptied
- const isOnlyChild =
- parent &&
- parent.block.node !== parent.node &&
- parent.node.children.length === 1
-
- context.dynamic.operation = {
- type: IRNodeTypes.FOR,
- id,
- source: source as SimpleExpressionNode,
- value: value as SimpleExpressionNode | undefined,
- key: key as SimpleExpressionNode | undefined,
- index: index as SimpleExpressionNode | undefined,
- keyProp: keyProperty,
- render,
- once:
- context.inVOnce ||
- isStaticExpression(
- source as SimpleExpressionNode,
- context.options.bindingMetadata,
- ),
- component: isComponent,
- onlyChild: !!isOnlyChild,
- }
- }
-}
+++ /dev/null
-import { IRNodeTypes } from '../ir'
-import type { DirectiveTransform } from '../transform'
-import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
-import { EMPTY_EXPRESSION } from './utils'
-
-export const transformVHtml: DirectiveTransform = (dir, node, context) => {
- let { exp, loc } = dir
- if (!exp) {
- context.options.onError(
- createDOMCompilerError(DOMErrorCodes.X_V_HTML_NO_EXPRESSION, loc),
- )
- exp = EMPTY_EXPRESSION
- }
- if (node.children.length) {
- context.options.onError(
- createDOMCompilerError(DOMErrorCodes.X_V_HTML_WITH_CHILDREN, loc),
- )
- context.childrenTemplate.length = 0
- }
-
- context.registerEffect([exp], {
- type: IRNodeTypes.SET_HTML,
- element: context.reference(),
- value: exp,
- })
-}
+++ /dev/null
-import {
- type ElementNode,
- ErrorCodes,
- createCompilerError,
- createSimpleExpression,
-} from '@vue/compiler-dom'
-import {
- type NodeTransform,
- type TransformContext,
- createStructuralDirectiveTransform,
-} from '../transform'
-import {
- type BlockIRNode,
- DynamicFlag,
- IRNodeTypes,
- type VaporDirectiveNode,
-} from '../ir'
-import { extend } from '@vue/shared'
-import { newBlock, wrapTemplate } from './utils'
-import { getSiblingIf } from './transformComment'
-import { isStaticExpression } from '../utils'
-
-export const transformVIf: NodeTransform = createStructuralDirectiveTransform(
- ['if', 'else', 'else-if'],
- processIf,
-)
-
-export function processIf(
- node: ElementNode,
- dir: VaporDirectiveNode,
- context: TransformContext<ElementNode>,
-): (() => void) | undefined {
- if (dir.name !== 'else' && (!dir.exp || !dir.exp.content.trim())) {
- const loc = dir.exp ? dir.exp.loc : node.loc
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc),
- )
- dir.exp = createSimpleExpression(`true`, false, loc)
- }
-
- context.dynamic.flags |= DynamicFlag.NON_TEMPLATE
- if (dir.name === 'if') {
- const id = context.reference()
- context.dynamic.flags |= DynamicFlag.INSERT
- const [branch, onExit] = createIfBranch(node, context)
-
- return () => {
- onExit()
- context.dynamic.operation = {
- type: IRNodeTypes.IF,
- id,
- condition: dir.exp!,
- positive: branch,
- once:
- context.inVOnce ||
- isStaticExpression(dir.exp!, context.options.bindingMetadata),
- }
- }
- } else {
- // check the adjacent v-if
- const siblingIf = getSiblingIf(context, true)
-
- const siblings = context.parent && context.parent.dynamic.children
- let lastIfNode
- if (siblings) {
- let i = siblings.length
- while (i--) {
- if (
- siblings[i].operation &&
- siblings[i].operation!.type === IRNodeTypes.IF
- ) {
- lastIfNode = siblings[i].operation
- break
- }
- }
- }
-
- if (
- // check if v-if is the sibling node
- !siblingIf ||
- // check if IfNode is the last operation and get the root IfNode
- !lastIfNode ||
- lastIfNode.type !== IRNodeTypes.IF
- ) {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc),
- )
- return
- }
-
- while (lastIfNode.negative && lastIfNode.negative.type === IRNodeTypes.IF) {
- lastIfNode = lastIfNode.negative
- }
-
- // Check if v-else was followed by v-else-if
- if (dir.name === 'else-if' && lastIfNode.negative) {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc),
- )
- }
-
- // TODO ignore comments if the v-if is direct child of <transition> (PR #3622)
- if (__DEV__ && context.root.comment.length) {
- node = wrapTemplate(node, ['else-if', 'else'])
- context.node = node = extend({}, node, {
- children: [...context.comment, ...node.children],
- })
- }
- context.root.comment = []
-
- const [branch, onExit] = createIfBranch(node, context)
-
- if (dir.name === 'else') {
- lastIfNode.negative = branch
- } else {
- lastIfNode.negative = {
- type: IRNodeTypes.IF,
- id: -1,
- condition: dir.exp!,
- positive: branch,
- once: context.inVOnce,
- }
- }
-
- return () => onExit()
- }
-}
-
-export function createIfBranch(
- node: ElementNode,
- context: TransformContext<ElementNode>,
-): [BlockIRNode, () => void] {
- context.node = node = wrapTemplate(node, ['if', 'else-if', 'else'])
-
- const branch: BlockIRNode = newBlock(node)
- const exitBlock = context.enterBlock(branch)
- context.reference()
- return [branch, exitBlock]
-}
+++ /dev/null
-import {
- BindingTypes,
- DOMErrorCodes,
- ElementTypes,
- ErrorCodes,
- NodeTypes,
- createCompilerError,
- createDOMCompilerError,
- createSimpleExpression,
- findDir,
- findProp,
- hasDynamicKeyVBind,
- isMemberExpression,
- isStaticArgOf,
-} from '@vue/compiler-dom'
-import type { DirectiveTransform } from '../transform'
-import { type DirectiveIRNode, IRNodeTypes } 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 =
- context.options.inline &&
- (bindingType === BindingTypes.SETUP_LET ||
- bindingType === BindingTypes.SETUP_REF ||
- bindingType === BindingTypes.SETUP_MAYBE_REF)
- if (
- !expString.trim() ||
- (!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 modelType: DirectiveIRNode['modelType'] | undefined = 'text'
- // TODO 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"
- modelType = 'dynamic'
- } else if (type.value) {
- switch (type.value.content) {
- case 'radio':
- modelType = 'radio'
- break
- case 'checkbox':
- modelType = 'checkbox'
- break
- case 'file':
- modelType = 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".
- modelType = 'dynamic'
- } else {
- // text type
- __DEV__ && checkDuplicatedValue()
- }
- } else if (tag === 'select') {
- modelType = 'select'
- } else {
- // textarea
- __DEV__ && checkDuplicatedValue()
- }
- } else {
- context.options.onError(
- createDOMCompilerError(
- DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
- dir.loc,
- ),
- )
- }
-
- if (modelType)
- context.registerOperation({
- type: IRNodeTypes.DIRECTIVE,
- element: context.reference(),
- dir,
- name: 'model',
- modelType,
- 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,
- ),
- )
- }
- }
-}
+++ /dev/null
-import {
- ElementTypes,
- ErrorCodes,
- createCompilerError,
-} from '@vue/compiler-dom'
-import type { DirectiveTransform } from '../transform'
-import { IRNodeTypes, type KeyOverride, type SetEventIRNode } from '../ir'
-import { resolveModifiers } from '@vue/compiler-dom'
-import { extend, makeMap } from '@vue/shared'
-import { resolveExpression } from '../utils'
-import { EMPTY_EXPRESSION } from './utils'
-
-const delegatedEvents = /*#__PURE__*/ makeMap(
- 'beforeinput,click,dblclick,contextmenu,focusin,focusout,input,keydown,' +
- 'keyup,mousedown,mousemove,mouseout,mouseover,mouseup,pointerdown,' +
- 'pointermove,pointerout,pointerover,pointerup,touchend,touchmove,' +
- 'touchstart',
-)
-
-export const transformVOn: DirectiveTransform = (dir, node, context) => {
- let { arg, exp, loc, modifiers } = dir
- const isComponent = node.tagType === ElementTypes.COMPONENT
- const isSlotOutlet = node.tag === 'slot'
-
- if (!exp && !modifiers.length) {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc),
- )
- }
- arg = resolveExpression(arg!)
-
- const { keyModifiers, nonKeyModifiers, eventOptionModifiers } =
- resolveModifiers(
- arg.isStatic ? `on${arg.content}` : arg,
- modifiers,
- null,
- loc,
- )
-
- let keyOverride: KeyOverride | undefined
- const isStaticClick = arg.isStatic && arg.content.toLowerCase() === 'click'
-
- // normalize click.right and click.middle since they don't actually fire
- if (nonKeyModifiers.includes('middle')) {
- if (keyOverride) {
- // TODO error here
- }
- if (isStaticClick) {
- arg = extend({}, arg, { content: 'mouseup' })
- } else if (!arg.isStatic) {
- keyOverride = ['click', 'mouseup']
- }
- }
- if (nonKeyModifiers.includes('right')) {
- if (isStaticClick) {
- arg = extend({}, arg, { content: 'contextmenu' })
- } else if (!arg.isStatic) {
- keyOverride = ['click', 'contextmenu']
- }
- }
-
- if (isComponent || isSlotOutlet) {
- const handler = exp || EMPTY_EXPRESSION
- return {
- key: arg,
- value: handler,
- handler: true,
- handlerModifiers: eventOptionModifiers,
- }
- }
-
- // Only delegate if:
- // - no dynamic event name
- // - no event option modifiers (passive, capture, once)
- // - is a delegatable event
- const delegate =
- arg.isStatic && !eventOptionModifiers.length && delegatedEvents(arg.content)
-
- const operation: SetEventIRNode = {
- type: IRNodeTypes.SET_EVENT,
- element: context.reference(),
- key: arg,
- value: exp,
- modifiers: {
- keys: keyModifiers,
- nonKeys: nonKeyModifiers,
- options: eventOptionModifiers,
- },
- keyOverride,
- delegate,
- effect: !arg.isStatic,
- }
-
- context.registerEffect([arg], operation)
-}
+++ /dev/null
-import { NodeTypes, findDir } from '@vue/compiler-dom'
-import type { NodeTransform } from '../transform'
-
-export const transformVOnce: NodeTransform = (node, context) => {
- if (
- // !context.inSSR &&
- node.type === NodeTypes.ELEMENT &&
- findDir(node, 'once', true)
- ) {
- context.inVOnce = true
- }
-}
+++ /dev/null
-import {
- DOMErrorCodes,
- ElementTypes,
- ErrorCodes,
- createCompilerError,
- createDOMCompilerError,
-} from '@vue/compiler-dom'
-import type { DirectiveTransform } from '../transform'
-import { IRNodeTypes } from '../ir'
-
-export const transformVShow: DirectiveTransform = (dir, node, context) => {
- const { exp, loc } = dir
- if (!exp) {
- context.options.onError(
- createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, loc),
- )
- return
- }
-
- if (node.tagType === ElementTypes.SLOT) {
- context.options.onError(
- createCompilerError(
- ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
- loc,
- ),
- )
- return
- }
-
- context.registerOperation({
- type: IRNodeTypes.DIRECTIVE,
- element: context.reference(),
- dir,
- name: 'show',
- builtin: true,
- })
-}
+++ /dev/null
-import {
- type ElementNode,
- ElementTypes,
- ErrorCodes,
- NodeTypes,
- type SimpleExpressionNode,
- type TemplateChildNode,
- createCompilerError,
- isTemplateNode,
- isVSlot,
-} from '@vue/compiler-dom'
-import type { NodeTransform, TransformContext } from '../transform'
-import { newBlock } from './utils'
-import {
- DynamicFlag,
- type IRFor,
- type IRSlotDynamic,
- type IRSlotDynamicBasic,
- type IRSlotDynamicConditional,
- IRSlotType,
- type IRSlots,
- type IRSlotsStatic,
- type SlotBlockIRNode,
- type VaporDirectiveNode,
-} from '../ir'
-import { findDir, resolveExpression } from '../utils'
-import { markNonTemplate } from './transformText'
-
-export const transformVSlot: NodeTransform = (node, context) => {
- if (node.type !== NodeTypes.ELEMENT) return
-
- const dir = findDir(node, 'slot', true)
- const { tagType, children } = node
- const { parent } = context
-
- const isComponent = tagType === ElementTypes.COMPONENT
- const isSlotTemplate =
- isTemplateNode(node) &&
- parent &&
- parent.node.type === NodeTypes.ELEMENT &&
- parent.node.tagType === ElementTypes.COMPONENT
-
- if (isComponent && children.length) {
- return transformComponentSlot(
- node,
- dir,
- context as TransformContext<ElementNode>,
- )
- } else if (isSlotTemplate && dir) {
- return transformTemplateSlot(
- node,
- dir,
- context as TransformContext<ElementNode>,
- )
- } else if (!isComponent && dir) {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_SLOT_MISPLACED, dir.loc),
- )
- }
-}
-
-// <Foo v-slot:default>
-function transformComponentSlot(
- node: ElementNode,
- dir: VaporDirectiveNode | undefined,
- context: TransformContext<ElementNode>,
-) {
- const { children } = node
- const arg = dir && dir.arg
-
- // whitespace: 'preserve'
- const emptyTextNodes: TemplateChildNode[] = []
- const nonSlotTemplateChildren = children.filter(n => {
- if (isNonWhitespaceContent(n)) {
- return !(n.type === NodeTypes.ELEMENT && n.props.some(isVSlot))
- } else {
- emptyTextNodes.push(n)
- }
- })
- if (!nonSlotTemplateChildren.length) {
- emptyTextNodes.forEach(n => {
- markNonTemplate(n, context)
- })
- }
-
- const [block, onExit] = createSlotBlock(node, dir, context)
-
- const { slots } = context
-
- return () => {
- onExit()
-
- const hasOtherSlots = !!slots.length
- if (dir && hasOtherSlots) {
- // already has on-component slot - this is incorrect usage.
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE, dir.loc),
- )
- return
- }
-
- if (nonSlotTemplateChildren.length) {
- if (hasStaticSlot(slots, 'default')) {
- context.options.onError(
- createCompilerError(
- ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN,
- nonSlotTemplateChildren[0].loc,
- ),
- )
- } else {
- registerSlot(slots, arg, block)
- context.slots = slots
- }
- } else if (hasOtherSlots) {
- context.slots = slots
- }
- }
-}
-
-// <template #foo>
-function transformTemplateSlot(
- node: ElementNode,
- dir: VaporDirectiveNode,
- context: TransformContext<ElementNode>,
-) {
- context.dynamic.flags |= DynamicFlag.NON_TEMPLATE
-
- const arg = dir.arg && resolveExpression(dir.arg)
- const vFor = findDir(node, 'for')
- const vIf = findDir(node, 'if')
- const vElse = findDir(node, /^else(-if)?$/, true /* allowEmpty */)
- const { slots } = context
- const [block, onExit] = createSlotBlock(node, dir, context)
-
- if (!vFor && !vIf && !vElse) {
- const slotName = arg ? arg.isStatic && arg.content : 'default'
- if (slotName && hasStaticSlot(slots, slotName)) {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_SLOT_DUPLICATE_SLOT_NAMES, dir.loc),
- )
- } else {
- registerSlot(slots, arg, block)
- }
- } else if (vIf) {
- registerDynamicSlot(slots, {
- slotType: IRSlotType.CONDITIONAL,
- condition: vIf.exp!,
- positive: {
- slotType: IRSlotType.DYNAMIC,
- name: arg!,
- fn: block,
- },
- })
- } else if (vElse) {
- const vIfSlot = slots[slots.length - 1] as IRSlotDynamic
- if (vIfSlot.slotType === IRSlotType.CONDITIONAL) {
- let ifNode = vIfSlot
- while (
- ifNode.negative &&
- ifNode.negative.slotType === IRSlotType.CONDITIONAL
- )
- ifNode = ifNode.negative
- const negative: IRSlotDynamicBasic | IRSlotDynamicConditional = vElse.exp
- ? {
- slotType: IRSlotType.CONDITIONAL,
- condition: vElse.exp,
- positive: {
- slotType: IRSlotType.DYNAMIC,
- name: arg!,
- fn: block,
- },
- }
- : {
- slotType: IRSlotType.DYNAMIC,
- name: arg!,
- fn: block,
- }
- ifNode.negative = negative
- } else {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, vElse.loc),
- )
- }
- } else if (vFor) {
- if (vFor.forParseResult) {
- registerDynamicSlot(slots, {
- slotType: IRSlotType.LOOP,
- name: arg!,
- fn: block,
- loop: vFor.forParseResult as IRFor,
- })
- } else {
- context.options.onError(
- createCompilerError(ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION, vFor.loc),
- )
- }
- }
-
- return onExit
-}
-
-function ensureStaticSlots(slots: IRSlots[]): IRSlotsStatic['slots'] {
- let lastSlots = slots[slots.length - 1]
- if (!slots.length || lastSlots.slotType !== IRSlotType.STATIC) {
- slots.push(
- (lastSlots = {
- slotType: IRSlotType.STATIC,
- slots: {},
- }),
- )
- }
- return lastSlots.slots
-}
-
-function registerSlot(
- slots: IRSlots[],
- name: SimpleExpressionNode | undefined,
- block: SlotBlockIRNode,
-) {
- const isStatic = !name || name.isStatic
- if (isStatic) {
- const staticSlots = ensureStaticSlots(slots)
- staticSlots[name ? name.content : 'default'] = block
- } else {
- slots.push({
- slotType: IRSlotType.DYNAMIC,
- name: name!,
- fn: block,
- })
- }
-}
-
-function registerDynamicSlot(allSlots: IRSlots[], dynamic: IRSlotDynamic) {
- allSlots.push(dynamic)
-}
-
-function hasStaticSlot(slots: IRSlots[], name: string) {
- return slots.some(slot => {
- if (slot.slotType === IRSlotType.STATIC) return !!slot.slots[name]
- })
-}
-
-function createSlotBlock(
- slotNode: ElementNode,
- dir: VaporDirectiveNode | undefined,
- context: TransformContext<ElementNode>,
-): [SlotBlockIRNode, () => void] {
- const block: SlotBlockIRNode = newBlock(slotNode)
- block.props = dir && dir.exp
- const exitBlock = context.enterBlock(block)
- return [block, exitBlock]
-}
-
-function isNonWhitespaceContent(node: TemplateChildNode): boolean {
- if (node.type !== NodeTypes.TEXT) return true
- return !!node.content.trim()
-}
+++ /dev/null
-import { DOMErrorCodes, createDOMCompilerError } from '@vue/compiler-dom'
-import { IRNodeTypes } from '../ir'
-import { EMPTY_EXPRESSION } from './utils'
-import type { DirectiveTransform } from '../transform'
-import { getLiteralExpressionValue } from '../utils'
-import { isVoidTag } from '../../../shared/src'
-
-export const transformVText: DirectiveTransform = (dir, node, context) => {
- let { exp, loc } = dir
- if (!exp) {
- context.options.onError(
- createDOMCompilerError(DOMErrorCodes.X_V_TEXT_NO_EXPRESSION, loc),
- )
- exp = EMPTY_EXPRESSION
- }
- if (node.children.length) {
- context.options.onError(
- createDOMCompilerError(DOMErrorCodes.X_V_TEXT_WITH_CHILDREN, loc),
- )
- context.childrenTemplate.length = 0
- }
-
- // v-text on void tags do nothing
- if (isVoidTag(context.node.tag)) {
- return
- }
-
- const literal = getLiteralExpressionValue(exp)
- if (literal != null) {
- context.childrenTemplate = [String(literal)]
- } else {
- context.childrenTemplate = [' ']
- context.registerOperation({
- type: IRNodeTypes.GET_TEXT_CHILD,
- parent: context.reference(),
- })
- context.registerEffect([exp], {
- type: IRNodeTypes.SET_TEXT,
- element: context.reference(),
- values: [exp],
- generated: true,
- })
- }
-}
+++ /dev/null
-import type { BigIntLiteral, NumericLiteral, StringLiteral } from '@babel/types'
-import { isGloballyAllowed } from '@vue/shared'
-import {
- type AttributeNode,
- type BindingMetadata,
- BindingTypes,
- type ElementNode,
- NodeTypes,
- type SimpleExpressionNode,
- findDir as _findDir,
- findProp as _findProp,
- createSimpleExpression,
- isConstantNode,
- isLiteralWhitelisted,
-} from '@vue/compiler-dom'
-import type { VaporDirectiveNode } from './ir'
-import { EMPTY_EXPRESSION } from './transforms/utils'
-
-export const findProp = _findProp as (
- node: ElementNode,
- name: string,
- dynamicOnly?: boolean,
- allowEmpty?: boolean,
-) => AttributeNode | VaporDirectiveNode | undefined
-
-/** find directive */
-export const findDir = _findDir as (
- node: ElementNode,
- name: string | RegExp,
- allowEmpty?: boolean,
-) => VaporDirectiveNode | undefined
-
-export function propToExpression(
- prop: AttributeNode | VaporDirectiveNode,
-): SimpleExpressionNode | undefined {
- return prop.type === NodeTypes.ATTRIBUTE
- ? prop.value
- ? createSimpleExpression(prop.value.content, true, prop.value.loc)
- : EMPTY_EXPRESSION
- : prop.exp
-}
-
-export function isConstantExpression(exp: SimpleExpressionNode): boolean {
- return (
- isLiteralWhitelisted(exp.content) ||
- isGloballyAllowed(exp.content) ||
- getLiteralExpressionValue(exp) !== null
- )
-}
-
-export function isStaticExpression(
- node: SimpleExpressionNode,
- bindings: BindingMetadata,
-): boolean {
- if (node.ast) {
- return isConstantNode(node.ast, bindings)
- } else if (node.ast === null) {
- const type = bindings[node.content]
- return type === BindingTypes.LITERAL_CONST
- }
- return false
-}
-
-export function resolveExpression(
- exp: SimpleExpressionNode,
-): SimpleExpressionNode {
- if (!exp.isStatic) {
- const value = getLiteralExpressionValue(exp)
- if (value !== null) {
- return createSimpleExpression('' + value, true, exp.loc)
- }
- }
- return exp
-}
-
-export function getLiteralExpressionValue(
- exp: SimpleExpressionNode,
-): number | string | boolean | null {
- if (exp.ast) {
- if (exp.ast.type === 'StringLiteral') {
- return (exp.ast as StringLiteral | NumericLiteral | BigIntLiteral).value
- } else if (
- exp.ast.type === 'TemplateLiteral' &&
- exp.ast.expressions.length === 0
- ) {
- return exp.ast.quasis[0].value.cooked!
- }
- }
- return exp.isStatic ? exp.content : null
-}
declare var __SSR__: boolean
declare var __VERSION__: string
declare var __COMPAT__: boolean
-declare var __BENCHMARK__: boolean
// Feature flags
declare var __FEATURE_OPTIONS_API__: boolean
})
})
- it('calling on() and off() multiple times inside an active scope should not break currentScope', () => {
- const parentScope = effectScope()
- parentScope.run(() => {
- const childScope = effectScope(true)
- childScope.on()
- childScope.on()
- childScope.off()
- childScope.off()
- childScope.off()
- expect(getCurrentScope()).toBe(parentScope)
- })
- })
-
it('should pause/resume EffectScope', async () => {
const counter = reactive({ num: 0 })
const fnSpy = vi.fn(() => counter.num)
expect(dummyY).toBe(5)
})
+ test('toRefs should warn on plain object', () => {
+ toRefs({})
+ expect(`toRefs() expects a reactive object`).toHaveBeenWarned()
+ })
+
+ test('toRefs should warn on plain array', () => {
+ toRefs([])
+ expect(`toRefs() expects a reactive object`).toHaveBeenWarned()
+ })
+
test('toRefs reactive array', () => {
const arr = reactive(['a', 'b', 'c'])
const refs = toRefs(arr)
return this._onTrigger
},
set(val) {
- if (val && !this._onTrigger) setupFlagsHandler(this)
+ if (!this._onTrigger) setupFlagsHandler(this)
this._onTrigger = val
},
})
*/
private index: number | undefined
- constructor(
- public detached = false,
- parent: EffectScope | undefined = activeEffectScope,
- ) {
- this.parent = parent
- if (!detached && parent) {
- this.index = (parent.scopes || (parent.scopes = [])).push(this) - 1
+ constructor(public detached = false) {
+ this.parent = activeEffectScope
+ if (!detached && activeEffectScope) {
+ this.index =
+ (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
+ this,
+ ) - 1
}
}
import {
type Builtin,
type ShallowReactiveMarker,
+ isProxy,
isReactive,
isReadonly,
isShallow,
toReactive,
} from './reactive'
import { type Dependency, type Link, link, propagate } from './system'
+import { warn } from './warning'
declare const RefSymbol: unique symbol
export declare const RawSymbol: unique symbol
): [T] extends [Ref] ? IfAny<T, Ref<T>, T> : Ref<UnwrapRef<T>, UnwrapRef<T> | T>
export function ref<T = any>(): Ref<T | undefined>
export function ref(value?: unknown) {
- return createRef(value, toReactive)
+ return createRef(value, false)
}
declare const ShallowRefMarker: unique symbol
: ShallowRef<T>
export function shallowRef<T = any>(): ShallowRef<T | undefined>
export function shallowRef(value?: unknown) {
- return createRef(value)
+ return createRef(value, true)
}
-function createRef(rawValue: unknown, wrap?: <T>(v: T) => T) {
+function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
- return new RefImpl(rawValue, wrap)
+ return new RefImpl(rawValue, shallow)
}
/**
subsTail: Link | undefined = undefined
_value: T
- _wrap?: <T>(v: T) => T
private _rawValue: T
public readonly [ReactiveFlags.IS_REF] = true
public readonly [ReactiveFlags.IS_SHALLOW]: boolean = false
- constructor(value: T, wrap: (<T>(v: T) => T) | undefined) {
- this._rawValue = wrap ? toRaw(value) : value
- this._value = wrap ? wrap(value) : value
- this._wrap = wrap
- this[ReactiveFlags.IS_SHALLOW] = !wrap
+ constructor(value: T, isShallow: boolean) {
+ this._rawValue = isShallow ? value : toRaw(value)
+ this._value = isShallow ? value : toReactive(value)
+ this[ReactiveFlags.IS_SHALLOW] = isShallow
}
get dep() {
newValue = useDirectValue ? newValue : toRaw(newValue)
if (hasChanged(newValue, oldValue)) {
this._rawValue = newValue
- this._value =
- this._wrap && !useDirectValue ? this._wrap(newValue) : newValue
+ this._value = useDirectValue ? newValue : toReactive(newValue)
if (__DEV__) {
triggerEventInfos.push({
target: this,
* @see {@link https://vuejs.org/api/reactivity-utilities.html#torefs}
*/
export function toRefs<T extends object>(object: T): ToRefs<T> {
+ if (__DEV__ && !isProxy(object)) {
+ warn(`toRefs() expects a reactive object but received a plain one.`)
+ }
const ret: any = isArray(object) ? new Array(object.length) : {}
for (const key in object) {
ret[key] = propertyToRef(object, key)
)
})
- // #6915
+ // #691ef
test('should not mutate original props long-form definition object', () => {
const props = {
msg: {
withDirectives,
} from '@vue/runtime-test'
import {
- type GenericComponentInstance,
+ type ComponentInternalInstance,
currentInstance,
} from '../src/component'
unmounted,
}
- let _instance: GenericComponentInstance | null = null
+ let _instance: ComponentInternalInstance | null = null
let _vnode: VNode | null = null
let _prevVnode: VNode | null = null
const Comp = {
expect(prevVNode).toBe(_prevVnode)
}) as DirectiveHook)
- let _instance: GenericComponentInstance | null = null
+ let _instance: ComponentInternalInstance | null = null
let _vnode: VNode | null = null
let _prevVnode: VNode | null = null
const Comp = {
unmounted,
}
- let _instance: GenericComponentInstance | null = null
+ let _instance: ComponentInternalInstance | null = null
let _vnode: VNode | null = null
let _prevVnode: VNode | null = null
const Child = {
props: [],
render() {
- return (openBlock(), createBlock('div'))
+ return openBlock(), createBlock('div')
},
}
expect(parentVnode!.el).toBe(childVnode2!.el)
})
- it('should create a component with props', () => {
+ it('should create an Component with props', () => {
const Comp = {
render: () => {
return h('div')
expect(serializeInner(root)).toBe(`<div id="foo" class="bar"></div>`)
})
- it('should create a component with direct text children', () => {
+ it('should create an Component with direct text children', () => {
const Comp = {
render: () => {
return h('div', 'test')
const root = nodeOps.createElement('div')
const renderFn = () => {
- return (openBlock(true), createBlock(Fragment, null))
+ return openBlock(true), createBlock(Fragment, null)
}
render(renderFn(), root)
await nextTick()
expect(calls).toEqual(['cb2', 'cb1'])
})
-
- test('error in postFlush cb should not cause nextTick to stuck in rejected state forever', async () => {
- queuePostFlushCb(() => {
- throw 'err'
- })
- await expect(nextTick).rejects.toThrow('err')
- await expect(nextTick()).resolves.toBeUndefined()
- })
})
openBlock,
transformVNodeArgs,
} from '../src/vnode'
-import { PatchFlags, ShapeFlags } from '@vue/shared'
import type { Data } from '../src/component'
+import { PatchFlags, ShapeFlags } from '@vue/shared'
import { h, isReactive, reactive, ref, setBlockTracking, withCtx } from '../src'
import { createApp, nodeOps, serializeInner } from '@vue/runtime-test'
import { setCurrentRenderingInstance } from '../src/componentRenderContext'
type ComponentInternalInstance,
type ComponentOptions,
type ConcreteComponent,
- type GenericComponentInstance,
currentInstance,
getComponentName,
isInSSRComponentSetup,
) => any
}
-export const isAsyncWrapper = (i: GenericComponentInstance | VNode): boolean =>
+export const isAsyncWrapper = (i: ComponentInternalInstance | VNode): boolean =>
!!(i.type as ComponentOptions).__asyncLoader
/*! #__NO_SIDE_EFFECTS__ */
},
setup() {
- const instance = currentInstance as ComponentInternalInstance
+ const instance = currentInstance!
markAsyncBoundary(instance)
// already resolved
load()
.then(() => {
loaded.value = true
- if (
- instance.parent &&
- instance.parent.vnode &&
- isKeepAlive(instance.parent.vnode)
- ) {
+ if (instance.parent && isKeepAlive(instance.parent.vnode)) {
// parent is keep-alive, force update so the loaded component's
// name is taken into account
- ;(instance.parent as ComponentInternalInstance).update()
+ instance.parent.update()
}
})
.catch(err => {
type ComponentInternalInstance,
type ConcreteComponent,
type Data,
- type GenericComponent,
- type GenericComponentInstance,
+ getComponentPublicInstance,
validateComponentName,
} from './component'
import type {
ComponentPublicInstance,
} from './componentPublicInstance'
import { type Directive, validateDirectiveName } from './directives'
-import type {
- ElementNamespace,
- RootRenderFunction,
- UnmountComponentFn,
-} from './renderer'
+import type { ElementNamespace, RootRenderFunction } from './renderer'
import type { InjectionKey } from './apiInject'
import { warn } from './warning'
-import type { VNode } from './vnode'
+import { type VNode, cloneVNode, createVNode } from './vnode'
+import type { RootHydrateFunction } from './hydration'
import { devtoolsInitApp, devtoolsUnmountApp } from './devtools'
import { NO, extend, hasOwn, isFunction, isObject } from '@vue/shared'
import { version } from '.'
// internal, but we need to expose these for the server-renderer and devtools
_uid: number
- _component: GenericComponent
+ _component: ConcreteComponent
_props: Data | null
_container: HostElement | null
_context: AppContext
- _instance: GenericComponentInstance | null
+ _instance: ComponentInternalInstance | null
/**
* @internal custom element vnode
export type OptionMergeFunction = (to: unknown, from: unknown) => any
-/**
- * Shared app config between vdom and vapor
- */
-export interface GenericAppConfig {
- performance?: boolean
+export interface AppConfig {
+ // @private
+ readonly isNativeTag: (tag: string) => boolean
+
+ performance: boolean
+ optionMergeStrategies: Record<string, OptionMergeFunction>
+ globalProperties: ComponentCustomProperties & Record<string, any>
errorHandler?: (
err: unknown,
instance: ComponentPublicInstance | null,
trace: string,
) => void
- /**
- * Whether to throw unhandled errors in production.
- * Default is `false` to avoid crashing on any error (and only logs it)
- * But in some cases, e.g. SSR, throwing might be more desirable.
- */
- throwUnhandledErrorInProduction?: boolean
-
- /**
- * Prefix for all useId() calls within this app
- */
- idPrefix?: string
-}
-
-export interface AppConfig extends GenericAppConfig {
- // @private
- readonly isNativeTag: (tag: string) => boolean
-
- optionMergeStrategies: Record<string, OptionMergeFunction>
- globalProperties: ComponentCustomProperties & Record<string, any>
-
/**
* Options to pass to `@vue/compiler-dom`.
* Only supported in runtime compiler build.
* @deprecated use config.compilerOptions.isCustomElement
*/
isCustomElement?: (tag: string) => boolean
-}
-
-/**
- * The vapor in vdom implementation is in runtime-vapor/src/vdomInterop.ts
- * @internal
- */
-export interface VaporInteropInterface {
- mount(
- vnode: VNode,
- container: any,
- anchor: any,
- parentComponent: ComponentInternalInstance | null,
- ): GenericComponentInstance // VaporComponentInstance
- update(n1: VNode, n2: VNode, shouldUpdate: boolean): void
- unmount(vnode: VNode, doRemove?: boolean): void
- move(vnode: VNode, container: any, anchor: any): void
- slot(n1: VNode | null, n2: VNode, container: any, anchor: any): void
-
- vdomMount: (component: ConcreteComponent, props?: any, slots?: any) => any
- vdomUnmount: UnmountComponentFn
- vdomSlot: (
- slots: any,
- name: string | (() => string),
- props: Record<string, any>,
- parentComponent: any, // VaporComponentInstance
- fallback?: any, // VaporSlot
- ) => any
-}
-/**
- * Minimal app context shared between vdom and vapor
- */
-export interface GenericAppContext {
- app: App // for devtools
- config: GenericAppConfig
- provides: Record<string | symbol, any>
- components?: Record<string, Component>
- directives?: Record<string, Directive>
/**
- * HMR only
- * @internal
+ * Whether to throw unhandled errors in production.
+ * Default is `false` to avoid crashing on any error (and only logs it)
+ * But in some cases, e.g. SSR, throwing might be more desirable.
*/
- reload?: () => void
+ throwUnhandledErrorInProduction?: boolean
/**
- * @internal vapor interop only
+ * Prefix for all useId() calls within this app
*/
- vapor?: VaporInteropInterface
+ idPrefix?: string
}
-export interface AppContext extends GenericAppContext {
+export interface AppContext {
+ app: App // for devtools
config: AppConfig
+ mixins: ComponentOptions[]
components: Record<string, Component>
directives: Record<string, Directive>
- mixins: ComponentOptions[]
+ provides: Record<string | symbol, any>
/**
* Cache for merged/normalized component options
* @internal
*/
emitsCache: WeakMap<ConcreteComponent, ObjectEmitsOptions | null>
+ /**
+ * HMR only
+ * @internal
+ */
+ reload?: () => void
/**
* v2 compat only
* @internal
}
}
-export type CreateAppFunction<HostElement, Comp = Component> = (
- rootComponent: Comp,
+export type CreateAppFunction<HostElement> = (
+ rootComponent: Component,
rootProps?: Data | null,
) => App<HostElement>
let uid = 0
-export type AppMountFn<HostElement> = (
- app: App,
- rootContainer: HostElement,
- isHydrate?: boolean,
- namespace?: boolean | ElementNamespace,
-) => GenericComponentInstance
-
-export type AppUnmountFn = (app: App) => void
-
-/**
- * @internal
- */
-export function createAppAPI<HostElement, Comp = Component>(
- // render: RootRenderFunction<HostElement>,
- // hydrate?: RootHydrateFunction,
- mount: AppMountFn<HostElement>,
- unmount: AppUnmountFn,
- getPublicInstance: (instance: GenericComponentInstance) => any,
- render?: RootRenderFunction,
-): CreateAppFunction<HostElement, Comp> {
+export function createAppAPI<HostElement>(
+ render: RootRenderFunction<HostElement>,
+ hydrate?: RootHydrateFunction,
+): CreateAppFunction<HostElement> {
return function createApp(rootComponent, rootProps = null) {
if (!isFunction(rootComponent)) {
rootComponent = extend({}, rootComponent)
},
mount(
- rootContainer: HostElement & { __vue_app__?: App },
+ rootContainer: HostElement,
isHydrate?: boolean,
namespace?: boolean | ElementNamespace,
): any {
if (!isMounted) {
// #5571
- if (__DEV__ && rootContainer.__vue_app__) {
+ if (__DEV__ && (rootContainer as any).__vue_app__) {
warn(
`There is already an app instance mounted on the host container.\n` +
` If you want to mount another app on the same host container,` +
` you need to unmount the previous app by calling \`app.unmount()\` first.`,
)
}
- const instance = mount(app, rootContainer, isHydrate, namespace)
+ const vnode = app._ceVNode || createVNode(rootComponent, rootProps)
+ // store app context on the root VNode.
+ // this will be set on the root instance on initial mount.
+ vnode.appContext = context
+
+ if (namespace === true) {
+ namespace = 'svg'
+ } else if (namespace === false) {
+ namespace = undefined
+ }
- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- app._instance = instance
- devtoolsInitApp(app, version)
+ // HMR root reload
+ if (__DEV__) {
+ context.reload = () => {
+ const cloned = cloneVNode(vnode)
+ // avoid hydration for hmr updating
+ cloned.el = null
+ // casting to ElementNamespace because TS doesn't guarantee type narrowing
+ // over function boundaries
+ render(cloned, rootContainer, namespace as ElementNamespace)
+ }
}
+ if (isHydrate && hydrate) {
+ hydrate(vnode as VNode<Node, Element>, rootContainer as any)
+ } else {
+ render(vnode, rootContainer, namespace)
+ }
isMounted = true
app._container = rootContainer
// for devtools and telemetry
- rootContainer.__vue_app__ = app
+ ;(rootContainer as any).__vue_app__ = app
+
+ if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
+ app._instance = vnode.component
+ devtoolsInitApp(app, version)
+ }
- return getPublicInstance(instance)
+ return getComponentPublicInstance(vnode.component!)
} else if (__DEV__) {
warn(
`App has already been mounted.\n` +
app._instance,
ErrorCodes.APP_UNMOUNT_CLEANUP,
)
- unmount(app)
+ render(null, app._container)
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
app._instance = null
devtoolsUnmountApp(app)
})
if (__COMPAT__) {
- installAppCompatProperties(
- app,
- context,
- // vapor doesn't have compat mode so this is always passed
- render!,
- )
+ installAppCompatProperties(app, context, render)
}
return app
import { isFunction } from '@vue/shared'
-import { getCurrentGenericInstance } from './component'
+import { currentInstance } from './component'
+import { currentRenderingInstance } from './componentRenderContext'
import { currentApp } from './apiCreateApp'
import { warn } from './warning'
key: K,
value: K extends InjectionKey<infer V> ? V : T,
): void {
- const currentInstance = getCurrentGenericInstance()
if (!currentInstance) {
if (__DEV__) {
warn(`provide() can only be used inside setup().`)
) {
// fallback to `currentRenderingInstance` so that this can be called in
// a functional component
- const instance = getCurrentGenericInstance()
+ const instance = currentInstance || currentRenderingInstance
// also support looking up from app-level provides w/ `app.runWithContext()`
if (instance || currentApp) {
? currentApp._context.provides
: instance
? instance.parent == null || instance.ce
- ? instance.appContext && instance.appContext.provides
+ ? instance.vnode.appContext && instance.vnode.appContext.provides
: instance.parent.provides
: undefined
* user. One example is `useRoute()` in `vue-router`.
*/
export function hasInjectionContext(): boolean {
- return !!(getCurrentGenericInstance() || currentApp)
+ return !!(currentInstance || currentRenderingInstance || currentApp)
}
import {
- type GenericComponentInstance,
+ type ComponentInternalInstance,
currentInstance,
isInSSRComponentSetup,
setCurrentInstance,
export function injectHook(
type: LifecycleHooks,
hook: Function & { __weh?: Function },
- target: GenericComponentInstance | null = currentInstance,
+ target: ComponentInternalInstance | null = currentInstance,
prepend: boolean = false,
): Function | undefined {
if (target) {
// This assumes the hook does not synchronously trigger other hooks, which
// can only be false when the user does something really funky.
const reset = setCurrentInstance(target)
- try {
- return callWithAsyncErrorHandling(hook, target, type, args)
- } finally {
- reset()
- resetTracking()
- }
+ const res = callWithAsyncErrorHandling(hook, target, type, args)
+ reset()
+ resetTracking()
+ return res
})
if (prepend) {
hooks.unshift(wrappedHook)
<T extends Function = () => any>(lifecycle: LifecycleHooks) =>
(
hook: T,
- target: GenericComponentInstance | null = currentInstance,
+ target: ComponentInternalInstance | null = currentInstance,
): void => {
// post-create lifecycle registrations are noops during SSR (except for serverPrefetch)
if (
}
type CreateHook<T = any> = (
hook: T,
- target?: GenericComponentInstance | null,
+ target?: ComponentInternalInstance | null,
) => void
export const onBeforeMount: CreateHook = createHook(LifecycleHooks.BEFORE_MOUNT)
export function onErrorCaptured<TError = Error>(
hook: ErrorCapturedHook<TError>,
- target: GenericComponentInstance | null = currentInstance,
+ target: ComponentInternalInstance | null = currentInstance,
): void {
injectHook(LifecycleHooks.ERROR_CAPTURED, hook, target)
}
isPromise,
} from '@vue/shared'
import {
- type ComponentInternalInstance,
type SetupContext,
createSetupContext,
- getCurrentGenericInstance,
+ getCurrentInstance,
setCurrentInstance,
unsetCurrentInstance,
} from './component'
return null as any
}
-// TODO return type for Vapor components
export function useSlots(): SetupContext['slots'] {
return getContext().slots
}
}
function getContext(): SetupContext {
- const i = getCurrentGenericInstance()!
+ const i = getCurrentInstance()!
if (__DEV__ && !i) {
warn(`useContext() called without active instance.`)
}
- if (i.vapor) {
- return i as any // vapor instance act as its own setup context
- } else {
- const ii = i as ComponentInternalInstance
- return ii.setupContext || (ii.setupContext = createSetupContext(ii))
- }
+ return i.setupContext || (i.setupContext = createSetupContext(i))
}
/**
* @internal
*/
export function withAsyncContext(getAwaitable: () => any): [any, () => void] {
- const ctx = getCurrentGenericInstance()!
+ const ctx = getCurrentInstance()!
if (__DEV__ && !ctx) {
warn(
`withAsyncContext called without active current instance. ` +
let resolve: (res: LegacyAsyncReturnValue) => void
let reject: (reason?: any) => void
const fallbackPromise = new Promise<Component>((r, rj) => {
- ;((resolve = r), (reject = rj))
+ ;(resolve = r), (reject = rj)
})
const res = comp(resolve!, reject!)
* function simulates that behavior.
*/
app._createRoot = options => {
- const component = app._component as Component
+ const component = app._component
const vnode = createVNode(component, options.propsData || null)
vnode.appContext = context
import {
type AppConfig,
type AppContext,
- type GenericAppContext,
createAppContext,
} from './apiCreateApp'
import { type Directive, validateDirectiveName } from './directives'
NOOP,
ShapeFlags,
extend,
+ getGlobalThis,
isArray,
- isBuiltInTag,
isFunction,
isObject,
isPromise,
+ makeMap,
} from '@vue/shared'
import type { SuspenseBoundary } from './components/Suspense'
import type { CompilerOptions } from '@vue/compiler-core'
import { markAttrsAccessed } from './componentRenderUtils'
+import { currentRenderingInstance } from './componentRenderContext'
import { endMeasure, startMeasure } from './profiling'
import { convertLegacyRenderFn } from './compat/renderFn'
import {
import { markAsyncBoundary } from './helpers/useId'
import { isAsyncWrapper } from './apiAsyncComponent'
import type { RendererElement } from './renderer'
-import {
- setCurrentInstance,
- setInSSRSetupState,
- unsetCurrentInstance,
-} from './componentCurrentInstance'
-
-export * from './componentCurrentInstance'
export type Data = Record<string, unknown>
// Note: can't mark this whole interface internal because some public interfaces
// extend it.
export interface ComponentInternalOptions {
- /**
- * indicates vapor component
- */
- __vapor?: boolean
/**
* @internal
*/
__vccOpts: ComponentOptions
}
-/**
- * Type used where a function accepts both vdom and vapor components.
- */
-export type GenericComponent = (
- | {
- name?: string
- }
- | ((() => any) & { displayName?: string })
-) &
- ComponentInternalOptions
-
/**
* Concrete component type matches its actual value: it's either an options
* object, or a function. Use this where the code expects to work with actual
}
/**
- * Base component instance interface that is shared between vdom mode and vapor
- * mode, so that we can have a mixed instance tree and reuse core logic that
- * operate on both.
+ * We expose a subset of properties on the internal instance as they are
+ * useful for advanced external libraries and tools.
*/
-export interface GenericComponentInstance {
- vapor?: boolean
+export interface ComponentInternalInstance {
uid: number
- type: GenericComponent
- root: GenericComponentInstance | null
- parent: GenericComponentInstance | null
- appContext: GenericAppContext
+ type: ConcreteComponent
+ parent: ComponentInternalInstance | null
+ root: ComponentInternalInstance
+ appContext: AppContext
/**
- * Object containing values this component provides for its descendants
- * @internal
+ * Vnode representing this component in its parent's vdom tree
*/
- provides: Data
+ vnode: VNode
/**
- * Tracking reactive effects (e.g. watchers) associated with this component
- * so that they can be automatically stopped on component unmount
+ * The pending new vnode from parent updates
* @internal
*/
- scope: EffectScope
- /**
- * render function will have different types between vdom and vapor
- */
- render?: Function | null
+ next: VNode | null
/**
- * SSR render function
- * (they are the same between vdom and vapor components.)
- * @internal
+ * Root vnode of this component's own vdom tree
*/
- ssrRender?: Function | null
-
- // state
- props: Data
- attrs: Data
+ subTree: VNode
/**
- * @internal
+ * Render effect instance
*/
- refs: Data
- emit: EmitFn
+ effect: ReactiveEffect
/**
- * used for keeping track of .once event handlers on components
- * @internal
+ * Force update render effect
*/
- emitted: Record<string, boolean> | null
+ update: () => void
/**
- * used for caching the value returned from props default factory functions to
- * avoid unnecessary watcher trigger
- * @internal
+ * Render effect job to be passed to scheduler (checks if dirty)
*/
- propsDefaults: Data | null
+ job: SchedulerJob
/**
- * used for getting the keys of a component's raw props, vapor only
+ * The render function that returns vdom tree.
* @internal
*/
- rawKeys?: () => string[]
-
- // exposed properties via expose()
- exposed: Record<string, any> | null
- exposeProxy: Record<string, any> | null
-
+ render: InternalRenderFunction | null
/**
- * setup related
+ * SSR render function
* @internal
*/
- setupState?: Data
+ ssrRender?: Function | null
/**
- * devtools access to additional info
+ * Object containing values this component provides for its descendants
* @internal
*/
- devtoolsRawSetupState?: any
-
- // lifecycle
- isMounted: boolean
- isUnmounted: boolean
- isDeactivated: boolean
-
+ provides: Data
/**
* for tracking useId()
* first element is the current boundary prefix
* @internal
*/
ids: [string, number, number]
-
- // for vapor the following two are dev only
/**
- * resolved props options
+ * Tracking reactive effects (e.g. watchers) associated with this component
+ * so that they can be automatically stopped on component unmount
* @internal
*/
- propsOptions?: NormalizedPropsOptions
+ scope: EffectScope
/**
- * resolved emits options
+ * cache for proxy access type to avoid hasOwnProperty calls
* @internal
*/
- emitsOptions?: ObjectEmitsOptions | null
-
- /**
- * Public instance proxy, vdom only
- */
- proxy?: any
+ accessCache: Data | null
/**
- * suspense related
+ * cache for render function values that rely on _ctx but won't need updates
+ * after initialized (e.g. inline handlers)
* @internal
*/
- suspense: SuspenseBoundary | null
+ renderCache: (Function | VNode | undefined)[]
- // lifecycle
- /**
- * @internal
- */
- [LifecycleHooks.BEFORE_CREATE]?: LifecycleHook
/**
+ * Resolved component registry, only for components with mixins or extends
* @internal
*/
- [LifecycleHooks.CREATED]?: LifecycleHook
+ components: Record<string, ConcreteComponent> | null
/**
+ * Resolved directive registry, only for components with mixins or extends
* @internal
*/
- [LifecycleHooks.BEFORE_MOUNT]?: LifecycleHook
+ directives: Record<string, Directive> | null
/**
+ * Resolved filters registry, v2 compat only
* @internal
*/
- [LifecycleHooks.MOUNTED]?: LifecycleHook
+ filters?: Record<string, Function>
/**
+ * resolved props options
* @internal
*/
- [LifecycleHooks.BEFORE_UPDATE]?: LifecycleHook
+ propsOptions: NormalizedPropsOptions
/**
+ * resolved emits options
* @internal
*/
- [LifecycleHooks.UPDATED]?: LifecycleHook
+ emitsOptions: ObjectEmitsOptions | null
/**
+ * resolved inheritAttrs options
* @internal
*/
- [LifecycleHooks.BEFORE_UNMOUNT]?: LifecycleHook
+ inheritAttrs?: boolean
/**
+ * Custom Element instance (if component is created by defineCustomElement)
* @internal
*/
- [LifecycleHooks.UNMOUNTED]?: LifecycleHook
+ ce?: ComponentCustomElementInterface
/**
+ * is custom element? (kept only for compatibility)
* @internal
*/
- [LifecycleHooks.RENDER_TRACKED]?: LifecycleHook
+ isCE?: boolean
/**
+ * custom element specific HMR method
* @internal
*/
- [LifecycleHooks.RENDER_TRIGGERED]?: LifecycleHook
+ ceReload?: (newStyles?: string[]) => void
+
+ // the rest are only for stateful components ---------------------------------
+
+ // main proxy that serves as the public instance (`this`)
+ proxy: ComponentPublicInstance | null
+
+ // exposed properties via expose()
+ exposed: Record<string, any> | null
+ exposeProxy: Record<string, any> | null
+
/**
+ * alternative proxy used only for runtime-compiled render functions using
+ * `with` block
* @internal
*/
- [LifecycleHooks.ACTIVATED]?: LifecycleHook
+ withProxy: ComponentPublicInstance | null
/**
+ * This is the target for the public instance proxy. It also holds properties
+ * injected by user options (computed, methods etc.) and user-attached
+ * custom properties (via `this.x = ...`)
* @internal
*/
- [LifecycleHooks.DEACTIVATED]?: LifecycleHook
+ ctx: Data
+
+ // state
+ data: Data
+ props: Data
+ attrs: Data
+ slots: InternalSlots
+ refs: Data
+ emit: EmitFn
+
/**
+ * used for keeping track of .once event handlers on components
* @internal
*/
- [LifecycleHooks.ERROR_CAPTURED]?: LifecycleHook
+ emitted: Record<string, boolean> | null
/**
+ * used for caching the value returned from props default factory functions to
+ * avoid unnecessary watcher trigger
* @internal
*/
- [LifecycleHooks.SERVER_PREFETCH]?: LifecycleHook<() => Promise<unknown>>
+ propsDefaults: Data
/**
- * @internal vapor only
- */
- hmrRerender?: () => void
- /**
- * @internal vapor only
- */
- hmrReload?: (newComp: any) => void
-
- // these only exist on vdom instances
- vnode?: VNode
- subTree?: VNode
-
- /**
- * Custom Element instance (if component is created by defineCustomElement)
+ * setup related
* @internal
*/
- ce?: ComponentCustomElementInterface
+ setupState: Data
/**
- * is custom element? (kept only for compatibility)
+ * devtools access to additional info
* @internal
*/
- isCE?: boolean
+ devtoolsRawSetupState?: any
/**
- * custom element specific HMR method
* @internal
*/
- ceReload?: (newStyles?: string[]) => void
-}
+ setupContext: SetupContext | null
-/**
- * We expose a subset of properties on the internal instance as they are
- * useful for advanced external libraries and tools.
- */
-export interface ComponentInternalInstance extends GenericComponentInstance {
- vapor?: never
- uid: number
- type: ConcreteComponent
- parent: GenericComponentInstance | null
- root: GenericComponentInstance
- appContext: AppContext
- /**
- * Vnode representing this component in its parent's vdom tree
- */
- vnode: VNode
/**
- * The pending new vnode from parent updates
+ * suspense related
* @internal
*/
- next: VNode | null
- /**
- * Root vnode of this component's own vdom tree
- */
- subTree: VNode
- /**
- * Render effect instance
- */
- effect: ReactiveEffect
- /**
- * Force update render effect
- */
- update: () => void
+ suspense: SuspenseBoundary | null
/**
- * Render effect job to be passed to scheduler (checks if dirty)
+ * suspense pending batch id
+ * @internal
*/
- job: SchedulerJob
+ suspenseId: number
/**
- * The render function that returns vdom tree.
* @internal
*/
- render: InternalRenderFunction | null
+ asyncDep: Promise<any> | null
/**
- * cache for proxy access type to avoid hasOwnProperty calls
* @internal
*/
- accessCache: Data | null
+ asyncResolved: boolean
+
+ // lifecycle
+ isMounted: boolean
+ isUnmounted: boolean
+ isDeactivated: boolean
/**
- * cache for render function values that rely on _ctx but won't need updates
- * after initialized (e.g. inline handlers)
* @internal
*/
- renderCache: (Function | VNode | undefined)[]
-
+ [LifecycleHooks.BEFORE_CREATE]: LifecycleHook
/**
- * Resolved component registry, only for components with mixins or extends
* @internal
*/
- components: Record<string, ConcreteComponent> | null
+ [LifecycleHooks.CREATED]: LifecycleHook
/**
- * Resolved directive registry, only for components with mixins or extends
* @internal
*/
- directives: Record<string, Directive> | null
+ [LifecycleHooks.BEFORE_MOUNT]: LifecycleHook
/**
- * Resolved filters registry, v2 compat only
* @internal
*/
- filters?: Record<string, Function>
+ [LifecycleHooks.MOUNTED]: LifecycleHook
/**
- * resolved props options
* @internal
*/
- propsOptions: NormalizedPropsOptions
+ [LifecycleHooks.BEFORE_UPDATE]: LifecycleHook
/**
- * resolved emits options
* @internal
*/
- emitsOptions: ObjectEmitsOptions | null
+ [LifecycleHooks.UPDATED]: LifecycleHook
/**
- * resolved inheritAttrs options
* @internal
*/
- inheritAttrs?: boolean
-
- // the rest are only for stateful components ---------------------------------
+ [LifecycleHooks.BEFORE_UNMOUNT]: LifecycleHook
/**
- * setup related
* @internal
*/
- setupState: Data
+ [LifecycleHooks.UNMOUNTED]: LifecycleHook
/**
* @internal
*/
- setupContext?: SetupContext | null
-
- // main proxy that serves as the public instance (`this`)
- proxy: ComponentPublicInstance | null
-
- data: Data // options API only
- emit: EmitFn
- slots: InternalSlots
-
- exposeProxy: Record<string, any> | null
-
+ [LifecycleHooks.RENDER_TRACKED]: LifecycleHook
/**
- * alternative proxy used only for runtime-compiled render functions using
- * `with` block
* @internal
*/
- withProxy: ComponentPublicInstance | null
+ [LifecycleHooks.RENDER_TRIGGERED]: LifecycleHook
/**
- * This is the target for the public instance proxy. It also holds properties
- * injected by user options (computed, methods etc.) and user-attached
- * custom properties (via `this.x = ...`)
* @internal
*/
- ctx: Data
+ [LifecycleHooks.ACTIVATED]: LifecycleHook
/**
- * suspense pending batch id
* @internal
*/
- suspenseId: number
+ [LifecycleHooks.DEACTIVATED]: LifecycleHook
/**
* @internal
*/
- asyncDep: Promise<any> | null
+ [LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
/**
* @internal
*/
- asyncResolved: boolean
+ [LifecycleHooks.SERVER_PREFETCH]: LifecycleHook<() => Promise<unknown>>
/**
* For caching bound $forceUpdate on public proxy access
let uid = 0
-/**
- * @internal for vapor
- */
-export function nextUid(): number {
- return uid++
-}
-
export function createComponentInstance(
vnode: VNode,
parent: ComponentInternalInstance | null,
emitted: null,
// props default value
- propsDefaults: null,
+ propsDefaults: EMPTY_OBJ,
// inheritAttrs
inheritAttrs: type.inheritAttrs,
return instance
}
+export let currentInstance: ComponentInternalInstance | null = null
+
+export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
+ currentInstance || currentRenderingInstance
+
+let internalSetCurrentInstance: (
+ instance: ComponentInternalInstance | null,
+) => void
+let setInSSRSetupState: (state: boolean) => void
+
/**
- * @internal
+ * The following makes getCurrentInstance() usage across multiple copies of Vue
+ * work. Some cases of how this can happen are summarized in #7590. In principle
+ * the duplication should be avoided, but in practice there are often cases
+ * where the user is unable to resolve on their own, especially in complicated
+ * SSR setups.
+ *
+ * Note this fix is technically incomplete, as we still rely on other singletons
+ * for effectScope and global reactive dependency maps. However, it does make
+ * some of the most common cases work. It also warns if the duplication is
+ * found during browser execution.
*/
+if (__SSR__) {
+ type Setter = (v: any) => void
+ const g = getGlobalThis()
+ const registerGlobalSetter = (key: string, setter: Setter) => {
+ let setters: Setter[]
+ if (!(setters = g[key])) setters = g[key] = []
+ setters.push(setter)
+ return (v: any) => {
+ if (setters.length > 1) setters.forEach(set => set(v))
+ else setters[0](v)
+ }
+ }
+ internalSetCurrentInstance = registerGlobalSetter(
+ `__VUE_INSTANCE_SETTERS__`,
+ v => (currentInstance = v),
+ )
+ // also make `isInSSRComponentSetup` sharable across copies of Vue.
+ // this is needed in the SFC playground when SSRing async components, since
+ // we have to load both the runtime and the server-renderer from CDNs, they
+ // contain duplicated copies of Vue runtime code.
+ setInSSRSetupState = registerGlobalSetter(
+ `__VUE_SSR_SETTERS__`,
+ v => (isInSSRComponentSetup = v),
+ )
+} else {
+ internalSetCurrentInstance = i => {
+ currentInstance = i
+ }
+ setInSSRSetupState = v => {
+ isInSSRComponentSetup = v
+ }
+}
+
+export const setCurrentInstance = (instance: ComponentInternalInstance) => {
+ const prev = currentInstance
+ internalSetCurrentInstance(instance)
+ instance.scope.on()
+ return (): void => {
+ instance.scope.off()
+ internalSetCurrentInstance(prev)
+ }
+}
+
+export const unsetCurrentInstance = (): void => {
+ currentInstance && currentInstance.scope.off()
+ internalSetCurrentInstance(null)
+}
+
+const isBuiltInTag = /*@__PURE__*/ makeMap('slot,component')
+
export function validateComponentName(
name: string,
{ isNativeTag }: AppConfig,
return instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
}
+export let isInSSRComponentSetup = false
+
export function setupComponent(
instance: ComponentInternalInstance,
isSSR = false,
): Promise<void> | undefined {
isSSR && setInSSRSetupState(isSSR)
- const { props, children, vi } = instance.vnode
+ const { props, children } = instance.vnode
const isStateful = isStatefulComponent(instance)
-
- if (vi) {
- // Vapor interop override - use Vapor props/attrs proxy
- vi(instance)
- } else {
- initProps(instance, props, isStateful, isSSR)
- initSlots(instance, children, optimized || isSSR)
- }
+ initProps(instance, props, isStateful, isSSR)
+ initSlots(instance, children, optimized || isSSR)
const setupResult = isStateful
? setupStatefulComponent(instance, isSSR)
export function createSetupContext(
instance: ComponentInternalInstance,
): SetupContext {
+ const expose: SetupContext['expose'] = exposed => {
+ if (__DEV__) {
+ if (instance.exposed) {
+ warn(`expose() should be called only once per setup().`)
+ }
+ if (exposed != null) {
+ let exposedType: string = typeof exposed
+ if (exposedType === 'object') {
+ if (isArray(exposed)) {
+ exposedType = 'array'
+ } else if (isRef(exposed)) {
+ exposedType = 'ref'
+ }
+ }
+ if (exposedType !== 'object') {
+ warn(
+ `expose() should be passed a plain object, received ${exposedType}.`,
+ )
+ }
+ }
+ }
+ instance.exposed = exposed || {}
+ }
+
if (__DEV__) {
// We use getters in dev in case libs like test-utils overwrite instance
// properties (overwrites should not be done in prod)
get emit() {
return (event: string, ...args: any[]) => instance.emit(event, ...args)
},
- expose: exposed => expose(instance, exposed as any),
+ expose,
})
} else {
return {
attrs: new Proxy(instance.attrs, attrsProxyHandlers),
slots: instance.slots,
emit: instance.emit,
- expose: exposed => expose(instance, exposed as any),
+ expose,
}
}
}
-/**
- * @internal
- */
-export function expose(
- instance: GenericComponentInstance,
- exposed: Record<string, any>,
-): void {
- if (__DEV__) {
- if (instance.exposed) {
- warn(`expose() should be called only once per setup().`)
- }
- if (exposed != null) {
- let exposedType: string = typeof exposed
- if (exposedType === 'object') {
- if (isArray(exposed)) {
- exposedType = 'array'
- } else if (isRef(exposed)) {
- exposedType = 'ref'
- }
- }
- if (exposedType !== 'object') {
- warn(
- `expose() should be passed a plain object, received ${exposedType}.`,
- )
- }
- }
- }
- instance.exposed = exposed || {}
-}
-
export function getComponentPublicInstance(
- instance: GenericComponentInstance,
+ instance: ComponentInternalInstance,
): ComponentPublicInstance | ComponentInternalInstance['exposed'] | null {
if (instance.exposed) {
return (
if (key in target) {
return target[key]
} else if (key in publicPropertiesMap) {
- return publicPropertiesMap[key](
- instance as ComponentInternalInstance,
- )
+ return publicPropertiesMap[key](instance)
}
},
has(target, key: string) {
str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '')
export function getComponentName(
- Component: GenericComponent,
+ Component: ConcreteComponent,
includeInferred = true,
): string | false | undefined {
return isFunction(Component)
}
export function formatComponentName(
- instance: GenericComponentInstance | null,
- Component: GenericComponent,
+ instance: ComponentInternalInstance | null,
+ Component: ConcreteComponent,
isRoot = false,
): string {
let name = getComponentName(Component)
}
name =
inferFromRegistry(
- (instance as ComponentInternalInstance).components ||
+ instance.components ||
(instance.parent.type as ComponentOptions).components,
) || inferFromRegistry(instance.appContext.components)
}
+++ /dev/null
-import { getGlobalThis } from '@vue/shared'
-import type {
- ComponentInternalInstance,
- GenericComponentInstance,
-} from './component'
-import { currentRenderingInstance } from './componentRenderContext'
-
-/**
- * @internal
- */
-export let currentInstance: GenericComponentInstance | null = null
-
-/**
- * @internal
- */
-export const getCurrentGenericInstance: () => GenericComponentInstance | null =
- () => currentInstance || currentRenderingInstance
-
-export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
- currentInstance && !currentInstance.vapor
- ? (currentInstance as ComponentInternalInstance)
- : currentRenderingInstance
-
-export let isInSSRComponentSetup = false
-
-export let setInSSRSetupState: (state: boolean) => void
-
-let internalSetCurrentInstance: (
- instance: GenericComponentInstance | null,
-) => void
-
-/**
- * The following makes getCurrentInstance() usage across multiple copies of Vue
- * work. Some cases of how this can happen are summarized in #7590. In principle
- * the duplication should be avoided, but in practice there are often cases
- * where the user is unable to resolve on their own, especially in complicated
- * SSR setups.
- *
- * Note this fix is technically incomplete, as we still rely on other singletons
- * for effectScope and global reactive dependency maps. However, it does make
- * some of the most common cases work. It also warns if the duplication is
- * found during browser execution.
- */
-if (__SSR__) {
- type Setter = (v: any) => void
- const g = getGlobalThis()
- const registerGlobalSetter = (key: string, setter: Setter) => {
- let setters: Setter[]
- if (!(setters = g[key])) setters = g[key] = []
- setters.push(setter)
- return (v: any) => {
- if (setters.length > 1) setters.forEach(set => set(v))
- else setters[0](v)
- }
- }
- internalSetCurrentInstance = registerGlobalSetter(
- `__VUE_INSTANCE_SETTERS__`,
- v => (currentInstance = v),
- )
- // also make `isInSSRComponentSetup` sharable across copies of Vue.
- // this is needed in the SFC playground when SSRing async components, since
- // we have to load both the runtime and the server-renderer from CDNs, they
- // contain duplicated copies of Vue runtime code.
- setInSSRSetupState = registerGlobalSetter(
- `__VUE_SSR_SETTERS__`,
- v => (isInSSRComponentSetup = v),
- )
-} else {
- internalSetCurrentInstance = i => {
- currentInstance = i
- }
- setInSSRSetupState = v => {
- isInSSRComponentSetup = v
- }
-}
-
-export const setCurrentInstance = (instance: GenericComponentInstance) => {
- const prev = currentInstance
- internalSetCurrentInstance(instance)
- instance.scope.on()
- return (): void => {
- instance.scope.off()
- internalSetCurrentInstance(prev)
- }
-}
-
-export const unsetCurrentInstance = (): void => {
- currentInstance && currentInstance.scope.off()
- internalSetCurrentInstance(null)
-}
-
-/**
- * Exposed for vapor only. Vapor never runs during SSR so we don't want to pay
- * for the extra overhead
- * @internal
- */
-export const simpleSetCurrentInstance = (
- i: GenericComponentInstance | null,
- unset?: GenericComponentInstance | null,
-): void => {
- currentInstance = i
- if (unset) {
- unset.scope.off()
- } else if (i) {
- i.scope.on()
- }
-}
type ComponentInternalInstance,
type ComponentOptions,
type ConcreteComponent,
- type GenericComponentInstance,
formatComponentName,
} from './component'
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
instance: ComponentInternalInstance,
event: string,
...rawArgs: any[]
-): ComponentPublicInstance | null | undefined {
- return baseEmit(
- instance,
- instance.vnode.props || EMPTY_OBJ,
- defaultPropGetter,
- event,
- ...rawArgs,
- )
-}
-
-/**
- * @internal for vapor only
- */
-export function baseEmit(
- instance: GenericComponentInstance,
- props: Record<string, any>,
- getter: (props: Record<string, any>, key: string) => unknown,
- event: string,
- ...rawArgs: any[]
): ComponentPublicInstance | null | undefined {
if (instance.isUnmounted) return
+ const props = instance.vnode.props || EMPTY_OBJ
+
if (__DEV__) {
- const { emitsOptions, propsOptions } = instance
+ const {
+ emitsOptions,
+ propsOptions: [propsOptions],
+ } = instance
if (emitsOptions) {
if (
!(event in emitsOptions) &&
event.startsWith(compatModelEventPrefix))
)
) {
- if (
- !propsOptions ||
- !propsOptions[0] ||
- !(toHandlerKey(camelize(event)) in propsOptions[0])
- ) {
+ if (!propsOptions || !(toHandlerKey(camelize(event)) in propsOptions)) {
warn(
`Component emitted event "${event}" but it is neither declared in ` +
`the emits option nor as an "${toHandlerKey(camelize(event))}" prop.`,
const isCompatModelListener =
__COMPAT__ && compatModelEventPrefix + event in props
const isModelListener = isCompatModelListener || event.startsWith('update:')
- // for v-model update:xxx events, apply modifiers on args
- // it's ok to use static get because modelModifiers can only be in the static
- // part of the props
const modifiers = isCompatModelListener
? props.modelModifiers
- : isModelListener && getModelModifiers(props, event.slice(7), getter)
+ : isModelListener && getModelModifiers(props, event.slice(7))
+
+ // for v-model update:xxx events, apply modifiers on args
if (modifiers) {
if (modifiers.trim) {
args = rawArgs.map(a => (isString(a) ? a.trim() : a))
if (__DEV__) {
const lowerCaseEvent = event.toLowerCase()
- if (
- lowerCaseEvent !== event &&
- getter(props, toHandlerKey(lowerCaseEvent))
- ) {
+ if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) {
warn(
`Event "${lowerCaseEvent}" is emitted in component ` +
`${formatComponentName(
let handlerName
let handler =
- getter(props, (handlerName = toHandlerKey(event))) ||
+ props[(handlerName = toHandlerKey(event))] ||
// also try camelCase event handler (#2249)
- getter(props, (handlerName = toHandlerKey(camelize(event))))
+ props[(handlerName = toHandlerKey(camelize(event)))]
// for v-model update:xxx events, also trigger kebab-case equivalent
// for props passed via kebab-case
if (!handler && isModelListener) {
- handler = getter(props, (handlerName = toHandlerKey(hyphenate(event))))
+ handler = props[(handlerName = toHandlerKey(hyphenate(event)))]
}
if (handler) {
callWithAsyncErrorHandling(
- handler as Function | Function[],
+ handler,
instance,
ErrorCodes.COMPONENT_EVENT_HANDLER,
args,
)
}
- const onceHandler = getter(props, handlerName + `Once`)
+ const onceHandler = props[handlerName + `Once`]
if (onceHandler) {
if (!instance.emitted) {
instance.emitted = {}
}
instance.emitted[handlerName] = true
callWithAsyncErrorHandling(
- onceHandler as Function | Function[],
+ onceHandler,
instance,
ErrorCodes.COMPONENT_EVENT_HANDLER,
args,
)
}
- if (__COMPAT__ && args) {
- compatModelEmit(instance as ComponentInternalInstance, event, args)
- return compatInstanceEmit(
- instance as ComponentInternalInstance,
- event,
- args,
- )
+ if (__COMPAT__) {
+ compatModelEmit(instance, event, args)
+ return compatInstanceEmit(instance, event, args)
}
}
-export function defaultPropGetter(
- props: Record<string, any>,
- key: string,
-): unknown {
- return props[key]
-}
-
export function normalizeEmitsOptions(
comp: ConcreteComponent,
appContext: AppContext,
return normalized
}
-/**
- * Check if an incoming prop key is a declared emit event listener.
- * e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
- * both considered matched listeners.
- *
- * @internal for vapor only
- */
+// Check if an incoming prop key is a declared emit event listener.
+// e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
+// both considered matched listeners.
export function isEmitListener(
options: ObjectEmitsOptions | null,
key: string,
type Data,
type InternalRenderFunction,
type SetupContext,
- getCurrentInstance,
+ currentInstance,
} from './component'
import {
type LooseRequired,
const options: WatchOptions = {}
if (__COMPAT__) {
- const cur = getCurrentInstance()
- const instance = cur && getCurrentScope() === cur.scope ? cur : null
+ const instance =
+ currentInstance && getCurrentScope() === currentInstance.scope
+ ? currentInstance
+ : null
const newValue = getter()
if (
type ComponentOptions,
type ConcreteComponent,
type Data,
- type GenericComponentInstance,
setCurrentInstance,
} from './component'
import { isEmitListener } from './componentEmits'
[BooleanFlags.shouldCastTrue]?: boolean
}
-/**
- * normalized value is a tuple of the actual normalized options
- * and an array of prop keys that need value casting (booleans and defaults)
- */
+// normalized value is a tuple of the actual normalized options
+// and an array of prop keys that need value casting (booleans and defaults)
export type NormalizedProps = Record<string, NormalizedProp>
-
export type NormalizedPropsOptions = [NormalizedProps, string[]] | []
export function initProps(
isStateful: number, // result of bitwise flag comparison
isSSR = false,
): void {
- const props: Data = (instance.props = {})
+ const props: Data = {}
const attrs: Data = createInternalObject()
instance.propsDefaults = Object.create(null)
// validation
if (__DEV__) {
- validateProps(rawProps || {}, props, instance.propsOptions[0]!)
+ validateProps(rawProps || {}, props, instance)
}
if (isStateful) {
instance.attrs = attrs
}
-function isInHmrContext(instance: GenericComponentInstance | null) {
+function isInHmrContext(instance: ComponentInternalInstance | null) {
while (instance) {
if (instance.type.__hmrId) return true
instance = instance.parent
const camelizedKey = camelize(key)
props[camelizedKey] = resolvePropValue(
options,
+ rawCurrentProps,
camelizedKey,
value,
instance,
- baseResolveDefault,
+ false /* isAbsent */,
)
}
} else {
) {
props[key] = resolvePropValue(
options,
+ rawCurrentProps,
key,
undefined,
instance,
- baseResolveDefault,
true /* isAbsent */,
)
}
}
if (__DEV__) {
- validateProps(rawProps || {}, props, instance.propsOptions[0]!)
+ validateProps(rawProps || {}, props, instance)
}
}
}
if (needCastKeys) {
+ const rawCurrentProps = toRaw(props)
const castValues = rawCastValues || EMPTY_OBJ
for (let i = 0; i < needCastKeys.length; i++) {
const key = needCastKeys[i]
props[key] = resolvePropValue(
options!,
+ rawCurrentProps,
key,
castValues[key],
instance,
- baseResolveDefault,
!hasOwn(castValues, key),
)
}
return hasAttrsChanged
}
-/**
- * @internal for runtime-vapor
- */
-export function resolvePropValue<
- T extends GenericComponentInstance & Pick<ComponentInternalInstance, 'ce'>,
->(
+function resolvePropValue(
options: NormalizedProps,
+ props: Data,
key: string,
value: unknown,
- instance: T,
- /**
- * Allow runtime-specific default resolution logic
- */
- resolveDefault: (
- factory: (props: Data) => unknown,
- instance: T,
- key: string,
- ) => unknown,
- isAbsent = false,
-): unknown {
+ instance: ComponentInternalInstance,
+ isAbsent: boolean,
+) {
const opt = options[key]
if (opt != null) {
const hasDefault = hasOwn(opt, 'default')
!opt.skipFactory &&
isFunction(defaultValue)
) {
- const cachedDefaults =
- instance.propsDefaults || (instance.propsDefaults = {})
- if (hasOwn(cachedDefaults, key)) {
- value = cachedDefaults[key]
+ const { propsDefaults } = instance
+ if (key in propsDefaults) {
+ value = propsDefaults[key]
} else {
- value = cachedDefaults[key] = resolveDefault(
- defaultValue,
- instance,
- key,
+ const reset = setCurrentInstance(instance)
+ value = propsDefaults[key] = defaultValue.call(
+ __COMPAT__ &&
+ isCompatEnabled(DeprecationTypes.PROPS_DEFAULT_THIS, instance)
+ ? createPropsDefaultThis(instance, props, key)
+ : null,
+ props,
)
+ reset()
}
} else {
value = defaultValue
return value
}
-/**
- * runtime-dom-specific default resolving logic
- */
-function baseResolveDefault(
- factory: (props: Data) => unknown,
- instance: ComponentInternalInstance,
- key: string,
-) {
- let value
- const reset = setCurrentInstance(instance)
- const props = toRaw(instance.props)
- value = factory.call(
- __COMPAT__ && isCompatEnabled(DeprecationTypes.PROPS_DEFAULT_THIS, instance)
- ? createPropsDefaultThis(instance, props, key)
- : null,
- props,
- )
- reset()
- return value
-}
-
const mixinPropsCache = new WeakMap<ConcreteComponent, NormalizedPropsOptions>()
export function normalizePropsOptions(
return EMPTY_ARR as any
}
- baseNormalizePropsOptions(raw, normalized, needCastKeys)
- const res: NormalizedPropsOptions = [normalized, needCastKeys]
- if (isObject(comp)) {
- cache.set(comp, res)
- }
- return res
-}
-
-/**
- * @internal for runtime-vapor only
- */
-export function baseNormalizePropsOptions(
- raw: ComponentPropsOptions | undefined,
- normalized: NonNullable<NormalizedPropsOptions[0]>,
- needCastKeys: NonNullable<NormalizedPropsOptions[1]>,
-): void {
if (isArray(raw)) {
for (let i = 0; i < raw.length; i++) {
if (__DEV__ && !isString(raw[i])) {
}
}
}
+
+ const res: NormalizedPropsOptions = [normalized, needCastKeys]
+ if (isObject(comp)) {
+ cache.set(comp, res)
+ }
+ return res
}
function validatePropName(key: string) {
/**
* dev only
- * @internal
*/
-export function validateProps(
+function validateProps(
rawProps: Data,
- resolvedProps: Data,
- options: NormalizedProps,
-): void {
- resolvedProps = toRaw(resolvedProps)
+ props: Data,
+ instance: ComponentInternalInstance,
+) {
+ const resolvedValues = toRaw(props)
+ const options = instance.propsOptions[0]
const camelizePropsKey = Object.keys(rawProps).map(key => camelize(key))
for (const key in options) {
- const opt = options[key]
- if (opt != null) {
- validateProp(
- key,
- resolvedProps[key],
- opt,
- resolvedProps,
- !camelizePropsKey.includes(key),
- )
- }
+ let opt = options[key]
+ if (opt == null) continue
+ validateProp(
+ key,
+ resolvedValues[key],
+ opt,
+ __DEV__ ? shallowReadonly(resolvedValues) : resolvedValues,
+ !camelizePropsKey.includes(key),
+ )
}
}
* dev only
*/
function validateProp(
- key: string,
+ name: string,
value: unknown,
- propOptions: PropOptions,
- resolvedProps: Data,
+ prop: PropOptions,
+ props: Data,
isAbsent: boolean,
) {
- const { type, required, validator, skipCheck } = propOptions
+ const { type, required, validator, skipCheck } = prop
// required!
if (required && isAbsent) {
- warn('Missing required prop: "' + key + '"')
+ warn('Missing required prop: "' + name + '"')
return
}
// missing but optional
isValid = valid
}
if (!isValid) {
- warn(getInvalidTypeMessage(key, value, expectedTypes))
+ warn(getInvalidTypeMessage(name, value, expectedTypes))
return
}
}
// custom validator
- if (
- validator &&
- !validator(value, __DEV__ ? shallowReadonly(resolvedProps) : resolvedProps)
- ) {
- warn('Invalid prop: custom validator check failed for prop "' + key + '".')
+ if (validator && !validator(value, props)) {
+ warn('Invalid prop: custom validator check failed for prop "' + name + '".')
}
}
type Component,
type ComponentInternalInstance,
type Data,
- type GenericComponentInstance,
getComponentPublicInstance,
isStatefulComponent,
} from './component'
* public $parent chains, skip functional ones and go to the parent instead.
*/
const getPublicInstance = (
- i: GenericComponentInstance | null,
+ i: ComponentInternalInstance | null,
): ComponentPublicInstance | ComponentInternalInstance['exposed'] | null => {
- if (!i || i.vapor) return null
- if (isStatefulComponent(i as ComponentInternalInstance))
- return getComponentPublicInstance(i)
+ if (!i) return null
+ if (isStatefulComponent(i)) return getComponentPublicInstance(i)
return getPublicInstance(i.parent)
}
{ vnode, parent }: ComponentInternalInstance,
el: typeof vnode.el, // HostNode
): void {
- while (parent && !parent.vapor) {
- const root = parent.subTree!
+ while (parent) {
+ const root = parent.subTree
if (root.suspense && root.suspense.activeBranch === vnode) {
root.el = vnode.el
}
if (root === vnode) {
- ;(vnode = parent.vnode!).el = el
+ ;(vnode = parent.vnode).el = el
parent = parent.parent
} else {
break
if (
__DEV__ &&
currentInstance &&
- !currentInstance.vapor &&
!(ctx === null && currentRenderingInstance) &&
!(ctx && ctx.root !== currentInstance.root)
) {
type ComponentInternalInstance,
type ComponentOptions,
type ConcreteComponent,
- type GenericComponentInstance,
type SetupContext,
+ currentInstance,
getComponentName,
getCurrentInstance,
} from '../component'
},
setup(props: KeepAliveProps, { slots }: SetupContext) {
- const keepAliveInstance = getCurrentInstance()!
+ const instance = getCurrentInstance()!
// KeepAlive communicates with the instantiated renderer via the
// ctx where the renderer passes in its internals,
// and the KeepAlive instance exposes activate/deactivate implementations.
// The whole point of this is to avoid importing KeepAlive directly in the
// renderer to facilitate tree-shaking.
- const sharedContext = keepAliveInstance.ctx as KeepAliveContext
+ const sharedContext = instance.ctx as KeepAliveContext
// if the internal renderer is not registered, it indicates that this is server-side rendering,
// for KeepAlive, we just need to render its children
let current: VNode | null = null
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- ;(keepAliveInstance as any).__v_cache = cache
+ ;(instance as any).__v_cache = cache
}
- const parentSuspense = keepAliveInstance.suspense
+ const parentSuspense = instance.suspense
const {
renderer: {
optimized,
) => {
const instance = vnode.component!
- move(
- vnode,
- container,
- anchor,
- MoveType.ENTER,
- keepAliveInstance,
- parentSuspense,
- )
+ move(vnode, container, anchor, MoveType.ENTER, parentSuspense)
// in case props have changed
patch(
instance.vnode,
invalidateMount(instance.m)
invalidateMount(instance.a)
- move(
- vnode,
- storageContainer,
- null,
- MoveType.LEAVE,
- keepAliveInstance,
- parentSuspense,
- )
+ move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense)
queuePostRenderEffect(() => {
if (instance.da) {
invokeArrayFns(instance.da)
function unmount(vnode: VNode) {
// reset the shapeFlag so it can be properly unmounted
resetShapeFlag(vnode)
- _unmount(vnode, keepAliveInstance, parentSuspense, true)
+ _unmount(vnode, instance, parentSuspense, true)
}
function pruneCache(filter: (name: string) => boolean) {
if (pendingCacheKey != null) {
// if KeepAlive child is a Suspense, it needs to be cached after Suspense resolves
// avoid caching vnode that not been mounted
- if (isSuspense(keepAliveInstance.subTree.type)) {
+ if (isSuspense(instance.subTree.type)) {
queuePostRenderEffect(() => {
- cache.set(
- pendingCacheKey!,
- getInnerChild(keepAliveInstance.subTree),
- )
- }, keepAliveInstance.subTree.suspense)
+ cache.set(pendingCacheKey!, getInnerChild(instance.subTree))
+ }, instance.subTree.suspense)
} else {
- cache.set(pendingCacheKey, getInnerChild(keepAliveInstance.subTree))
+ cache.set(pendingCacheKey, getInnerChild(instance.subTree))
}
}
}
onBeforeUnmount(() => {
cache.forEach(cached => {
- const { subTree, suspense } = keepAliveInstance
+ const { subTree, suspense } = instance
const vnode = getInnerChild(subTree)
if (cached.type === vnode.type && cached.key === vnode.key) {
// current instance will be unmounted as part of keep-alive's unmount
function registerKeepAliveHook(
hook: Function & { __wdc?: Function },
type: LifecycleHooks,
- target: ComponentInternalInstance | null = getCurrentInstance(),
+ target: ComponentInternalInstance | null = currentInstance,
) {
// cache the deactivate branch check wrapper for injected hooks so the same
// hook can be properly deduped by the scheduler. "__wdc" stands for "with
hook.__wdc ||
(hook.__wdc = () => {
// only fire the hook if the target instance is NOT in a deactivated branch.
- let current: GenericComponentInstance | null = target
+ let current: ComponentInternalInstance | null = target
while (current) {
if (current.isDeactivated) {
return
// arrays.
if (target) {
let current = target.parent
- while (current && current.parent && current.parent.vnode) {
+ while (current && current.parent) {
if (isKeepAlive(current.parent.vnode)) {
injectToKeepAliveRoot(wrappedHook, type, target, current)
}
hook: Function & { __weh?: Function },
type: LifecycleHooks,
target: ComponentInternalInstance,
- keepAliveRoot: GenericComponentInstance,
+ keepAliveRoot: ComponentInternalInstance,
) {
// injectHook wraps the original for error handling, so make sure to remove
// the wrapped version.
container,
anchor === initialAnchor ? next(activeBranch!) : anchor,
MoveType.ENTER,
- parentComponent,
)
queuePostFlushCb(effects)
}
}
if (!delayEnter) {
// move content from off-dom container to actual container
- move(
- pendingBranch!,
- container,
- anchor,
- MoveType.ENTER,
- parentComponent,
- )
+ move(pendingBranch!, container, anchor, MoveType.ENTER)
}
}
move(container, anchor, type) {
suspense.activeBranch &&
- move(suspense.activeBranch, container, anchor, type, parentComponent)
+ move(suspense.activeBranch, container, anchor, type)
suspense.container = container
},
container,
mainAnchor,
internals,
- parentComponent,
TeleportMoveTypes.TOGGLE,
)
} else {
nextTarget,
null,
internals,
- parentComponent,
TeleportMoveTypes.TARGET_CHANGE,
)
} else if (__DEV__) {
target,
targetAnchor,
internals,
- parentComponent,
TeleportMoveTypes.TOGGLE,
)
}
container: RendererElement,
parentAnchor: RendererNode | null,
{ o: { insert }, m: move }: RendererInternals,
- parentComponent: ComponentInternalInstance | null,
moveType: TeleportMoveTypes = TeleportMoveTypes.REORDER,
): void {
// move target anchor if this is a target change.
container,
parentAnchor,
MoveType.REORDER,
- parentComponent,
)
}
}
/* eslint-disable no-restricted-globals */
import type { App } from './apiCreateApp'
import { Comment, Fragment, Static, Text } from './vnode'
-import type { GenericComponentInstance } from './component'
+import type { ComponentInternalInstance } from './component'
interface AppRecord {
id: number
}
}
-let queued = false
export function setDevtoolsHook(hook: DevtoolsHook, target: any): void {
- if (devtoolsNotInstalled || queued) {
- return
- }
devtools = hook
if (devtools) {
devtools.enabled = true
// eslint-disable-next-line no-restricted-syntax
!window.navigator?.userAgent?.includes('jsdom')
) {
- queued = true
const replay = (target.__VUE_DEVTOOLS_HOOK_REPLAY__ =
target.__VUE_DEVTOOLS_HOOK_REPLAY__ || [])
replay.push((newHook: DevtoolsHook) => {
)
export const devtoolsComponentRemoved = (
- component: GenericComponentInstance,
+ component: ComponentInternalInstance,
): void => {
if (
devtools &&
}
}
-type DevtoolsComponentHook = (component: GenericComponentInstance) => void
+type DevtoolsComponentHook = (component: ComponentInternalInstance) => void
/*! #__NO_SIDE_EFFECTS__ */
function createDevtoolsComponentHook(
hook: DevtoolsHooks,
): DevtoolsComponentHook {
- return (component: GenericComponentInstance) => {
+ return (component: ComponentInternalInstance) => {
emit(
hook,
component.appContext.app,
/*@__PURE__*/ createDevtoolsPerformanceHook(DevtoolsHooks.PERFORMANCE_END)
type DevtoolsPerformanceHook = (
- component: GenericComponentInstance,
+ component: ComponentInternalInstance,
type: string,
time: number,
) => void
function createDevtoolsPerformanceHook(
hook: DevtoolsHooks,
): DevtoolsPerformanceHook {
- return (component: GenericComponentInstance, type: string, time: number) => {
+ return (component: ComponentInternalInstance, type: string, time: number) => {
emit(hook, component.appContext.app, component.uid, component, type, time)
}
}
export function devtoolsComponentEmit(
- component: GenericComponentInstance,
+ component: ComponentInternalInstance,
event: string,
params: any[],
): void {
import { pauseTracking, resetTracking } from '@vue/reactivity'
-import type { GenericComponentInstance } from './component'
+import type { VNode } from './vnode'
+import type { ComponentInternalInstance } from './component'
import { popWarningContext, pushWarningContext, warn } from './warning'
import { EMPTY_OBJ, isArray, isFunction, isPromise } from '@vue/shared'
import { LifecycleHooks } from './enums'
export function callWithErrorHandling(
fn: Function,
- instance: GenericComponentInstance | null | undefined,
+ instance: ComponentInternalInstance | null | undefined,
type: ErrorTypes,
args?: unknown[],
): any {
export function callWithAsyncErrorHandling(
fn: Function | Function[],
- instance: GenericComponentInstance | null,
+ instance: ComponentInternalInstance | null,
type: ErrorTypes,
args?: unknown[],
): any {
export function handleError(
err: unknown,
- instance: GenericComponentInstance | null | undefined,
+ instance: ComponentInternalInstance | null | undefined,
type: ErrorTypes,
throwInDev = true,
): void {
+ const contextVNode = instance ? instance.vnode : null
const { errorHandler, throwUnhandledErrorInProduction } =
(instance && instance.appContext.config) || EMPTY_OBJ
if (instance) {
let cur = instance.parent
// the exposed instance is the render proxy to keep it consistent with 2.x
- const exposedInstance = instance.proxy || instance
+ const exposedInstance = instance.proxy
// in production the hook receives only the error code
const errorInfo = __DEV__
? ErrorTypeStrings[type]
return
}
}
- logError(err, type, instance, throwInDev, throwUnhandledErrorInProduction)
+ logError(err, type, contextVNode, throwInDev, throwUnhandledErrorInProduction)
}
function logError(
err: unknown,
type: ErrorTypes,
- instance: GenericComponentInstance | null | undefined,
+ contextVNode: VNode | null,
throwInDev = true,
throwInProd = false,
) {
if (__DEV__) {
const info = ErrorTypeStrings[type]
- if (instance) {
- pushWarningContext(instance)
+ if (contextVNode) {
+ pushWarningContext(contextVNode)
}
warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`)
- if (instance) {
+ if (contextVNode) {
popWarningContext()
}
// crash in dev by default so it's more noticeable
import { getGlobalThis } from '@vue/shared'
-let initialized = false
-
/**
* This is only called in esm-bundler builds.
* It is called when a renderer is created, in `baseCreateRenderer` so that
* importing runtime-core is side-effects free.
*/
export function initFeatureFlags(): void {
- if (initialized) return
-
const needWarn = []
if (typeof __FEATURE_OPTIONS_API__ !== 'boolean') {
`For more details, see https://link.vuejs.org/feature-flags.`,
)
}
-
- initialized = true
}
+import type { Data } from '../component'
import type { RawSlots, Slots } from '../componentSlots'
import {
type ContextualRenderFn,
Fragment,
type VNode,
type VNodeArrayChildren,
- VaporSlot,
createBlock,
createVNode,
isVNode,
import { PatchFlags, SlotFlags, isSymbol } from '@vue/shared'
import { warn } from '../warning'
import { isAsyncWrapper } from '../apiAsyncComponent'
-import type { Data } from '../component'
/**
* Compiler runtime helper for rendering `<slot/>`
fallback?: () => VNodeArrayChildren,
noSlotted?: boolean,
): VNode {
- let slot = slots[name]
-
- // vapor slots rendered in vdom
- if (slot && slots._vapor) {
- const ret = (openBlock(), createBlock(VaporSlot, props))
- ret.vs = { slot, fallback }
- return ret
- }
-
if (
- currentRenderingInstance &&
- (currentRenderingInstance.ce ||
- (currentRenderingInstance.parent &&
- isAsyncWrapper(currentRenderingInstance.parent) &&
- currentRenderingInstance.parent.ce))
+ currentRenderingInstance!.ce ||
+ (currentRenderingInstance!.parent &&
+ isAsyncWrapper(currentRenderingInstance!.parent) &&
+ currentRenderingInstance!.parent.ce)
) {
// in custom element mode, render <slot/> as actual slot outlets
// wrap it with a fragment because in shadowRoot: false mode the slot
)
}
+ let slot = slots[name]
+
if (__DEV__ && slot && slot.length > 1) {
warn(
`SSR-optimized slot function detected in a non-SSR-optimized render ` +
import {
- type ComponentInternalInstance,
type ComponentOptions,
type ConcreteComponent,
currentInstance,
const res =
// local registration
// check instance[type] first which is resolved for options API
- resolve(
- (instance as ComponentInternalInstance)[type] ||
- (Component as ComponentOptions)[type],
- name,
- ) ||
+ resolve(instance[type] || (Component as ComponentOptions)[type], name) ||
// global registration
- // @ts-expect-error filters only exist in compat mode
resolve(instance.appContext[type], name)
if (!res && maybeSelfReference) {
import {
- type GenericComponentInstance,
- getCurrentGenericInstance,
+ type ComponentInternalInstance,
+ getCurrentInstance,
} from '../component'
import { warn } from '../warning'
export function useId(): string {
- const i = getCurrentGenericInstance()
+ const i = getCurrentInstance()
if (i) {
return (i.appContext.config.idPrefix || 'v') + '-' + i.ids[0] + i.ids[1]++
} else if (__DEV__) {
* - components with async setup()
* - components with serverPrefetch
*/
-export function markAsyncBoundary(instance: GenericComponentInstance): void {
+export function markAsyncBoundary(instance: ComponentInternalInstance): void {
instance.ids = [instance.ids[0] + instance.ids[2]++ + '-', 0, 0]
}
import { type Ref, customRef, ref } from '@vue/reactivity'
import { EMPTY_OBJ, camelize, hasChanged, hyphenate } from '@vue/shared'
import type { DefineModelOptions, ModelRef } from '../apiSetupHelpers'
-import {
- type ComponentInternalInstance,
- getCurrentGenericInstance,
-} from '../component'
+import { getCurrentInstance } from '../component'
import { warn } from '../warning'
import type { NormalizedProps } from '../componentProps'
import { watchSyncEffect } from '../apiWatch'
-import { defaultPropGetter } from '../componentEmits'
export function useModel<
M extends PropertyKey,
name: string,
options: DefineModelOptions = EMPTY_OBJ,
): Ref {
- const i = getCurrentGenericInstance()!
+ const i = getCurrentInstance()!
if (__DEV__ && !i) {
warn(`useModel() called without active instance.`)
return ref() as any
}
const camelizedName = camelize(name)
- if (__DEV__ && !(i.propsOptions![0] as NormalizedProps)[camelizedName]) {
+ if (__DEV__ && !(i.propsOptions[0] as NormalizedProps)[camelizedName]) {
warn(`useModel() called with prop "${name}" which is not declared.`)
return ref() as any
}
const hyphenatedName = hyphenate(name)
- const modifiers = getModelModifiers(props, camelizedName, defaultPropGetter)
+ const modifiers = getModelModifiers(props, camelizedName)
const res = customRef((track, trigger) => {
let localValue: any
) {
return
}
-
- let rawPropKeys
- let parentPassedModelValue = false
- let parentPassedModelUpdater = false
-
- if (i.rawKeys) {
- // vapor instance
- rawPropKeys = i.rawKeys()
- } else {
- const rawProps = (i as ComponentInternalInstance).vnode!.props
- rawPropKeys = rawProps && Object.keys(rawProps)
- }
-
- if (rawPropKeys) {
- for (const key of rawPropKeys) {
- if (
- key === name ||
- key === camelizedName ||
- key === hyphenatedName
- ) {
- parentPassedModelValue = true
- } else if (
- key === `onUpdate:${name}` ||
- key === `onUpdate:${camelizedName}` ||
- key === `onUpdate:${hyphenatedName}`
- ) {
- parentPassedModelUpdater = true
- }
- }
- }
-
- if (!parentPassedModelValue || !parentPassedModelUpdater) {
+ const rawProps = i.vnode!.props
+ if (
+ !(
+ rawProps &&
+ // check if parent has passed v-model
+ (name in rawProps ||
+ camelizedName in rawProps ||
+ hyphenatedName in rawProps) &&
+ (`onUpdate:${name}` in rawProps ||
+ `onUpdate:${camelizedName}` in rawProps ||
+ `onUpdate:${hyphenatedName}` in rawProps)
+ )
+ ) {
// no v-model, local update
localValue = value
trigger()
export const getModelModifiers = (
props: Record<string, any>,
modelName: string,
- getter: (props: Record<string, any>, key: string) => any,
): Record<string, boolean> | undefined => {
return modelName === 'modelValue' || modelName === 'model-value'
- ? getter(props, 'modelModifiers')
- : getter(props, `${modelName}Modifiers`) ||
- getter(props, `${camelize(modelName)}Modifiers`) ||
- getter(props, `${hyphenate(modelName)}Modifiers`)
+ ? props.modelModifiers
+ : props[`${modelName}Modifiers`] ||
+ props[`${camelize(modelName)}Modifiers`] ||
+ props[`${hyphenate(modelName)}Modifiers`]
}
import { type ShallowRef, readonly, shallowRef } from '@vue/reactivity'
-import { getCurrentGenericInstance } from '../component'
+import { getCurrentInstance } from '../component'
import { warn } from '../warning'
import { EMPTY_OBJ } from '@vue/shared'
export function useTemplateRef<T = unknown, Keys extends string = string>(
key: Keys,
-): Readonly<ShallowRef<T | null>> {
- const i = getCurrentGenericInstance()
+): TemplateRef<T> {
+ const i = getCurrentInstance()
const r = shallowRef(null)
if (i) {
const refs = i.refs === EMPTY_OBJ ? (i.refs = {}) : i.refs
type ComponentInternalInstance,
type ComponentOptions,
type ConcreteComponent,
- type GenericComponentInstance,
+ type InternalRenderFunction,
isClassComponent,
} from './component'
-import { nextTick, queueJob, queuePostFlushCb } from './scheduler'
+import { queueJob, queuePostFlushCb } from './scheduler'
import { extend, getGlobalThis } from '@vue/shared'
type HMRComponent = ComponentOptions | ClassComponent
export const hmrDirtyComponents: Map<
ConcreteComponent,
- Set<GenericComponentInstance>
-> = new Map<ConcreteComponent, Set<GenericComponentInstance>>()
+ Set<ComponentInternalInstance>
+> = new Map<ConcreteComponent, Set<ComponentInternalInstance>>()
export interface HMRRuntime {
createRecord: typeof createRecord
// to apply hot updates to the component even when there are no actively
// rendered instance.
initialDef: ComponentOptions
- instances: Set<GenericComponentInstance>
+ instances: Set<ComponentInternalInstance>
}
> = new Map()
-export function registerHMR(instance: GenericComponentInstance): void {
+export function registerHMR(instance: ComponentInternalInstance): void {
const id = instance.type.__hmrId!
let record = map.get(id)
if (!record) {
record.instances.add(instance)
}
-export function unregisterHMR(instance: GenericComponentInstance): void {
+export function unregisterHMR(instance: ComponentInternalInstance): void {
map.get(instance.type.__hmrId!)!.instances.delete(instance)
}
// Create a snapshot which avoids the set being mutated during updates
;[...record.instances].forEach(instance => {
if (newRender) {
- instance.render = newRender
+ instance.render = newRender as InternalRenderFunction
normalizeClassComponent(instance.type as HMRComponent).render = newRender
}
+ instance.renderCache = []
// this flag forces child components with slot content to update
isHmrUpdating = true
- if (instance.vapor) {
- instance.hmrRerender!()
- } else {
- const i = instance as ComponentInternalInstance
- i.renderCache = []
- i.update()
- }
- nextTick(() => {
- isHmrUpdating = false
- })
+ instance.update()
+ isHmrUpdating = false
})
}
// create a snapshot which avoids the set being mutated during updates
const instances = [...record.instances]
- if (newComp.vapor) {
- for (const instance of instances) {
- instance.hmrReload!(newComp)
- }
- } else {
- for (const instance of instances as ComponentInternalInstance[]) {
- const oldComp = normalizeClassComponent(instance.type as HMRComponent)
-
- let dirtyInstances = hmrDirtyComponents.get(oldComp)
- if (!dirtyInstances) {
- // 1. Update existing comp definition to match new one
- if (oldComp !== record.initialDef) {
- updateComponentDef(oldComp, newComp)
- }
- // 2. mark definition dirty. This forces the renderer to replace the
- // component on patch.
- hmrDirtyComponents.set(oldComp, (dirtyInstances = new Set()))
+ for (let i = 0; i < instances.length; i++) {
+ const instance = instances[i]
+ const oldComp = normalizeClassComponent(instance.type as HMRComponent)
+
+ let dirtyInstances = hmrDirtyComponents.get(oldComp)
+ if (!dirtyInstances) {
+ // 1. Update existing comp definition to match new one
+ if (oldComp !== record.initialDef) {
+ updateComponentDef(oldComp, newComp)
}
- dirtyInstances.add(instance)
+ // 2. mark definition dirty. This forces the renderer to replace the
+ // component on patch.
+ hmrDirtyComponents.set(oldComp, (dirtyInstances = new Set()))
+ }
+ dirtyInstances.add(instance)
- // 3. invalidate options resolution cache
- instance.appContext.propsCache.delete(instance.type as any)
- instance.appContext.emitsCache.delete(instance.type as any)
- instance.appContext.optionsCache.delete(instance.type as any)
+ // 3. invalidate options resolution cache
+ instance.appContext.propsCache.delete(instance.type as any)
+ instance.appContext.emitsCache.delete(instance.type as any)
+ instance.appContext.optionsCache.delete(instance.type as any)
- // 4. actually update
- if (instance.ceReload) {
- // custom element
- dirtyInstances.add(instance)
- instance.ceReload((newComp as any).styles)
+ // 4. actually update
+ if (instance.ceReload) {
+ // custom element
+ dirtyInstances.add(instance)
+ instance.ceReload((newComp as any).styles)
+ dirtyInstances.delete(instance)
+ } else if (instance.parent) {
+ // 4. Force the parent instance to re-render. This will cause all updated
+ // components to be unmounted and re-mounted. Queue the update so that we
+ // don't end up forcing the same parent to re-render multiple times.
+ queueJob(() => {
+ isHmrUpdating = true
+ instance.parent!.update()
+ isHmrUpdating = false
+ // #6930, #11248 avoid infinite recursion
dirtyInstances.delete(instance)
- } else if (instance.parent) {
- // 4. Force the parent instance to re-render. This will cause all updated
- // components to be unmounted and re-mounted. Queue the update so that we
- // don't end up forcing the same parent to re-render multiple times.
- queueJob(() => {
- isHmrUpdating = true
- const parent = instance.parent!
- if (parent.vapor) {
- parent.hmrRerender!()
- } else {
- ;(parent as ComponentInternalInstance).update()
- }
- nextTick(() => {
- isHmrUpdating = false
- })
- // #6930, #11248 avoid infinite recursion
- dirtyInstances.delete(instance)
- })
- } else if (instance.appContext.reload) {
- // root instance mounted via createApp() has a reload method
- instance.appContext.reload()
- } else if (typeof window !== 'undefined') {
- // root instance inside tree created via raw render(). Force reload.
- window.location.reload()
- } else {
- console.warn(
- '[HMR] Root or manually mounted instance modified. Full reload required.',
- )
- }
+ })
+ } else if (instance.appContext.reload) {
+ // root instance mounted via createApp() has a reload method
+ instance.appContext.reload()
+ } else if (typeof window !== 'undefined') {
+ // root instance inside tree created via raw render(). Force reload.
+ window.location.reload()
+ } else {
+ console.warn(
+ '[HMR] Root or manually mounted instance modified. Full reload required.',
+ )
+ }
- // update custom element child style
- if (instance.root.ce && instance !== instance.root) {
- instance.root.ce._removeChildStyle(oldComp)
- }
+ // update custom element child style
+ if (instance.root.ce && instance !== instance.root) {
+ instance.root.ce._removeChildStyle(oldComp)
}
}
+
// 5. make sure to cleanup dirty hmr components after update
queuePostFlushCb(() => {
hmrDirtyComponents.clear()
normalizeVNode,
} from './vnode'
import { flushPostFlushCbs } from './scheduler'
-import type {
- ComponentInternalInstance,
- ComponentOptions,
- ConcreteComponent,
-} from './component'
+import type { ComponentInternalInstance, ComponentOptions } from './component'
import { invokeDirectiveHook } from './directives'
import { warn } from './warning'
import {
)
}
} else if (shapeFlag & ShapeFlags.COMPONENT) {
- if ((vnode.type as ConcreteComponent).__vapor) {
- throw new Error('Vapor component hydration is not supported yet.')
- }
-
// when setting up the render effect, if the initial vnode already
// has .el set, the component will perform hydration instead of mount
// on its sub-tree.
if (parent.vnode.el === oldNode) {
parent.vnode.el = parent.subTree.el = newNode
}
- parent = parent.parent as ComponentInternalInstance
+ parent = parent.parent
}
}
}
}
if (vnode === root && instance.parent) {
- resolveCssVars(
- instance.parent as ComponentInternalInstance,
- instance.vnode,
- expectedMap,
- )
+ resolveCssVars(instance.parent, instance.vnode, expectedMap)
}
}
App,
AppConfig,
AppContext,
- GenericAppContext,
Plugin,
ObjectPlugin,
FunctionPlugin,
ObjectDirective,
FunctionDirective,
DirectiveArguments,
- DirectiveModifiers,
} from './directives'
export type { SuspenseBoundary } from './components/Suspense'
export type {
export const DeprecationTypes = (
__COMPAT__ ? _DeprecationTypes : null
) as typeof _DeprecationTypes
-
-// VAPOR -----------------------------------------------------------------------
-
-// **IMPORTANT** These APIs are exposed solely for @vue/runtime-vapor and may
-// change without notice between versions. User code should never rely on them.
-
-/**
- * these types cannot be marked internal because runtime-vapor's type relies on
- * them, but they should be considered internal
- * @private
- */
-export {
- type ComponentInternalOptions,
- type GenericComponentInstance,
- type LifecycleHook,
-} from './component'
-export { type NormalizedPropsOptions } from './componentProps'
-/**
- * @internal
- */
-export { type VaporInteropInterface } from './apiCreateApp'
-/**
- * @internal
- */
-export { type RendererInternals, MoveType } from './renderer'
-/**
- * @internal
- */
-export {
- baseNormalizePropsOptions,
- resolvePropValue,
- validateProps,
-} from './componentProps'
-/**
- * @internal
- */
-export { baseEmit, isEmitListener } from './componentEmits'
-/**
- * @internal
- */
-export { type SchedulerJob, queueJob, flushOnAppMount } from './scheduler'
-/**
- * @internal
- */
-export { expose, nextUid, validateComponentName } from './component'
-/**
- * @internal
- */
-export { pushWarningContext, popWarningContext } from './warning'
-/**
- * @internal
- */
-export {
- createAppAPI,
- type AppMountFn,
- type AppUnmountFn,
-} from './apiCreateApp'
-/**
- * @internal
- */
-export {
- currentInstance,
- simpleSetCurrentInstance,
-} from './componentCurrentInstance'
-/**
- * @internal
- */
-export { registerHMR, unregisterHMR } from './hmr'
-/**
- * @internal
- */
-export { startMeasure, endMeasure } from './profiling'
-/**
- * @internal
- */
-export { initFeatureFlags } from './featureFlags'
-/**
- * @internal
- */
-export { createInternalObject } from './internalObject'
/* eslint-disable no-restricted-globals */
-import { type GenericComponentInstance, formatComponentName } from './component'
+import {
+ type ComponentInternalInstance,
+ formatComponentName,
+} from './component'
import { devtoolsPerfEnd, devtoolsPerfStart } from './devtools'
let supported: boolean
let perf: Performance
-// To avoid the overhead of repeatedly calling Date.now(), we cache
-// and use the same timestamp for all event listeners attached in the same tick.
-let cachedNow: number = 0
-const p = /*@__PURE__*/ Promise.resolve()
-const getNow = () =>
- cachedNow ||
- (p.then(() => (cachedNow = 0)),
- (cachedNow = isSupported() ? perf.now() : Date.now()))
-
-/**
- * @internal
- */
export function startMeasure(
- instance: GenericComponentInstance,
+ instance: ComponentInternalInstance,
type: string,
): void {
if (instance.appContext.config.performance && isSupported()) {
}
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- devtoolsPerfStart(instance, type, getNow())
+ devtoolsPerfStart(instance, type, isSupported() ? perf.now() : Date.now())
}
}
-/**
- * @internal
- */
export function endMeasure(
- instance: GenericComponentInstance,
+ instance: ComponentInternalInstance,
type: string,
): void {
if (instance.appContext.config.performance && isSupported()) {
}
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- devtoolsPerfEnd(instance, type, getNow())
+ devtoolsPerfEnd(instance, type, isSupported() ? perf.now() : Date.now())
}
}
type VNodeArrayChildren,
type VNodeHook,
type VNodeProps,
- VaporSlot,
cloneIfMounted,
- cloneVNode,
createVNode,
invokeVNodeHook,
isSameVNodeType,
import {
type ComponentInternalInstance,
type ComponentOptions,
- type ConcreteComponent,
type Data,
- type GenericComponentInstance,
type LifecycleHook,
createComponentInstance,
- getComponentPublicInstance,
setupComponent,
} from './component'
import {
ShapeFlags,
def,
getGlobalThis,
- getSequence,
invokeArrayFns,
isArray,
isReservedProp,
type SchedulerJob,
SchedulerJobFlags,
type SchedulerJobs,
- flushOnAppMount,
+ flushPostFlushCbs,
flushPreFlushCbs,
queueJob,
queuePostFlushCb,
import { updateProps } from './componentProps'
import { updateSlots } from './componentSlots'
import { popWarningContext, pushWarningContext, warn } from './warning'
-import {
- type AppMountFn,
- type AppUnmountFn,
- type CreateAppFunction,
- createAppAPI,
-} from './apiCreateApp'
+import { type CreateAppFunction, createAppAPI } from './apiCreateApp'
import { setRef } from './rendererTemplateRef'
import {
type SuspenseBoundary,
import { isCompatEnabled } from './compat/compatConfig'
import { DeprecationTypes } from './compat/compatConfig'
import type { TransitionHooks } from './components/BaseTransition'
-import type { VaporInteropInterface } from './apiCreateApp'
import type { VueElement } from '@vue/runtime-dom'
export interface Renderer<HostElement = RendererElement> {
render: RootRenderFunction<HostElement>
createApp: CreateAppFunction<HostElement>
- internals: RendererInternals
}
export interface HydrationRenderer extends Renderer<Element | ShadowRoot> {
r: RemoveFn
m: MoveFn
mt: MountComponentFn
- umt: UnmountComponentFn
mc: MountChildrenFn
pc: PatchChildrenFn
pbc: PatchBlockChildrenFn
container: RendererElement,
anchor: RendererNode | null,
type: MoveType,
- parentComponent: ComponentInternalInstance | null,
parentSuspense?: SuspenseBoundary | null,
) => void
optimized: boolean,
) => void
-export type UnmountComponentFn = (
- instance: ComponentInternalInstance,
- parentSuspense: SuspenseBoundary | null,
- doRemove?: boolean,
-) => void
-
type ProcessTextOrCommentFn = (
n1: VNode | null,
n2: VNode,
optimized,
)
break
- case VaporSlot:
- getVaporInterface(parentComponent, n2).slot(n1, n2, container, anchor)
- break
default:
if (shapeFlag & ShapeFlags.ELEMENT) {
processElement(
vnode: VNode,
scopeId: string | null,
slotScopeIds: string[] | null,
- parentComponent: GenericComponentInstance | null,
+ parentComponent: ComponentInternalInstance | null,
) => {
if (scopeId) {
hostSetScopeId(el, scopeId)
hostSetScopeId(el, slotScopeIds[i])
}
}
- let subTree = parentComponent && parentComponent.subTree
- if (subTree) {
+ if (parentComponent) {
+ let subTree = parentComponent.subTree
if (
__DEV__ &&
subTree.patchFlag > 0 &&
(isSuspense(subTree.type) &&
(subTree.ssContent === vnode || subTree.ssFallback === vnode))
) {
- const parentVNode = parentComponent!.vnode!
+ const parentVNode = parentComponent.vnode
setScopeId(
el,
parentVNode,
parentVNode.scopeId,
parentVNode.slotScopeIds,
- parentComponent!.parent,
+ parentComponent.parent,
)
}
}
optimized: boolean,
) => {
n2.slotScopeIds = slotScopeIds
-
- if ((n2.type as ConcreteComponent).__vapor) {
- if (n1 == null) {
- getVaporInterface(parentComponent, n2).mount(
- n2,
- container,
- anchor,
- parentComponent,
- )
- } else {
- getVaporInterface(parentComponent, n2).update(
- n1,
- n2,
- shouldUpdateComponent(n1, n2, optimized),
- )
- }
- } else if (n1 == null) {
+ if (n1 == null) {
if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
;(parentComponent!.ctx as KeepAliveContext).activate(
n2,
} else {
// custom element style injection
if (
- (root as ComponentInternalInstance).ce &&
+ root.ce &&
// @ts-expect-error _def is private
- ((root as ComponentInternalInstance).ce as VueElement)._def
- .shadowRoot !== false
+ (root.ce as VueElement)._def.shadowRoot !== false
) {
- ;(root as ComponentInternalInstance).ce!._injectChildStyle(type)
+ root.ce._injectChildStyle(type)
}
if (__DEV__) {
if (
initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE ||
(parent &&
- parent.vnode &&
isAsyncWrapper(parent.vnode) &&
parent.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE)
) {
// There is no stable subsequence (e.g. a reverse)
// OR current node is not among the stable sequence
if (j < 0 || i !== increasingNewIndexSequence[j]) {
- move(
- nextChild,
- container,
- anchor,
- MoveType.REORDER,
- parentComponent,
- )
+ move(nextChild, container, anchor, MoveType.REORDER)
} else {
j--
}
container,
anchor,
moveType,
- parentComponent,
parentSuspense = null,
) => {
const { el, type, transition, children, shapeFlag } = vnode
if (shapeFlag & ShapeFlags.COMPONENT) {
- if ((type as ConcreteComponent).__vapor) {
- getVaporInterface(parentComponent, vnode).move(vnode, container, anchor)
- } else {
- move(
- vnode.component!.subTree,
- container,
- anchor,
- moveType,
- parentComponent,
- )
- }
+ move(vnode.component!.subTree, container, anchor, moveType)
return
}
}
if (shapeFlag & ShapeFlags.TELEPORT) {
- ;(type as typeof TeleportImpl).move(
- vnode,
- container,
- anchor,
- internals,
- parentComponent,
- )
+ ;(type as typeof TeleportImpl).move(vnode, container, anchor, internals)
return
}
if (type === Fragment) {
hostInsert(el!, container, anchor)
for (let i = 0; i < (children as VNode[]).length; i++) {
- move(
- (children as VNode[])[i],
- container,
- anchor,
- moveType,
- parentComponent,
- )
+ move((children as VNode[])[i], container, anchor, moveType)
}
hostInsert(vnode.anchor!, container, anchor)
return
}
if (shapeFlag & ShapeFlags.COMPONENT) {
- if ((type as ConcreteComponent).__vapor) {
- getVaporInterface(parentComponent, vnode).unmount(vnode, doRemove)
- return
- } else {
- unmountComponent(vnode.component!, parentSuspense, doRemove)
- }
+ unmountComponent(vnode.component!, parentSuspense, doRemove)
} else {
if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
vnode.suspense!.unmount(parentSuspense, doRemove)
unmountChildren(children as VNode[], parentComponent, parentSuspense)
}
- if (type === VaporSlot) {
- getVaporInterface(parentComponent, vnode).unmount(vnode, doRemove)
- return
- }
-
if (doRemove) {
remove(vnode)
}
hostRemove(end)
}
- const unmountComponent: UnmountComponentFn = (
- instance,
- parentSuspense,
- doRemove,
+ const unmountComponent = (
+ instance: ComponentInternalInstance,
+ parentSuspense: SuspenseBoundary | null,
+ doRemove?: boolean,
) => {
if (__DEV__ && instance.type.__hmrId) {
unregisterHMR(instance)
// remove slots content from parent renderCache
if (parent && isArray(slotCacheKeys)) {
slotCacheKeys.forEach(v => {
- ;(parent as ComponentInternalInstance).renderCache[v] = undefined
+ parent.renderCache[v] = undefined
})
}
const getNextHostNode: NextFn = vnode => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT) {
- if ((vnode.type as ConcreteComponent).__vapor) {
- return hostNextSibling((vnode.component! as any).block)
- }
return getNextHostNode(vnode.component!.subTree)
}
if (__FEATURE_SUSPENSE__ && vnode.shapeFlag & ShapeFlags.SUSPENSE) {
return teleportEnd ? hostNextSibling(teleportEnd) : el
}
+ let isFlushing = false
const render: RootRenderFunction = (vnode, container, namespace) => {
if (vnode == null) {
if (container._vnode) {
)
}
container._vnode = vnode
- flushOnAppMount()
+ if (!isFlushing) {
+ isFlushing = true
+ flushPreFlushCbs()
+ flushPostFlushCbs()
+ isFlushing = false
+ }
}
const internals: RendererInternals = {
m: move,
r: remove,
mt: mountComponent,
- umt: unmountComponent,
mc: mountChildren,
pc: patchChildren,
pbc: patchBlockChildren,
)
}
- const mountApp: AppMountFn<Element> = (
- app,
- container,
- isHydrate,
- namespace,
- ) => {
- const vnode = app._ceVNode || createVNode(app._component, app._props)
- // store app context on the root VNode.
- // this will be set on the root instance on initial mount.
- vnode.appContext = app._context
-
- if (namespace === true) {
- namespace = 'svg'
- } else if (namespace === false) {
- namespace = undefined
- }
-
- // HMR root reload
- if (__DEV__) {
- app._context.reload = () => {
- const cloned = cloneVNode(vnode)
- // avoid hydration for hmr updating
- cloned.el = null
- // casting to ElementNamespace because TS doesn't guarantee type narrowing
- // over function boundaries
- render(cloned, container, namespace as ElementNamespace)
- }
- }
-
- if (isHydrate && hydrate) {
- hydrate(vnode as VNode<Node, Element>, container as any)
- } else {
- render(vnode, container, namespace)
- }
-
- return vnode.component!
- }
-
- const unmountApp: AppUnmountFn = app => {
- render(null, app._container)
- }
-
return {
render,
hydrate,
- internals,
- createApp: createAppAPI(
- mountApp,
- unmountApp,
- getComponentPublicInstance as any,
- render,
- ),
+ createApp: createAppAPI(render, hydrate),
}
}
}
function toggleRecurse(
- { effect, job, vapor }: ComponentInternalInstance,
+ { effect, job }: ComponentInternalInstance,
allowed: boolean,
) {
- if (!vapor) {
- if (allowed) {
- effect.flags |= EffectFlags.ALLOW_RECURSE
- job.flags! |= SchedulerJobFlags.ALLOW_RECURSE
- } else {
- effect.flags &= ~EffectFlags.ALLOW_RECURSE
- job.flags! &= ~SchedulerJobFlags.ALLOW_RECURSE
- }
+ if (allowed) {
+ effect.flags |= EffectFlags.ALLOW_RECURSE
+ job.flags! |= SchedulerJobFlags.ALLOW_RECURSE
+ } else {
+ effect.flags &= ~EffectFlags.ALLOW_RECURSE
+ job.flags! &= ~SchedulerJobFlags.ALLOW_RECURSE
}
}
}
}
+// https://en.wikipedia.org/wiki/Longest_increasing_subsequence
+function getSequence(arr: number[]): number[] {
+ const p = arr.slice()
+ const result = [0]
+ let i, j, u, v, c
+ const len = arr.length
+ for (i = 0; i < len; i++) {
+ const arrI = arr[i]
+ if (arrI !== 0) {
+ j = result[result.length - 1]
+ if (arr[j] < arrI) {
+ p[i] = j
+ result.push(i)
+ continue
+ }
+ u = 0
+ v = result.length - 1
+ while (u < v) {
+ c = (u + v) >> 1
+ if (arr[result[c]] < arrI) {
+ u = c + 1
+ } else {
+ v = c
+ }
+ }
+ if (arrI < arr[result[u]]) {
+ if (u > 0) {
+ p[i] = result[u - 1]
+ }
+ result[u] = i
+ }
+ }
+ }
+ u = result.length
+ v = result[u - 1]
+ while (u-- > 0) {
+ result[u] = v
+ v = p[v]
+ }
+ return result
+}
+
function locateNonHydratedAsyncRoot(
instance: ComponentInternalInstance,
): ComponentInternalInstance | undefined {
}
}
-export function invalidateMount(hooks: LifecycleHook | undefined): void {
+export function invalidateMount(hooks: LifecycleHook): void {
if (hooks) {
for (let i = 0; i < hooks.length; i++)
hooks[i].flags! |= SchedulerJobFlags.DISPOSED
}
}
-
-function getVaporInterface(
- instance: ComponentInternalInstance | null,
- vnode: VNode,
-): VaporInteropInterface {
- const ctx = instance ? instance.appContext : vnode.appContext
- const res = ctx && ctx.vapor
- if (__DEV__ && !res) {
- warn(
- `Vapor component found in vdom tree but vapor-in-vdom interop was not installed. ` +
- `Make sure to install it:\n` +
- `\`\`\`\nimport { vaporInteropPlugin } from 'vue'\n` +
- `app.use(vaporInteropPlugin)\n` +
- `\`\`\``,
- )
- }
- return res!
-}
import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
import { NOOP, isArray } from '@vue/shared'
-import { type GenericComponentInstance, getComponentName } from './component'
+import { type ComponentInternalInstance, getComponentName } from './component'
export enum SchedulerJobFlags {
QUEUED = 1 << 0,
* Attached by renderer.ts when setting up a component's render effect
* Used to obtain component information when reporting max recursive updates.
*/
- i?: GenericComponentInstance
+ i?: ComponentInternalInstance
}
export type SchedulerJobs = SchedulerJob | SchedulerJob[]
return start
}
-/**
- * @internal for runtime-vapor only
- */
export function queueJob(job: SchedulerJob): void {
if (!(job.flags! & SchedulerJobFlags.QUEUED)) {
const jobId = getId(job)
function queueFlush() {
if (!currentFlushPromise) {
- currentFlushPromise = resolvedPromise.then(flushJobs).catch(e => {
- currentFlushPromise = null
- throw e
- })
+ currentFlushPromise = resolvedPromise.then(flushJobs)
}
}
}
export function flushPreFlushCbs(
- instance?: GenericComponentInstance,
+ instance?: ComponentInternalInstance,
seen?: CountMap,
// skip the current job
i: number = flushIndex + 1,
if (cb.flags! & SchedulerJobFlags.ALLOW_RECURSE) {
cb.flags! &= ~SchedulerJobFlags.QUEUED
}
- if (!(cb.flags! & SchedulerJobFlags.DISPOSED)) {
- try {
- cb()
- } finally {
- cb.flags! &= ~SchedulerJobFlags.QUEUED
- }
- }
+ if (!(cb.flags! & SchedulerJobFlags.DISPOSED)) cb()
+ cb.flags! &= ~SchedulerJobFlags.QUEUED
}
activePostFlushCbs = null
postFlushIndex = 0
}
}
-let isFlushing = false
-/**
- * @internal
- */
-export function flushOnAppMount(): void {
- if (!isFlushing) {
- isFlushing = true
- flushPreFlushCbs()
- flushPostFlushCbs()
- isFlushing = false
- }
-}
-
const getId = (job: SchedulerJob): number =>
job.id == null ? (job.flags! & SchedulerJobFlags.PRE ? -1 : Infinity) : job.id
type ComponentInternalInstance,
type ConcreteComponent,
type Data,
- type GenericComponentInstance,
isClassComponent,
} from './component'
import type { RawSlots } from './componentSlots'
import {
type ReactiveFlags,
type Ref,
- type ShallowRef,
isProxy,
isRef,
toRaw,
export const Text: unique symbol = Symbol.for('v-txt')
export const Comment: unique symbol = Symbol.for('v-cmt')
export const Static: unique symbol = Symbol.for('v-stc')
-export const VaporSlot: unique symbol = Symbol.for('v-vps')
export type VNodeTypes =
| string
| typeof TeleportImpl
| typeof Suspense
| typeof SuspenseImpl
- | typeof VaporSlot
export type VNodeRef =
| string
* @internal custom element interception hook
*/
ce?: (instance: ComponentInternalInstance) => void
- /**
- * @internal VDOM in Vapor interop hook
- */
- vi?: (instance: ComponentInternalInstance) => void
- /**
- * @internal Vapor slot in VDOM metadata
- */
- vs?: {
- slot: (props: any) => any
- fallback: (() => VNodeArrayChildren) | undefined
- ref?: ShallowRef<any>
- }
- /**
- * @internal Vapor slot Block
- */
- vb?: any
}
// Since v-if and v-for are the two possible ways node structure can dynamically
export function invokeVNodeHook(
hook: VNodeHook,
- instance: GenericComponentInstance | null,
+ instance: ComponentInternalInstance | null,
vnode: VNode,
prevVNode: VNode | null = null,
): void {
+import type { VNode } from './vnode'
import {
+ type ComponentInternalInstance,
+ type ConcreteComponent,
type Data,
- type GenericComponentInstance,
formatComponentName,
} from './component'
import { isFunction, isString } from '@vue/shared'
import { isRef, pauseTracking, resetTracking, toRaw } from '@vue/reactivity'
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
-import { type VNode, isVNode } from './vnode'
-const stack: (GenericComponentInstance | VNode)[] = []
+type ComponentVNode = VNode & {
+ type: ConcreteComponent
+}
+
+const stack: VNode[] = []
type TraceEntry = {
- ctx: GenericComponentInstance | VNode
+ vnode: ComponentVNode
recurseCount: number
}
type ComponentTraceStack = TraceEntry[]
-/**
- * @internal
- */
-export function pushWarningContext(
- ctx: GenericComponentInstance | VNode,
-): void {
- stack.push(ctx)
+export function pushWarningContext(vnode: VNode): void {
+ stack.push(vnode)
}
-/**
- * @internal
- */
export function popWarningContext(): void {
stack.pop()
}
// during patch, leading to infinite recursion.
pauseTracking()
- const entry = stack.length ? stack[stack.length - 1] : null
- const instance = isVNode(entry) ? entry.component : entry
+ const instance = stack.length ? stack[stack.length - 1].component : null
const appWarnHandler = instance && instance.appContext.config.warnHandler
const trace = getComponentTrace()
[
// eslint-disable-next-line no-restricted-syntax
msg + args.map(a => a.toString?.() ?? JSON.stringify(a)).join(''),
- (instance && instance.proxy) || instance,
+ instance && instance.proxy,
trace
.map(
- ({ ctx }) =>
- `at <${formatComponentName(instance, (ctx as any).type)}>`,
+ ({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>`,
)
.join('\n'),
trace,
}
export function getComponentTrace(): ComponentTraceStack {
- let currentCtx: TraceEntry['ctx'] | null = stack[stack.length - 1]
- if (!currentCtx) {
+ let currentVNode: VNode | null = stack[stack.length - 1]
+ if (!currentVNode) {
return []
}
// instance parent pointers.
const normalizedStack: ComponentTraceStack = []
- while (currentCtx) {
+ while (currentVNode) {
const last = normalizedStack[0]
- if (last && last.ctx === currentCtx) {
+ if (last && last.vnode === currentVNode) {
last.recurseCount++
} else {
normalizedStack.push({
- ctx: currentCtx,
+ vnode: currentVNode as ComponentVNode,
recurseCount: 0,
})
}
- if (isVNode(currentCtx)) {
- const parent: GenericComponentInstance | null =
- currentCtx.component && currentCtx.component.parent
- currentCtx = (parent && parent.vnode) || parent
- } else {
- currentCtx = currentCtx.parent
- }
+ const parentInstance: ComponentInternalInstance | null =
+ currentVNode.component && currentVNode.component.parent
+ currentVNode = parentInstance && parentInstance.vnode
}
return normalizedStack
return logs
}
-function formatTraceEntry({ ctx, recurseCount }: TraceEntry): any[] {
+function formatTraceEntry({ vnode, recurseCount }: TraceEntry): any[] {
const postfix =
recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``
- const instance = isVNode(ctx) ? ctx.component : ctx
- const isRoot = instance ? instance.parent == null : false
- const open = ` at <${formatComponentName(instance, (ctx as any).type, isRoot)}`
+ const isRoot = vnode.component ? vnode.component.parent == null : false
+ const open = ` at <${formatComponentName(
+ vnode.component,
+ vnode.type,
+ isRoot,
+ )}`
const close = `>` + postfix
- return ctx.props ? [open, ...formatProps(ctx.props), close] : [open + close]
+ return vnode.props
+ ? [open, ...formatProps(vnode.props), close]
+ : [open + close]
}
function formatProps(props: Data): any[] {
vtcKey,
} from './Transition'
import {
- type ComponentInternalInstance,
type ComponentOptions,
DeprecationTypes,
Fragment,
!rawProps.tag &&
compatUtils.checkCompatEnabled(
DeprecationTypes.TRANSITION_GROUP_ROOT,
- instance.parent as ComponentInternalInstance,
+ instance.parent,
)
) {
tag = 'span'
> = {
created(el, { modifiers: { lazy, trim, number } }, vnode) {
el[assignKey] = getModelAssigner(vnode)
- vModelTextInit(
- el,
- trim,
- number || !!(vnode.props && vnode.props.type === 'number'),
- lazy,
- )
+ const castToNumber =
+ number || (vnode.props && vnode.props.type === 'number')
+ addEventListener(el, lazy ? 'change' : 'input', e => {
+ if ((e.target as any).composing) return
+ let domValue: string | number = el.value
+ if (trim) {
+ domValue = domValue.trim()
+ }
+ if (castToNumber) {
+ domValue = looseToNumber(domValue)
+ }
+ el[assignKey](domValue)
+ })
+ if (trim) {
+ addEventListener(el, 'change', () => {
+ el.value = el.value.trim()
+ })
+ }
+ if (!lazy) {
+ addEventListener(el, 'compositionstart', onCompositionStart)
+ addEventListener(el, 'compositionend', onCompositionEnd)
+ // Safari < 10.2 & UIWebView doesn't fire compositionend when
+ // switching focus before confirming composition choice
+ // this also fixes the issue where some browsers e.g. iOS Chrome
+ // fires "change" instead of "input" on autocomplete.
+ addEventListener(el, 'change', onCompositionEnd)
+ }
},
// set value on mounted so it's after min/max for type="range"
mounted(el, { value }) {
vnode,
) {
el[assignKey] = getModelAssigner(vnode)
- vModelTextUpdate(el, oldValue, value, trim, number, lazy)
- },
-}
-
-/**
- * @internal
- */
-export const vModelTextInit = (
- el: HTMLInputElement | HTMLTextAreaElement,
- trim: boolean | undefined,
- number: boolean | undefined,
- lazy: boolean | undefined,
- set?: (v: any) => void,
-): void => {
- addEventListener(el, lazy ? 'change' : 'input', e => {
- if ((e.target as any).composing) return
- let domValue: string | number = el.value
- if (trim) {
- domValue = domValue.trim()
- }
- if (number || el.type === 'number') {
- domValue = looseToNumber(domValue)
- }
- ;(set || (el as any)[assignKey])(domValue)
- })
- if (trim) {
- addEventListener(el, 'change', () => {
- el.value = el.value.trim()
- })
- }
- if (!lazy) {
- addEventListener(el, 'compositionstart', onCompositionStart)
- addEventListener(el, 'compositionend', onCompositionEnd)
- // Safari < 10.2 & UIWebView doesn't fire compositionend when
- // switching focus before confirming composition choice
- // this also fixes the issue where some browsers e.g. iOS Chrome
- // fires "change" instead of "input" on autocomplete.
- addEventListener(el, 'change', onCompositionEnd)
- }
-}
-
-/**
- * @internal
- */
-export const vModelTextUpdate = (
- el: HTMLInputElement | HTMLTextAreaElement,
- oldValue: any,
- value: any,
- trim: boolean | undefined,
- number: boolean | undefined,
- lazy: boolean | undefined,
-): void => {
- // avoid clearing unresolved text. #2302
- if ((el as any).composing) return
- const elValue =
- (number || el.type === 'number') && !/^0\d/.test(el.value)
- ? looseToNumber(el.value)
- : el.value
- const newValue = value == null ? '' : value
-
- if (elValue === newValue) {
- return
- }
-
- if (document.activeElement === el && el.type !== 'range') {
- // #8546
- if (lazy && value === oldValue) {
+ // avoid clearing unresolved text. #2302
+ if ((el as any).composing) return
+ const elValue =
+ (number || el.type === 'number') && !/^0\d/.test(el.value)
+ ? looseToNumber(el.value)
+ : el.value
+ const newValue = value == null ? '' : value
+
+ if (elValue === newValue) {
return
}
- if (trim && el.value.trim() === newValue) {
- return
+
+ if (document.activeElement === el && el.type !== 'range') {
+ // #8546
+ if (lazy && value === oldValue) {
+ return
+ }
+ if (trim && el.value.trim() === newValue) {
+ return
+ }
}
- }
- el.value = newValue
+ el.value = newValue
+ },
}
export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
deep: true,
created(el, _, vnode) {
el[assignKey] = getModelAssigner(vnode)
- vModelCheckboxInit(el)
+ addEventListener(el, 'change', () => {
+ const modelValue = (el as any)._modelValue
+ const elementValue = getValue(el)
+ const checked = el.checked
+ const assign = el[assignKey]
+ if (isArray(modelValue)) {
+ const index = looseIndexOf(modelValue, elementValue)
+ const found = index !== -1
+ if (checked && !found) {
+ assign(modelValue.concat(elementValue))
+ } else if (!checked && found) {
+ const filtered = [...modelValue]
+ filtered.splice(index, 1)
+ assign(filtered)
+ }
+ } else if (isSet(modelValue)) {
+ const cloned = new Set(modelValue)
+ if (checked) {
+ cloned.add(elementValue)
+ } else {
+ cloned.delete(elementValue)
+ }
+ assign(cloned)
+ } else {
+ assign(getCheckboxValue(el, checked))
+ }
+ })
},
// set initial checked on mount to wait for true-value/false-value
- mounted(el, binding, vnode) {
- vModelCheckboxUpdate(
- el,
- binding.oldValue,
- binding.value,
- vnode.props!.value,
- )
- },
+ mounted: setChecked,
beforeUpdate(el, binding, vnode) {
el[assignKey] = getModelAssigner(vnode)
- vModelCheckboxUpdate(
- el,
- binding.oldValue,
- binding.value,
- vnode.props!.value,
- )
+ setChecked(el, binding, vnode)
},
}
-/**
- * @internal
- */
-export const vModelCheckboxInit = (
- el: HTMLInputElement,
- set?: (v: any) => void,
-): void => {
- addEventListener(el, 'change', () => {
- const assign = set || (el as any)[assignKey]
- const modelValue = (el as any)._modelValue
- const elementValue = getValue(el)
- const checked = el.checked
- if (isArray(modelValue)) {
- const index = looseIndexOf(modelValue, elementValue)
- const found = index !== -1
- if (checked && !found) {
- assign(modelValue.concat(elementValue))
- } else if (!checked && found) {
- const filtered = [...modelValue]
- filtered.splice(index, 1)
- assign(filtered)
- }
- } else if (isSet(modelValue)) {
- const cloned = new Set(modelValue)
- if (checked) {
- cloned.add(elementValue)
- } else {
- cloned.delete(elementValue)
- }
- assign(cloned)
- } else {
- assign(getCheckboxValue(el, checked))
- }
- })
-}
-
-/**
- * @internal
- */
-export const vModelCheckboxUpdate = (
+function setChecked(
el: HTMLInputElement,
- oldValue: any,
- value: any,
- rawValue: any = getValue(el),
-): void => {
+ { value, oldValue }: DirectiveBinding,
+ vnode: VNode,
+) {
// store the v-model value on the element so it can be accessed by the
// change listener.
;(el as any)._modelValue = value
let checked: boolean
if (isArray(value)) {
- checked = looseIndexOf(value, rawValue) > -1
+ checked = looseIndexOf(value, vnode.props!.value) > -1
} else if (isSet(value)) {
- checked = value.has(rawValue)
+ checked = value.has(vnode.props!.value)
} else {
if (value === oldValue) return
checked = looseEqual(value, getCheckboxValue(el, true))
// <select multiple> value need to be deep traversed
deep: true,
created(el, { value, modifiers: { number } }, vnode) {
- vModelSelectInit(el, value, number)
+ const isSetModel = isSet(value)
+ addEventListener(el, 'change', () => {
+ const selectedVal = Array.prototype.filter
+ .call(el.options, (o: HTMLOptionElement) => o.selected)
+ .map((o: HTMLOptionElement) =>
+ number ? looseToNumber(getValue(o)) : getValue(o),
+ )
+ el[assignKey](
+ el.multiple
+ ? isSetModel
+ ? new Set(selectedVal)
+ : selectedVal
+ : selectedVal[0],
+ )
+ el._assigning = true
+ nextTick(() => {
+ el._assigning = false
+ })
+ })
el[assignKey] = getModelAssigner(vnode)
},
// set value in mounted & updated because <select> relies on its children
// <option>s.
mounted(el, { value }) {
- vModelSetSelected(el, value)
+ setSelected(el, value)
},
beforeUpdate(el, _binding, vnode) {
el[assignKey] = getModelAssigner(vnode)
},
updated(el, { value }) {
- vModelSetSelected(el, value)
+ if (!el._assigning) {
+ setSelected(el, value)
+ }
},
}
-/**
- * @internal
- */
-export const vModelSelectInit = (
- el: HTMLSelectElement & { [assignKey]?: AssignerFn; _assigning?: boolean },
- value: any,
- number: boolean | undefined,
- set?: (v: any) => void,
-): void => {
- const isSetModel = isSet(value)
- addEventListener(el, 'change', () => {
- const selectedVal = Array.prototype.filter
- .call(el.options, (o: HTMLOptionElement) => o.selected)
- .map((o: HTMLOptionElement) =>
- number ? looseToNumber(getValue(o)) : getValue(o),
- )
- ;(set || el[assignKey]!)(
- el.multiple
- ? isSetModel
- ? new Set(selectedVal)
- : selectedVal
- : selectedVal[0],
- )
- el._assigning = true
- nextTick(() => {
- el._assigning = false
- })
- })
-}
-
-/**
- * @internal
- */
-export const vModelSetSelected = (el: HTMLSelectElement, value: any): void => {
- if ((el as any)._assigning) return
+function setSelected(el: HTMLSelectElement, value: any) {
const isMultiple = el.multiple
const isArrayValue = isArray(value)
if (isMultiple && !isArrayValue && !isSet(value)) {
}
}
-/**
- * @internal retrieve raw value set via :value bindings
- */
-export function getValue(el: HTMLOptionElement | HTMLInputElement): any {
+// retrieve raw value set via :value bindings
+function getValue(el: HTMLOptionElement | HTMLInputElement) {
return '_value' in el ? (el as any)._value : el.value
}
checked: boolean,
) {
const key = checked ? '_trueValue' : '_falseValue'
- if (key in el) {
- return el[key]
- }
- const attr = checked ? 'true-value' : 'false-value'
- if (el.hasAttribute(attr)) {
- return el.getAttribute(attr)
- }
- return checked
+ return key in el ? el[key] : checked
}
export const vModelDynamic: ObjectDirective<
import type { ObjectDirective } from '@vue/runtime-core'
export const vShowOriginalDisplay: unique symbol = Symbol('_vod')
-
export const vShowHidden: unique symbol = Symbol('_vsh')
export interface VShowElement extends HTMLElement {
// _vod = vue original display
- [vShowOriginalDisplay]?: string
- [vShowHidden]?: boolean
+ [vShowOriginalDisplay]: string
+ [vShowHidden]: boolean
}
export const vShow: ObjectDirective<VShowElement> & { name?: 'show' } = {
}
function setDisplay(el: VShowElement, value: unknown): void {
- el.style.display = value ? el[vShowOriginalDisplay]! : 'none'
+ el.style.display = value ? el[vShowOriginalDisplay] : 'none'
el[vShowHidden] = !value
}
import {
type App,
- type Component,
- type ConcreteComponent,
type CreateAppFunction,
type DefineComponent,
DeprecationTypes,
let enabledHydration = false
-function ensureRenderer(): Renderer<Element | ShadowRoot> {
+function ensureRenderer() {
return (
renderer ||
(renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
const container = normalizeContainer(containerOrSelector)
if (!container) return
- const component = app._component as ConcreteComponent
+ const component = app._component
if (!isFunction(component) && !component.render && !component.template) {
// __UNSAFE__
// Reason: potential execution of JS expressions in in-DOM template.
}
return app
-}) as CreateAppFunction<Element, Component>
+}) as CreateAppFunction<Element>
export const createSSRApp = ((...args) => {
const app = ensureHydrationRenderer().createApp(...args)
}
}
-/**
- * @internal
- */
-function normalizeContainer<T extends ParentNode>(
- container: T | string,
-): T | null {
+function normalizeContainer(
+ container: Element | ShadowRoot | string,
+): Element | ShadowRoot | null {
if (isString(container)) {
const res = document.querySelector(container)
if (__DEV__ && !res) {
`Failed to mount app: mount target selector "${container}" returned null.`,
)
}
- return res as any
+ return res
}
if (
__DEV__ &&
export * from '@vue/runtime-core'
export * from './jsx'
-
-// VAPOR -----------------------------------------------------------------------
-// Everything below are exposed for vapor only and can change any time.
-// They are also trimmed from non-bundler builds.
-
-/**
- * @internal
- */
-export { ensureRenderer, normalizeContainer }
-/**
- * @internal
- */
-export { patchStyle } from './modules/style'
-/**
- * @internal
- */
-export { shouldSetAsProp } from './patchProp'
-/**
- * @internal
- */
-export {
- vShowOriginalDisplay,
- vShowHidden,
- type VShowElement,
-} from './directives/vShow'
-/**
- * @internal
- */
-export {
- vModelTextInit,
- vModelTextUpdate,
- vModelCheckboxInit,
- vModelCheckboxUpdate,
- getValue as vModelGetValue,
- vModelSelectInit,
- vModelSetSelected,
-} from './directives/vModel'
import { DeprecationTypes, compatUtils, warn } from '@vue/runtime-core'
-import { canSetValueDirectly, includeBooleanAttr } from '@vue/shared'
+import { includeBooleanAttr } from '@vue/shared'
import { unsafeToTrustedHTML } from '../nodeOps'
// functions. The user is responsible for using them with only trusted content.
const tag = el.tagName
- if (key === 'value' && canSetValueDirectly(tag)) {
+ if (
+ key === 'value' &&
+ tag !== 'PROGRESS' &&
+ // custom elements may use _value internally
+ !tag.includes('-')
+ ) {
// #4956: <option> value will fallback to its text content so we need to
// compare against its attribute value instead.
const oldValue =
} from '../directives/vShow'
import { CSS_VAR_TEXT } from '../helpers/useCssVars'
-type Style = string | null | undefined | Record<string, unknown>
+type Style = string | Record<string, string | string[]> | null
const displayRE = /(^|;)\s*display\s*:/
const semicolonRE = /[^\\];\s*$/
const importantRE = /\s*!important$/
-function setStyle(style: CSSStyleDeclaration, name: string, rawVal: unknown) {
- if (isArray(rawVal)) {
- rawVal.forEach(v => setStyle(style, name, v))
+function setStyle(
+ style: CSSStyleDeclaration,
+ name: string,
+ val: string | string[],
+) {
+ if (isArray(val)) {
+ val.forEach(v => setStyle(style, name, v))
} else {
- const val = rawVal == null ? '' : String(rawVal)
+ if (val == null) val = ''
if (__DEV__) {
if (semicolonRE.test(val)) {
warn(
camelize,
isFunction,
isModelListener,
- isNativeOn,
isOn,
isString,
- shouldSetAsAttr,
} from '@vue/shared'
import type { RendererOptions } from '@vue/runtime-core'
import type { VueElement } from './apiCustomElement'
+const isNativeOn = (key: string) =>
+ key.charCodeAt(0) === 111 /* o */ &&
+ key.charCodeAt(1) === 110 /* n */ &&
+ // lowercase letter
+ key.charCodeAt(2) > 96 &&
+ key.charCodeAt(2) < 123
+
type DOMRendererOptions = RendererOptions<Node, Element>
export const patchProp: DOMRendererOptions['patchProp'] = (
}
}
-export function shouldSetAsProp(
+function shouldSetAsProp(
el: Element,
key: string,
value: unknown,
isSVG: boolean,
-): boolean {
+) {
if (isSVG) {
// most keys must be set as attribute on svg elements to work
// ...except innerHTML & textContent
return false
}
- if (shouldSetAsAttr(el.tagName, key)) {
+ // these are enumerated attrs, however their corresponding DOM properties
+ // are actually booleans - this leads to setting it with a string "false"
+ // value leading it to be coerced to `true`, so we need to always treat
+ // them as attributes.
+ // Note that `contentEditable` doesn't have this problem: its DOM
+ // property is also enumerated string values.
+ if (
+ key === 'spellcheck' ||
+ key === 'draggable' ||
+ key === 'translate' ||
+ key === 'autocorrect'
+ ) {
+ return false
+ }
+
+ // #1787, #2840 form property on form elements is readonly and must be set as
+ // attribute.
+ if (key === 'form') {
+ return false
+ }
+
+ // #1526 <input list> must be set as attribute
+ if (key === 'list' && el.tagName === 'INPUT') {
return false
}
+ // #2766 <textarea type> must be set as attribute
+ if (key === 'type' && el.tagName === 'TEXTAREA') {
+ return false
+ }
+
+ // #8780 the width or height of embedded tags must be set as attribute
+ if (key === 'width' || key === 'height') {
+ const tag = el.tagName
+ if (
+ tag === 'IMG' ||
+ tag === 'VIDEO' ||
+ tag === 'CANVAS' ||
+ tag === 'SOURCE'
+ ) {
+ return false
+ }
+ }
+
// native onclick with string value, must be set as attribute
if (isNativeOn(key) && isString(value)) {
return false
+++ /dev/null
-The MIT License (MIT)
-
-Copyright (c) 2018-present, Yuxi (Evan) You
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-# @vue/runtime-vapor
-
-This package only ships `esm-bundler` build because:
-
-1. Vapor mode requires SFC build.
-2. Vapor mode runtime only runs in the browser.
-
-The main `vue` package ships `dist/vue.runtime-with-vapor.esm-browser.js` which inlines this package. It is used for the SFC Playground only.
+++ /dev/null
-import { createVaporApp, vaporInteropPlugin } from '../src'
-import { type App, type Component, createApp } from '@vue/runtime-dom'
-import type { VaporComponent, VaporComponentInstance } from '../src/component'
-import type { RawProps } from '../src/componentProps'
-
-export interface RenderContext {
- component: VaporComponent
- host: HTMLElement
- instance: VaporComponentInstance | 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 = VaporComponent>(
- initHost = (): HTMLDivElement => {
- const host = document.createElement('div')
- host.setAttribute('id', 'host')
- document.body.appendChild(host)
- return host
- },
-): (comp: C) => RenderContext {
- let host: HTMLElement
- function resetHost() {
- return (host = initHost())
- }
-
- beforeEach(() => {
- resetHost()
- })
- afterEach(() => {
- host.remove()
- })
-
- function define(comp: C) {
- const component = comp as any
- component.__vapor = true
- let instance: VaporComponentInstance | undefined
- let app: App
-
- function render(
- props: RawProps | undefined = undefined,
- container: string | ParentNode = host,
- ) {
- create(props)
- return mount(container)
- }
-
- function create(props: RawProps | undefined = undefined) {
- app?.unmount()
- app = createVaporApp(component, props)
- return res()
- }
-
- function mount(container: string | ParentNode = host) {
- app.mount(container)
- instance = app._instance as VaporComponentInstance
- return res()
- }
-
- function html() {
- return host.innerHTML
- }
-
- const res = () => ({
- component,
- host,
- instance,
- app,
- create,
- mount,
- render,
- resetHost,
- html,
- })
-
- return res()
- }
-
- return define
-}
-
-export interface InteropRenderContext {
- mount: (container?: string | ParentNode) => InteropRenderContext
- render: (
- props?: RawProps,
- container?: string | ParentNode,
- ) => InteropRenderContext
- host: HTMLElement
- html: () => string
-}
-
-export function makeInteropRender(): (comp: Component) => InteropRenderContext {
- let host: HTMLElement
- beforeEach(() => {
- host = document.createElement('div')
- })
- afterEach(() => {
- host.remove()
- })
-
- function define(comp: Component) {
- let app: App
- function render(
- props: RawProps | undefined = undefined,
- container: string | ParentNode = host,
- ) {
- app?.unmount()
- app = createApp(comp, props)
- app.use(vaporInteropPlugin)
- return mount(container)
- }
-
- function mount(container: string | ParentNode = host) {
- app.mount(container)
- return res()
- }
-
- function html() {
- return host.innerHTML
- }
-
- const res = () => ({
- host,
- mount,
- render,
- html,
- })
-
- return res()
- }
-
- return define
-}
+++ /dev/null
-import { ref, shallowRef } from '@vue/reactivity'
-import { nextTick, resolveDynamicComponent } from '@vue/runtime-dom'
-import {
- createComponentWithFallback,
- createDynamicComponent,
- defineVaporComponent,
- renderEffect,
- setHtml,
- setInsertionState,
- template,
-} from '../src'
-import { makeRender } from './_utils'
-
-const define = makeRender()
-
-describe('api: createDynamicComponent', () => {
- const A = () => document.createTextNode('AAA')
- const B = () => document.createTextNode('BBB')
-
- test('direct value', async () => {
- const val = shallowRef<any>(A)
-
- const { html } = define({
- setup() {
- return createDynamicComponent(() => val.value)
- },
- }).render()
-
- expect(html()).toBe('AAA<!--dynamic-component-->')
-
- val.value = B
- await nextTick()
- expect(html()).toBe('BBB<!--dynamic-component-->')
-
- // fallback
- val.value = 'foo'
- await nextTick()
- expect(html()).toBe('<foo></foo><!--dynamic-component-->')
- })
-
- test('global registration', async () => {
- const val = shallowRef('foo')
-
- const { app, html, mount } = define({
- setup() {
- return createDynamicComponent(() => val.value)
- },
- }).create()
-
- app.component('foo', A)
- app.component('bar', B)
-
- mount()
- expect(html()).toBe('AAA<!--dynamic-component-->')
-
- val.value = 'bar'
- await nextTick()
- expect(html()).toBe('BBB<!--dynamic-component-->')
-
- // fallback
- val.value = 'baz'
- await nextTick()
- expect(html()).toBe('<baz></baz><!--dynamic-component-->')
- })
-
- test('render fallback with insertionState', async () => {
- const { html, mount } = define({
- setup() {
- const html = ref('hi')
- const n1 = template('<div></div>', true)() as any
- setInsertionState(n1)
- const n0 = createComponentWithFallback(
- resolveDynamicComponent('button') as any,
- ) as any
- renderEffect(() => setHtml(n0, html.value))
- return n1
- },
- }).create()
-
- mount()
- expect(html()).toBe('<div><button>hi</button></div>')
- })
-
- test('switch dynamic component children', async () => {
- const CompA = defineVaporComponent({
- setup() {
- return template('<div>A</div>')()
- },
- })
- const CompB = defineVaporComponent({
- setup() {
- return template('<div>B</div>')()
- },
- })
-
- const current = shallowRef(CompA)
- const { html } = define({
- setup() {
- const t1 = template('<div></div>')
- const n2 = t1() as any
- setInsertionState(n2)
- createDynamicComponent(() => current.value)
- return n2
- },
- }).render()
-
- expect(html()).toBe('<div><div>A</div><!--dynamic-component--></div>')
-
- current.value = CompB
- await nextTick()
- expect(html()).toBe('<div><div>B</div><!--dynamic-component--></div>')
- })
-})
+++ /dev/null
-import { ref } from '@vue/reactivity'
-import { makeRender } from './_utils'
-// @ts-expect-error
-import { createFor, createSelector, renderEffect } from '../src'
-import { nextTick } from '@vue/runtime-dom'
-
-const define = makeRender()
-
-describe.todo('api: createSelector', () => {
- test('basic', async () => {
- let calledTimes = 0
- let expectedCalledTimes = 0
-
- const list = ref([{ id: 0 }, { id: 1 }, { id: 2 }])
- const index = ref(0)
-
- const { host } = define(() => {
- const isSleected = createSelector(index)
- return createFor(
- () => list.value,
- item => {
- const span = document.createElement('li')
- renderEffect(() => {
- calledTimes += 1
- const { id } = item.value
- span.textContent = `${id}.${isSleected(id) ? 't' : 'f'}`
- })
- return span
- },
- item => item.id,
- )
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>0.t</li><li>1.f</li><li>2.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 3))
-
- index.value = 1
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0.f</li><li>1.t</li><li>2.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 2))
-
- index.value = 2
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0.f</li><li>1.f</li><li>2.t</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 2))
-
- list.value[2].id = 3
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0.f</li><li>1.f</li><li>3.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 1))
- })
-
- test('custom compare', async () => {
- let calledTimes = 0
- let expectedCalledTimes = 0
-
- const list = ref([{ id: 1 }, { id: 2 }, { id: 3 }])
- const index = ref(0)
-
- const { host } = define(() => {
- const isSleected = createSelector(
- index,
- // @ts-expect-error
- (key, value) => key === value + 1,
- )
- return createFor(
- () => list.value,
- item => {
- const span = document.createElement('li')
- renderEffect(() => {
- calledTimes += 1
- const { id } = item.value
- span.textContent = `${id}.${isSleected(id) ? 't' : 'f'}`
- })
- return span
- },
- item => item.id,
- )
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>1.t</li><li>2.f</li><li>3.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 3))
-
- index.value = 1
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>1.f</li><li>2.t</li><li>3.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 2))
-
- index.value = 2
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>1.f</li><li>2.f</li><li>3.t</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 2))
-
- list.value[2].id = 4
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>1.f</li><li>2.f</li><li>4.f</li><!--for-->',
- )
- expect(calledTimes).toBe((expectedCalledTimes += 1))
- })
-})
+++ /dev/null
-import {
- createComponent,
- createTextNode,
- createVaporApp,
- defineVaporComponent,
- // @ts-expect-error
- withDirectives,
-} from '../src'
-import {
- type GenericComponentInstance,
- type Plugin,
- currentInstance,
- inject,
- provide,
- resolveComponent,
- resolveDirective,
- warn,
-} from '@vue/runtime-dom'
-import { makeRender } from './_utils'
-import type { VaporComponent } from '../src/component'
-
-const define = makeRender()
-
-describe('api: createVaporApp', () => {
- test('mount', () => {
- const Comp = defineVaporComponent({
- props: {
- count: { default: 0 },
- },
- setup(props) {
- return createTextNode(String(props.count))
- },
- })
-
- const root1 = document.createElement('div')
- createVaporApp(Comp).mount(root1)
- expect(root1.innerHTML).toBe(`0`)
-
- //#5571 mount multiple apps to the same host element
- createVaporApp(Comp).mount(root1)
- expect(`mount target container is not empty`).toHaveBeenWarned()
- expect(
- `There is already an app instance mounted on the host container`,
- ).toHaveBeenWarned()
-
- // mount with props
- const root2 = document.createElement('div')
- const app2 = createVaporApp(Comp, { count: () => 1 })
- app2.mount(root2)
- expect(root2.innerHTML).toBe(`1`)
-
- // remount warning
- const root3 = document.createElement('div')
- app2.mount(root3)
- expect(root3.innerHTML).toBe(``)
- expect(`already been mounted`).toHaveBeenWarned()
- })
-
- test('unmount', () => {
- const Comp = defineVaporComponent({
- props: {
- count: { default: 0 },
- },
- setup(props) {
- return createTextNode(String(props.count))
- },
- })
-
- const root = document.createElement('div')
- const app = createVaporApp(Comp)
-
- // warning
- app.unmount()
- expect(`that is not mounted`).toHaveBeenWarned()
-
- app.mount(root)
-
- app.unmount()
- expect(root.innerHTML).toBe(``)
- })
-
- test('provide', () => {
- const Root = define({
- setup() {
- // test override
- provide('foo', 3)
- return createComponent(Child)
- },
- })
-
- const Child = defineVaporComponent({
- setup() {
- const foo = inject('foo')
- const bar = inject('bar')
- try {
- inject('__proto__')
- } catch (e: any) {}
- return createTextNode(`${foo},${bar}`)
- },
- })
-
- const { app, mount, create, html } = Root.create()
- app.provide('foo', 1)
- app.provide('bar', 2)
- mount()
- expect(html()).toBe(`3,2`)
- expect('[Vue warn]: injection "__proto__" not found.').toHaveBeenWarned()
-
- const { app: app2 } = create()
- app2.provide('bar', 1)
- app2.provide('bar', 2)
- expect(`App already provides property with key "bar".`).toHaveBeenWarned()
- })
-
- test('runWithContext', () => {
- const { app } = define({
- setup() {
- provide('foo', 'should not be seen')
- return document.createElement('div')
- },
- }).create()
- app.provide('foo', 1)
-
- expect(app.runWithContext(() => inject('foo'))).toBe(1)
-
- expect(
- app.runWithContext(() => {
- app.runWithContext(() => {})
- return inject('foo')
- }),
- ).toBe(1)
-
- // ensure the context is restored
- inject('foo')
- expect('inject() can only be used inside setup').toHaveBeenWarned()
- })
-
- test('component', () => {
- const { app, mount, host } = define({
- setup() {
- const FooBar = resolveComponent('foo-bar') as VaporComponent
- const BarBaz = resolveComponent('bar-baz') as VaporComponent
- return [createComponent(FooBar), createComponent(BarBaz)]
- },
- }).create()
-
- const FooBar = () => createTextNode('foobar!')
- app.component('FooBar', FooBar)
- expect(app.component('FooBar')).toBe(FooBar)
-
- app.component('BarBaz', () => createTextNode('barbaz!'))
- app.component('BarBaz', () => createTextNode('barbaz!'))
- expect(
- 'Component "BarBaz" has already been registered in target app.',
- ).toHaveBeenWarnedTimes(1)
-
- mount()
- expect(host.innerHTML).toBe(`foobar!barbaz!`)
- })
-
- test.todo('directive', () => {
- const spy1 = vi.fn()
- const spy2 = vi.fn()
-
- const { app, mount } = define({
- setup() {
- const FooBar = resolveDirective('foo-bar')
- const BarBaz = resolveDirective('bar-baz')
- return withDirectives(document.createElement('div'), [
- [FooBar],
- [BarBaz],
- ])
- },
- }).create()
-
- const FooBar = spy1
- app.directive('FooBar', FooBar)
- expect(app.directive('FooBar')).toBe(FooBar)
-
- app.directive('BarBaz', spy2)
- app.directive('BarBaz', spy2)
- expect(
- 'Directive "BarBaz" has already been registered in target app.',
- ).toHaveBeenWarnedTimes(1)
-
- mount()
- expect(spy1).toHaveBeenCalled()
- expect(spy2).toHaveBeenCalled()
-
- app.directive('bind', FooBar)
- expect(
- `Do not use built-in directive ids as custom directive id: bind`,
- ).toHaveBeenWarned()
- })
-
- test('use', () => {
- const PluginA: Plugin = app => app.provide('foo', 1)
- const PluginB: Plugin = {
- install: (app, arg1, arg2) => app.provide('bar', arg1 + arg2),
- }
- class PluginC {
- someProperty = {}
- static install() {
- app.provide('baz', 2)
- }
- }
- const PluginD: any = undefined
-
- const { app, host, mount } = define({
- setup() {
- const foo = inject('foo')
- const bar = inject('bar')
- return document.createTextNode(`${foo},${bar}`)
- },
- }).create()
-
- app.use(PluginA)
- app.use(PluginB, 1, 1)
- app.use(PluginC)
-
- mount()
- expect(host.innerHTML).toBe(`1,2`)
-
- app.use(PluginA)
- expect(
- `Plugin has already been applied to target app`,
- ).toHaveBeenWarnedTimes(1)
-
- app.use(PluginD)
- expect(
- `A plugin must either be a function or an object with an "install" ` +
- `function.`,
- ).toHaveBeenWarnedTimes(1)
- })
-
- test('config.errorHandler', () => {
- const error = new Error()
- let instance: GenericComponentInstance
-
- const handler = vi.fn((err, _instance, info) => {
- expect(err).toBe(error)
- expect(_instance).toBe(instance)
- expect(info).toBe(`render function`)
- })
-
- const { app, mount } = define({
- setup() {
- instance = currentInstance!
- return {}
- },
- render() {
- throw error
- },
- }).create()
- app.config.errorHandler = handler
- mount()
- expect(handler).toHaveBeenCalled()
- })
-
- test('config.warnHandler', () => {
- let instance: GenericComponentInstance
-
- const handler = vi.fn((msg, _instance, trace) => {
- expect(msg).toMatch(`warn message`)
- expect(_instance).toBe(instance)
- expect(trace).toMatch(`Hello`)
- })
-
- const { app, mount } = define({
- name: 'Hello',
- setup() {
- instance = currentInstance!
- warn('warn message')
- return []
- },
- }).create()
-
- app.config.warnHandler = handler
- mount()
- expect(handler).toHaveBeenCalledTimes(1)
- })
-
- describe('config.isNativeTag', () => {
- const isNativeTag = vi.fn(tag => tag === 'div')
-
- // Not relevant for vapor
- // test('Component.name', () => {
- // const { app, mount } = define({
- // name: 'div',
- // render(): any {},
- // }).create()
-
- // Object.defineProperty(app.config, 'isNativeTag', {
- // value: isNativeTag,
- // writable: false,
- // })
-
- // mount()
- // expect(
- // `Do not use built-in or reserved HTML elements as component id: div`,
- // ).toHaveBeenWarned()
- // })
-
- test('register using app.component', () => {
- const { app, mount } = define({
- render(): any {},
- }).create()
-
- Object.defineProperty(app.config, 'isNativeTag', {
- value: isNativeTag,
- writable: false,
- })
-
- app.component('div', () => createTextNode('div'))
- mount()
- expect(
- `Do not use built-in or reserved HTML elements as component id: div`,
- ).toHaveBeenWarned()
- })
- })
-
- describe('config.performance', () => {
- afterEach(() => {
- window.performance.clearMeasures()
- })
-
- test('with performance enabled', () => {
- const { app, mount } = define({ setup: () => [] }).create()
-
- app.config.performance = true
- mount()
- expect(window.performance.getEntries()).lengthOf(2)
- })
-
- test('with performance disabled', () => {
- const { app, mount } = define({ setup: () => [] }).create()
-
- app.config.performance = false
- mount()
- expect(window.performance.getEntries()).lengthOf(0)
- })
- })
-
- test('config.globalProperty', () => {
- const { app } = define({
- setup() {
- return []
- },
- }).create()
- try {
- app.config.globalProperties.msg = 'hello world'
- } catch (e) {}
- expect(
- `app.config.globalProperties is not supported in vapor mode`,
- ).toHaveBeenWarned()
- })
-})
+++ /dev/null
-import { ref, shallowRef } from '@vue/reactivity'
-import { type VaporComponentInstance, createComponent } from '../src/component'
-import { setRef } from '../src/apiTemplateRef'
-import { makeRender } from './_utils'
-import { currentInstance } from '@vue/runtime-dom'
-import { defineVaporComponent } from '../src/apiDefineComponent'
-
-const define = makeRender()
-
-describe('api: expose', () => {
- test('via setup context + template ref', () => {
- let i: any
- const Child = defineVaporComponent({
- setup(_, { expose }) {
- expose({
- foo: 1,
- bar: ref(2),
- })
- return []
- },
- })
- const childRef = ref()
- define({
- setup: () => {
- const n0 = (i = createComponent(Child))
- setRef(currentInstance as VaporComponentInstance, n0, childRef)
- return n0
- },
- }).render()
-
- expect(childRef.value).toBe(i.exposeProxy)
- expect(childRef.value.foo).toBe(1)
- expect(childRef.value.bar).toBe(2)
- expect(childRef.value.baz).toBeUndefined()
- })
-
- test('via setup context + template ref (expose empty)', () => {
- let childInstance: VaporComponentInstance | null = null
- const Child = defineVaporComponent({
- setup(_) {
- childInstance = currentInstance as VaporComponentInstance
- return []
- },
- })
- const childRef = shallowRef()
- define({
- setup: () => {
- const n0 = createComponent(Child)
- setRef(currentInstance as VaporComponentInstance, n0, childRef)
- return n0
- },
- }).render()
-
- expect(childInstance!.exposed).toBeNull()
- expect(childRef.value).toBe(childInstance!)
- })
-
- test('with mount', () => {
- const { app, host } = define({
- setup(_, { expose }) {
- expose({
- foo: 1,
- })
- return []
- },
- }).create()
- const exposed = app.mount(host) as any
- expect(exposed.foo).toBe(1)
- expect(exposed.bar).toBe(undefined)
- })
-
- test('warning for ref', () => {
- define({
- setup(_, { expose }) {
- expose(ref(1))
- return []
- },
- }).render()
-
- expect(
- 'expose() should be passed a plain object, received ref',
- ).toHaveBeenWarned()
- })
-
- test('warning for array', () => {
- define({
- setup(_, { expose }) {
- expose(['focus'])
- return []
- },
- }).render()
-
- expect(
- 'expose() should be passed a plain object, received array',
- ).toHaveBeenWarned()
- })
-
- test('warning for function', () => {
- define({
- setup(_, { expose }) {
- expose(() => null)
- return []
- },
- }).render()
-
- expect(
- 'expose() should be passed a plain object, received function',
- ).toHaveBeenWarned()
- })
-})
+++ /dev/null
-import {
- type InjectionKey,
- type Ref,
- hasInjectionContext,
- inject,
- nextTick,
- provide,
- reactive,
- readonly,
- ref,
- toDisplayString,
-} from '@vue/runtime-dom'
-import {
- createComponent,
- createTextNode,
- createVaporApp,
- renderEffect,
-} from '../src'
-import { makeRender } from './_utils'
-import { setElementText } from '../src/dom/prop'
-
-const define = makeRender<any>()
-
-// reference: https://vue-composition-api-rfc.netlify.com/api.html#provide-inject
-describe('api: provide/inject', () => {
- it('string keys', () => {
- const Provider = define({
- setup() {
- provide('foo', 1)
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render() {
- return createComponent(Consumer)
- },
- }
-
- const Consumer = {
- setup() {
- const foo = inject('foo')
- return (() => {
- const n0 = createTextNode()
- setElementText(n0, foo)
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('1')
- })
-
- it('symbol keys', () => {
- // also verifies InjectionKey type sync
- const key: InjectionKey<number> = Symbol()
-
- const Provider = define({
- setup() {
- provide(key, 1)
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- const foo = inject(key)
- return (() => {
- const n0 = createTextNode()
- setElementText(n0, foo)
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('1')
- })
-
- it('default values', () => {
- const Provider = define({
- setup() {
- provide('foo', 'foo')
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- // default value should be ignored if value is provided
- const foo = inject('foo', 'fooDefault')
- // default value should be used if value is not provided
- const bar = inject('bar', 'bar')
- return (() => {
- const n0 = createTextNode()
- setElementText(n0, foo + bar)
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('foobar')
- })
-
- // NOTE: Options API is not supported
- // it('bound to instance', () => {})
-
- it('nested providers', () => {
- const ProviderOne = define({
- setup() {
- provide('foo', 'foo')
- provide('bar', 'bar')
- return createComponent(ProviderTwo)
- },
- })
-
- const ProviderTwo = {
- setup() {
- // override parent value
- provide('foo', 'fooOverride')
- provide('baz', 'baz')
- return createComponent(Consumer)
- },
- }
-
- const Consumer = {
- setup() {
- const foo = inject('foo')
- const bar = inject('bar')
- const baz = inject('baz')
- return (() => {
- const n0 = createTextNode()
- setElementText(n0, [foo, bar, baz].join(','))
- return n0
- })()
- },
- }
-
- ProviderOne.render()
- expect(ProviderOne.host.innerHTML).toBe('fooOverride,bar,baz')
- })
-
- it('reactivity with refs', async () => {
- const count = ref(1)
-
- const Provider = define({
- setup() {
- provide('count', count)
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- const count = inject<Ref<number>>('count')!
- return (() => {
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, count.value)
- })
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('1')
-
- count.value++
- await nextTick()
- expect(Provider.host.innerHTML).toBe('2')
- })
-
- it('reactivity with readonly refs', async () => {
- const count = ref(1)
-
- const Provider = define({
- setup() {
- provide('count', readonly(count))
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- const count = inject<Ref<number>>('count')!
- // should not work
- count.value++
- return (() => {
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, count.value)
- })
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('1')
-
- expect(
- `Set operation on key "value" failed: target is readonly`,
- ).toHaveBeenWarned()
-
- count.value++
- await nextTick()
- expect(Provider.host.innerHTML).toBe('2')
- })
-
- it('reactivity with objects', async () => {
- const rootState = reactive({ count: 1 })
-
- const Provider = define({
- setup() {
- provide('state', rootState)
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- const state = inject<typeof rootState>('state')!
- return (() => {
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, state.count)
- })
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('1')
-
- rootState.count++
- await nextTick()
- expect(Provider.host.innerHTML).toBe('2')
- })
-
- it('reactivity with readonly objects', async () => {
- const rootState = reactive({ count: 1 })
-
- const Provider = define({
- setup() {
- provide('state', readonly(rootState))
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- const state = inject<typeof rootState>('state')!
- // should not work
- state.count++
- return (() => {
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, state.count)
- })
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('1')
-
- expect(
- `Set operation on key "count" failed: target is readonly`,
- ).toHaveBeenWarned()
-
- rootState.count++
- await nextTick()
- expect(Provider.host.innerHTML).toBe('2')
- })
-
- it('should warn unfound', () => {
- const Provider = define({
- setup() {
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- const foo = inject('foo')
- expect(foo).toBeUndefined()
- return (() => {
- const n0 = createTextNode()
- setElementText(n0, foo)
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(Provider.host.innerHTML).toBe('')
- expect(`injection "foo" not found.`).toHaveBeenWarned()
- })
-
- it('should not warn when default value is undefined', () => {
- const Provider = define({
- setup() {
- return createComponent(Middle)
- },
- })
-
- const Middle = {
- render: () => createComponent(Consumer),
- }
-
- const Consumer = {
- setup() {
- const foo = inject('foo', undefined)
- return (() => {
- const n0 = createTextNode()
- setElementText(n0, foo)
- return n0
- })()
- },
- }
-
- Provider.render()
- expect(`injection "foo" not found.`).not.toHaveBeenWarned()
- })
-
- // #2400
- it('should not self-inject', () => {
- const { host } = define({
- setup() {
- provide('foo', 'foo')
- const injection = inject('foo', null)
- return createTextNode(toDisplayString(injection))
- },
- }).render()
- expect(host.innerHTML).toBe('')
- })
-
- describe('hasInjectionContext', () => {
- it('should be false outside of setup', () => {
- expect(hasInjectionContext()).toBe(false)
- })
-
- it('should be true within setup', () => {
- expect.assertions(1)
- const Comp = define({
- setup() {
- expect(hasInjectionContext()).toBe(true)
- return []
- },
- })
-
- Comp.render()
- })
-
- it('should be true within app.runWithContext()', () => {
- expect.assertions(1)
- createVaporApp({}).runWithContext(() => {
- expect(hasInjectionContext()).toBe(true)
- })
- })
- })
-})
+++ /dev/null
-import {
- type DebuggerEvent,
- type InjectionKey,
- type Ref,
- TrackOpTypes,
- TriggerOpTypes,
- currentInstance,
- inject,
- nextTick,
- onBeforeMount,
- onBeforeUnmount,
- onBeforeUpdate,
- onMounted,
- onRenderTracked,
- onRenderTriggered,
- onUnmounted,
- onUpdated,
- provide,
- reactive,
- ref,
-} from '@vue/runtime-dom'
-import {
- createComponent,
- createFor,
- createIf,
- createTextNode,
- insert,
- renderEffect,
- template,
-} from '../src'
-import { makeRender } from './_utils'
-import { ITERATE_KEY } from '@vue/reactivity'
-import { setElementText } from '../src/dom/prop'
-
-const define = makeRender<any>()
-
-describe('api: lifecycle hooks', () => {
- it('onBeforeMount', () => {
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe(``)
- })
- const { render, host } = define({
- setup() {
- onBeforeMount(fn)
- return []
- },
- })
- render()
- expect(fn).toHaveBeenCalledTimes(1)
- })
-
- it('onMounted', () => {
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe(``)
- })
- const { render, host } = define({
- setup() {
- onMounted(fn)
- return []
- },
- })
- render()
- expect(fn).toHaveBeenCalledTimes(1)
- })
-
- it('onBeforeUpdate', async () => {
- const count = ref(0)
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('0')
- })
- const { render, host } = define({
- setup() {
- onBeforeUpdate(fn)
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, count.value)
- })
- return n0
- },
- })
- render()
- count.value++
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(1)
- expect(host.innerHTML).toBe('1')
- })
-
- it('state mutation in onBeforeUpdate', async () => {
- const count = ref(0)
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('0')
- count.value++
- })
- const renderSpy = vi.fn()
-
- const { render, host } = define({
- setup() {
- onBeforeUpdate(fn)
- const n0 = createTextNode()
- renderEffect(() => {
- renderSpy()
- setElementText(n0, count.value)
- })
- return n0
- },
- })
- render()
- expect(renderSpy).toHaveBeenCalledTimes(1)
- })
-
- it('onUpdated', async () => {
- const count = ref(0)
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('1')
- })
-
- const { render, host } = define({
- setup() {
- onUpdated(fn)
-
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, count.value)
- })
- return n0
- },
- })
- render()
-
- count.value++
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(1)
- })
-
- it('onBeforeUnmount', async () => {
- const toggle = ref(true)
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('<div></div><!--if-->')
- })
- const { render, host } = define({
- setup() {
- const n0 = createIf(
- () => toggle.value,
- () => createComponent(Child),
- )
- return n0
- },
- })
-
- const Child = {
- setup() {
- onBeforeUnmount(fn)
-
- const t0 = template('<div></div>')
- const n0 = t0()
- return n0
- },
- }
-
- render()
-
- toggle.value = false
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(1)
- expect(host.innerHTML).toBe('<!--if-->')
- })
-
- it('onUnmounted', async () => {
- const toggle = ref(true)
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('<!--if-->')
- })
- const { render, host } = define({
- setup() {
- const n0 = createIf(
- () => toggle.value,
- () => createComponent(Child),
- )
- return n0
- },
- })
-
- const Child = {
- setup() {
- onUnmounted(fn)
-
- const t0 = template('<div></div>')
- const n0 = t0()
- return n0
- },
- }
-
- render()
-
- toggle.value = false
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(1)
- expect(host.innerHTML).toBe('<!--if-->')
- })
-
- it('onBeforeUnmount in onMounted', async () => {
- const toggle = ref(true)
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('<div></div><!--if-->')
- })
- const { render, host } = define({
- setup() {
- const n0 = createIf(
- () => toggle.value,
- () => createComponent(Child),
- )
- return n0
- },
- })
-
- const Child = {
- setup() {
- onMounted(() => {
- onBeforeUnmount(fn)
- })
-
- const t0 = template('<div></div>')
- const n0 = t0()
- return n0
- },
- }
-
- render()
-
- toggle.value = false
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(1)
- expect(host.innerHTML).toBe('<!--if-->')
- })
-
- it('lifecycle call order', async () => {
- const count = ref(0)
- const toggle = ref(true)
- const calls: string[] = []
-
- const { render } = define({
- setup() {
- onBeforeMount(() => calls.push('root onBeforeMount'))
- onMounted(() => calls.push('root onMounted'))
- onBeforeUpdate(() => calls.push('root onBeforeUpdate'))
- onUpdated(() => calls.push('root onUpdated'))
- onBeforeUnmount(() => calls.push('root onBeforeUnmount'))
- onUnmounted(() => calls.push('root onUnmounted'))
-
- const n0 = createIf(
- () => toggle.value,
- () => createComponent(Mid, { count: () => count.value }),
- )
- return n0
- },
- })
-
- const Mid = {
- props: ['count'],
- setup(props: any) {
- onBeforeMount(() => calls.push('mid onBeforeMount'))
- onMounted(() => calls.push('mid onMounted'))
- onBeforeUpdate(() => calls.push('mid onBeforeUpdate'))
- onUpdated(() => calls.push('mid onUpdated'))
- onBeforeUnmount(() => calls.push('mid onBeforeUnmount'))
- onUnmounted(() => calls.push('mid onUnmounted'))
-
- const n0 = createComponent(Child, { count: () => props.count })
- return n0
- },
- }
-
- const Child = {
- props: ['count'],
- setup(props: any) {
- onBeforeMount(() => calls.push('child onBeforeMount'))
- onMounted(() => calls.push('child onMounted'))
- onBeforeUpdate(() => calls.push('child onBeforeUpdate'))
- onUpdated(() => calls.push('child onUpdated'))
- onBeforeUnmount(() => calls.push('child onBeforeUnmount'))
- onUnmounted(() => calls.push('child onUnmounted'))
-
- const t0 = template('<div></div>')
- const n0 = t0()
- renderEffect(() => setElementText(n0, props.count))
- return n0
- },
- }
-
- // mount
- const ctx = render()
- expect(calls).toEqual([
- 'root onBeforeMount',
- 'mid onBeforeMount',
- 'child onBeforeMount',
- 'child onMounted',
- 'mid onMounted',
- 'root onMounted',
- ])
-
- calls.length = 0
-
- // update
- count.value++
- await nextTick()
- // only child updated
- expect(calls).toEqual(['child onBeforeUpdate', 'child onUpdated'])
-
- calls.length = 0
-
- // unmount
- ctx.app.unmount()
- await nextTick()
- expect(calls).toEqual([
- 'root onBeforeUnmount',
- 'mid onBeforeUnmount',
- 'child onBeforeUnmount',
- 'child onUnmounted',
- 'mid onUnmounted',
- 'root onUnmounted',
- ])
- })
-
- it('onRenderTracked', async () => {
- const events: DebuggerEvent[] = []
- const onTrack = vi.fn((e: DebuggerEvent) => {
- events.push(e)
- })
- const obj = reactive({ foo: 1, bar: 2 })
-
- const { render } = define({
- setup() {
- onRenderTracked(onTrack)
-
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, [obj.foo, 'bar' in obj, Object.keys(obj).join('')])
- })
- return n0
- },
- })
-
- render()
- expect(onTrack).toHaveBeenCalledTimes(3)
- expect(events).toMatchObject([
- {
- target: obj,
- type: TrackOpTypes.GET,
- key: 'foo',
- },
- {
- target: obj,
- type: TrackOpTypes.HAS,
- key: 'bar',
- },
- {
- target: obj,
- type: TrackOpTypes.ITERATE,
- key: ITERATE_KEY,
- },
- ])
- })
-
- it('onRenderTrigger', async () => {
- const events: DebuggerEvent[] = []
- const onTrigger = vi.fn((e: DebuggerEvent) => {
- events.push(e)
- })
- const obj = reactive<{
- foo: number
- bar?: number
- }>({ foo: 1, bar: 2 })
-
- const { render } = define({
- setup() {
- onRenderTriggered(onTrigger)
-
- const n0 = createTextNode()
- renderEffect(() => {
- setElementText(n0, [obj.foo, 'bar' in obj, Object.keys(obj).join('')])
- })
- return n0
- },
- })
-
- render()
-
- obj.foo++
- await nextTick()
- expect(onTrigger).toHaveBeenCalledTimes(1)
- expect(events[0]).toMatchObject({
- type: TriggerOpTypes.SET,
- key: 'foo',
- oldValue: 1,
- newValue: 2,
- })
-
- delete obj.bar
- await nextTick()
- expect(onTrigger).toHaveBeenCalledTimes(2)
- expect(events[1]).toMatchObject({
- type: TriggerOpTypes.DELETE,
- key: 'bar',
- oldValue: 2,
- })
- ;(obj as any).baz = 3
- await nextTick()
- expect(onTrigger).toHaveBeenCalledTimes(3)
- expect(events[2]).toMatchObject({
- type: TriggerOpTypes.ADD,
- key: 'baz',
- newValue: 3,
- })
- })
-
- it('runs shared hook fn for each instance', async () => {
- const fn = vi.fn()
- const toggle = ref(true)
- const { render } = define({
- setup() {
- return createIf(
- () => toggle.value,
- () => [createComponent(Child), createComponent(Child)],
- )
- },
- })
- const Child = {
- setup() {
- onBeforeMount(fn)
- onBeforeUnmount(fn)
- return template('<div></div>')()
- },
- }
-
- render()
- expect(fn).toHaveBeenCalledTimes(2)
- toggle.value = false
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(4)
- })
-
- // #136
- it('should trigger updated hooks across components. (parent -> child)', async () => {
- const handleUpdated = vi.fn()
- const handleUpdatedChild = vi.fn()
-
- const count = ref(0)
-
- const { render, host } = define({
- setup() {
- onUpdated(() => handleUpdated())
-
- const n0 = createTextNode()
- renderEffect(() => setElementText(n0, count.value))
- const n1 = createComponent(Child, { count: () => count.value })
- return [n0, n1]
- },
- })
-
- const Child = {
- props: { count: Number },
- setup() {
- onUpdated(() => handleUpdatedChild())
-
- const props = currentInstance!.props
- const n2 = createTextNode()
- renderEffect(() => setElementText(n2, props.count))
- return n2
- },
- }
-
- render()
-
- expect(host.innerHTML).toBe('00')
- expect(handleUpdated).toHaveBeenCalledTimes(0)
- expect(handleUpdatedChild).toHaveBeenCalledTimes(0)
-
- count.value++
- await nextTick()
- expect(host.innerHTML).toBe('11')
- expect(handleUpdated).toHaveBeenCalledTimes(1)
- expect(handleUpdatedChild).toHaveBeenCalledTimes(1)
- })
-
- // #136
- it('should trigger updated hooks across components. (child -> parent)', async () => {
- const handleUpdated = vi.fn()
- const handleUpdatedChild = vi.fn()
-
- const key: InjectionKey<Ref<number>> = Symbol()
-
- const { render, host } = define({
- setup() {
- const count = ref(0)
- provide(key, count)
- onUpdated(() => handleUpdated())
-
- const n0 = createTextNode()
- renderEffect(() => setElementText(n0, count.value))
- const n1 = createComponent(Child, { count: () => count.value })
- return [n0, n1]
- },
- })
-
- let update: any
- const Child = {
- props: { count: Number },
- setup() {
- onUpdated(() => handleUpdatedChild())
- const count = inject(key)!
- update = () => count.value++
-
- const n2 = createTextNode()
- renderEffect(() => setElementText(n2, count.value))
- return n2
- },
- }
-
- render()
-
- expect(host.innerHTML).toBe('00')
- expect(handleUpdated).toHaveBeenCalledTimes(0)
- expect(handleUpdatedChild).toHaveBeenCalledTimes(0)
-
- update()
- await nextTick()
- expect(host.innerHTML).toBe('11')
- expect(handleUpdated).toHaveBeenCalledTimes(1)
- expect(handleUpdatedChild).toHaveBeenCalledTimes(1)
- })
-
- test('unmount hooks when nested in if block', async () => {
- const toggle = ref(true)
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('<div><span></span></div><!--if-->')
- })
- const fn2 = vi.fn(() => {
- expect(host.innerHTML).toBe('<!--if-->')
- })
- const { render, host } = define({
- setup() {
- const n0 = createIf(
- () => toggle.value,
- () => {
- const n1 = document.createElement('div')
- const n2 = createComponent(Child)
- insert(n2, n1)
- return n1
- },
- )
- return n0
- },
- })
-
- const Child = {
- setup() {
- onBeforeUnmount(fn)
- onUnmounted(fn2)
-
- const t0 = template('<span></span>')
- const n0 = t0()
- return n0
- },
- }
-
- render()
-
- toggle.value = false
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(1)
- expect(fn2).toHaveBeenCalledTimes(1)
- expect(host.innerHTML).toBe('<!--if-->')
- })
-
- test('unmount hooks when nested in for blocks', async () => {
- const list = ref([1])
- const fn = vi.fn(() => {
- expect(host.innerHTML).toBe('<div><span></span></div><!--for-->')
- })
- const fn2 = vi.fn(() => {
- expect(host.innerHTML).toBe('<!--for-->')
- })
- const { render, host } = define({
- setup() {
- const n0 = createFor(
- () => list.value,
- () => {
- const n1 = document.createElement('div')
- const n2 = createComponent(Child)
- insert(n2, n1)
- return n1
- },
- )
- return n0
- },
- })
-
- const Child = {
- setup() {
- onBeforeUnmount(fn)
- onUnmounted(fn2)
-
- const t0 = template('<span></span>')
- const n0 = t0()
- return n0
- },
- }
-
- render()
-
- list.value.pop()
- await nextTick()
- expect(fn).toHaveBeenCalledTimes(1)
- expect(fn2).toHaveBeenCalledTimes(1)
- expect(host.innerHTML).toBe('<!--for-->')
- })
-})
+++ /dev/null
-import {
- createComponent,
- createSlot,
- createTextNode,
- defineVaporComponent,
- delegate,
- delegateEvents,
- insert,
- renderEffect,
- setDynamicProps,
- setText,
- template,
-} from '../src'
-import { nextTick, reactive, ref, watchEffect } from '@vue/runtime-dom'
-import { makeRender } from './_utils'
-
-const define = makeRender()
-
-describe('api: setup context', () => {
- it('should expose return values to template render context', () => {
- const { html } = define({
- setup() {
- return {
- ref: ref('foo'),
- object: reactive({ msg: 'bar' }),
- value: 'baz',
- }
- },
- render(ctx) {
- return createTextNode(`${ctx.ref} ${ctx.object.msg} ${ctx.value}`)
- },
- }).render()
- expect(html()).toMatch(`foo bar baz`)
- })
-
- it('should support returning render function', () => {
- const { html } = define({
- setup() {
- return createTextNode(`hello`)
- },
- }).render()
- expect(html()).toMatch(`hello`)
- })
-
- it('props', async () => {
- const count = ref(0)
- let dummy
-
- const Child = defineVaporComponent({
- props: { count: Number },
- setup(props) {
- watchEffect(() => {
- dummy = props.count
- })
- const n = createTextNode()
- renderEffect(() => {
- setText(n, props.count)
- })
- return n
- },
- })
-
- const { html } = define({
- render: () => createComponent(Child, { count: () => count.value }),
- }).render()
-
- expect(html()).toMatch(`0`)
-
- count.value++
- await nextTick()
- expect(dummy).toBe(1)
- expect(html()).toMatch(`1`)
- })
-
- it('context.attrs', async () => {
- const toggle = ref(true)
-
- const Child = defineVaporComponent({
- inheritAttrs: false,
- setup(_props, { attrs }) {
- const el = document.createElement('div')
- renderEffect(() => setDynamicProps(el, [attrs]))
- return el
- },
- })
-
- const { html } = define({
- render: () =>
- createComponent(Child, {
- $: [() => (toggle.value ? { id: 'foo' } : { class: 'baz' })],
- }),
- }).render()
-
- expect(html()).toMatch(`<div id="foo"></div>`)
-
- toggle.value = false
- await nextTick()
- expect(html()).toMatch(`<div class="baz"></div>`)
- })
-
- // #4161
- it('context.attrs in child component slots', async () => {
- const toggle = ref(true)
-
- const Wrapper = defineVaporComponent({
- setup(_) {
- const n0 = createSlot('default')
- return n0
- },
- })
-
- const Child = defineVaporComponent({
- inheritAttrs: false,
- setup(_: any, { attrs }: any) {
- const n0 = createComponent(Wrapper, null, {
- default: () => {
- const n0 = template('<div>')() as HTMLDivElement
- renderEffect(() => setDynamicProps(n0, [attrs]))
- return n0
- },
- })
- return n0
- },
- })
-
- const { html } = define({
- render: () =>
- createComponent(Child, {
- $: [() => (toggle.value ? { id: 'foo' } : { class: 'baz' })],
- }),
- }).render()
-
- expect(html()).toMatch(`<div id="foo"></div>`)
-
- // should update even though it's not reactive
- toggle.value = false
- await nextTick()
- expect(html()).toMatch(`<div class="baz"></div>`)
- })
-
- it('context.slots', async () => {
- const id = ref('foo')
-
- const Child = defineVaporComponent({
- render() {
- return [createSlot('foo'), createSlot('bar')]
- },
- })
-
- const { html } = define({
- render() {
- return createComponent(Child, null, {
- $: [
- () => ({
- name: 'foo',
- fn: () => {
- const n = createTextNode()
- renderEffect(() => setText(n, id.value))
- return n
- },
- }),
- () => ({
- name: 'bar',
- fn: () => createTextNode('bar'),
- }),
- ],
- })
- },
- }).render()
-
- expect(html()).toMatch(`foo<!--slot-->bar<!--slot-->`)
-
- id.value = 'baz'
- await nextTick()
- expect(html()).toMatch(`baz<!--slot-->bar<!--slot-->`)
- })
-
- it('context.emit', async () => {
- const count = ref(0)
- const spy = vi.fn()
-
- delegateEvents('click')
-
- const Child = defineVaporComponent({
- props: {
- count: { type: Number, default: 1 },
- },
- setup(props, { emit }) {
- const n0 = template('<div>')() as HTMLDivElement
- delegate(n0, 'click', () => {
- emit('inc', props.count + 1)
- })
- const n = createTextNode()
- renderEffect(() => setText(n, props.count))
- insert(n, n0)
- return n0
- },
- })
-
- const { host, html } = define({
- render: () =>
- createComponent(Child, {
- count: () => count.value,
- onInc: () => (newVal: number) => {
- spy()
- count.value = newVal
- },
- }),
- }).render()
-
- expect(html()).toMatch(`<div>0</div>`)
- ;(host.children[0] as HTMLDivElement).click()
-
- expect(spy).toHaveBeenCalled()
- await nextTick()
- expect(html()).toMatch(`<div>1</div>`)
- })
-})
+++ /dev/null
-import { createComponent, defineVaporComponent, template } from '../src'
-import {
- currentInstance,
- onMounted,
- ref,
- useAttrs,
- useSlots,
- withAsyncContext,
-} from '@vue/runtime-dom'
-import { makeRender } from './_utils'
-import type { VaporComponentInstance } from '../src/component'
-
-const define = makeRender<any>()
-
-describe('SFC <script setup> helpers', () => {
- test('useSlots / useAttrs (no args)', () => {
- let slots: VaporComponentInstance['slots'] | undefined
- let attrs: VaporComponentInstance['attrs'] | undefined
-
- const Comp = defineVaporComponent({
- setup() {
- // @ts-expect-error
- slots = useSlots()
- attrs = useAttrs()
- return []
- },
- })
- const count = ref(0)
- const passedAttrs = { id: () => count.value }
- const passedSlots = {
- default: () => template('')(),
- x: () => template('')(),
- }
-
- const { render } = define({
- render: () => createComponent(Comp, passedAttrs, passedSlots),
- })
- render()
-
- expect(typeof slots!.default).toBe('function')
- expect(typeof slots!.x).toBe('function')
- expect(attrs).toMatchObject({ id: 0 })
-
- count.value++
- expect(attrs).toMatchObject({ id: 1 })
- })
-
- test('useSlots / useAttrs (with args)', () => {
- let slots: VaporComponentInstance['slots'] | undefined
- let attrs: VaporComponentInstance['attrs'] | undefined
- let ctx: VaporComponentInstance | undefined
- const Comp = defineVaporComponent({
- setup(_, _ctx) {
- // @ts-expect-error
- slots = useSlots()
- attrs = useAttrs()
- ctx = _ctx as VaporComponentInstance
- return []
- },
- })
- const { render } = define({ render: () => createComponent(Comp) })
- render()
- expect(slots).toBe(ctx!.slots)
- expect(attrs).toBe(ctx!.attrs)
- })
-
- describe.todo('withAsyncContext', () => {
- test('basic', async () => {
- const spy = vi.fn()
-
- let beforeInstance: VaporComponentInstance | null = null
- let afterInstance: VaporComponentInstance | null = null
- let resolve: (msg: string) => void
-
- const Comp = defineVaporComponent({
- async setup() {
- let __temp: any, __restore: any
-
- beforeInstance = currentInstance as VaporComponentInstance
-
- const msg =
- (([__temp, __restore] = withAsyncContext(
- () =>
- new Promise(r => {
- resolve = r
- }),
- )),
- (__temp = await __temp),
- __restore(),
- __temp)
-
- // register the lifecycle after an await statement
- onMounted(spy)
- afterInstance = currentInstance as VaporComponentInstance
- return document.createTextNode(msg)
- },
- })
-
- const { html } = define(Comp).render()
-
- expect(spy).not.toHaveBeenCalled()
- resolve!('hello')
- // wait a macro task tick for all micro ticks to resolve
- await new Promise(r => setTimeout(r))
- // mount hook should have been called
- expect(spy).toHaveBeenCalled()
- // should retain same instance before/after the await call
- expect(beforeInstance).toBe(afterInstance)
- expect(html()).toBe('hello')
- })
-
- test.todo('error handling', async () => {})
- test.todo('should not leak instance on multiple awaits', async () => {})
- test.todo('should not leak on multiple awaits + error', async () => {})
- test.todo('race conditions', async () => {})
- test.todo('should teardown in-scope effects', async () => {})
- })
-})
+++ /dev/null
-import {
- currentInstance,
- effectScope,
- nextTick,
- onMounted,
- onUpdated,
- ref,
- watch,
- watchEffect,
-} from '@vue/runtime-dom'
-import {
- createComponent,
- createIf,
- createTemplateRefSetter,
- defineVaporComponent,
- renderEffect,
- template,
-} from '../src'
-import { makeRender } from './_utils'
-import type { VaporComponentInstance } from '../src/component'
-import type { RefEl } from '../src/apiTemplateRef'
-
-const define = makeRender()
-
-// only need to port test cases related to in-component usage
-describe('apiWatch', () => {
- // #7030
- it(// need if support
- 'should not fire on child component unmount w/ flush: pre', async () => {
- const visible = ref(true)
- const cb = vi.fn()
- const Parent = defineVaporComponent({
- props: ['visible'],
- setup() {
- return createIf(
- () => visible.value,
- () => createComponent(Comp),
- )
- },
- })
- const Comp = {
- setup() {
- watch(visible, cb, { flush: 'pre' })
- return []
- },
- }
- define(Parent).render({
- visible: () => visible.value,
- })
- expect(cb).not.toHaveBeenCalled()
- visible.value = false
- await nextTick()
- expect(cb).not.toHaveBeenCalled()
- })
-
- // #7030
- it('flush: pre watcher in child component should not fire before parent update', async () => {
- const b = ref(0)
- const calls: string[] = []
-
- const Comp = {
- setup() {
- watch(
- () => b.value,
- val => {
- calls.push('watcher child')
- },
- { flush: 'pre' },
- )
- renderEffect(() => {
- b.value
- calls.push('render child')
- })
- return []
- },
- }
-
- const Parent = {
- props: ['a'],
- setup() {
- watch(
- () => b.value,
- val => {
- calls.push('watcher parent')
- },
- { flush: 'pre' },
- )
- renderEffect(() => {
- b.value
- calls.push('render parent')
- })
-
- return createComponent(Comp)
- },
- }
-
- define(Parent).render({
- a: () => b.value,
- })
-
- expect(calls).toEqual(['render parent', 'render child'])
-
- b.value++
- await nextTick()
- expect(calls).toEqual([
- 'render parent',
- 'render child',
- 'watcher parent',
- 'render parent',
- 'watcher child',
- 'render child',
- ])
- })
-
- // #1763
- it('flush: pre watcher watching props should fire before child update', async () => {
- const a = ref(0)
- const b = ref(0)
- const c = ref(0)
- const calls: string[] = []
-
- const Comp = {
- props: ['a', 'b'],
- setup(props: any) {
- watch(
- () => props.a + props.b,
- () => {
- calls.push('watcher 1')
- c.value++
- },
- { flush: 'pre' },
- )
-
- // #1777 chained pre-watcher
- watch(
- c,
- () => {
- calls.push('watcher 2')
- },
- { flush: 'pre' },
- )
- renderEffect(() => {
- c.value
- calls.push('render')
- })
- return []
- },
- }
-
- define(Comp).render({
- a: () => a.value,
- b: () => b.value,
- })
-
- expect(calls).toEqual(['render'])
-
- // both props are updated
- // should trigger pre-flush watcher first and only once
- // then trigger child render
- a.value++
- b.value++
- await nextTick()
- expect(calls).toEqual(['render', 'watcher 1', 'watcher 2', 'render'])
- })
-
- // #5721
- it('flush: pre triggered in component setup should be buffered and called before mounted', () => {
- const count = ref(0)
- const calls: string[] = []
- const App = {
- setup() {
- watch(
- count,
- () => {
- calls.push('watch ' + count.value)
- },
- { flush: 'pre' },
- )
- onMounted(() => {
- calls.push('mounted')
- })
- // mutate multiple times
- count.value++
- count.value++
- count.value++
- return []
- },
- }
- define(App).render()
- expect(calls).toMatchObject(['watch 3', 'mounted'])
- })
-
- // #1852
- it('flush: post watcher should fire after template refs updated', async () => {
- const toggle = ref(false)
- let dom: Element | null = null
-
- const App = {
- setup() {
- const domRef = ref<Element | null>(null)
-
- watch(
- toggle,
- () => {
- dom = domRef.value
- },
- { flush: 'post' },
- )
-
- const setRef = createTemplateRefSetter()
- return createIf(
- () => toggle.value,
- () => {
- const n = template('<p>')()
- setRef(n as RefEl, domRef)
- return n
- },
- )
- },
- }
-
- define(App).render()
- expect(dom).toBe(null)
-
- toggle.value = true
- await nextTick()
- expect(dom!.tagName).toBe('P')
- })
-
- test('should not leak `this.proxy` to setup()', () => {
- const source = vi.fn()
-
- const Comp = defineVaporComponent({
- setup() {
- watch(source, () => {})
- return []
- },
- })
-
- define(Comp).render()
-
- // should not have any arguments
- expect(source.mock.calls[0]).toMatchObject([])
- })
-
- // #2728
- test('pre watcher callbacks should not track dependencies', async () => {
- const a = ref(0)
- const b = ref(0)
- const updated = vi.fn()
-
- const Comp = defineVaporComponent({
- props: ['a'],
- setup(props) {
- onUpdated(updated)
- watch(
- () => props.a,
- () => {
- b.value
- },
- )
- renderEffect(() => {
- props.a
- })
- return []
- },
- })
-
- define(Comp).render({
- a: () => a.value,
- })
-
- a.value++
- await nextTick()
- expect(updated).toHaveBeenCalledTimes(1)
-
- b.value++
- await nextTick()
- // should not track b as dependency of Child
- expect(updated).toHaveBeenCalledTimes(1)
- })
-
- // #4158
- test('watch should not register in owner component if created inside detached scope', () => {
- let instance: VaporComponentInstance
- const Comp = {
- setup() {
- instance = currentInstance as VaporComponentInstance
- effectScope(true).run(() => {
- watch(
- () => 1,
- () => {},
- )
- })
- return []
- },
- }
- define(Comp).render()
- // should not record watcher in detached scope
- // the 1 is the props validation effect
- expect(instance!.scope.effects.length).toBe(1)
- })
-
- test('watchEffect should keep running if created in a detached scope', async () => {
- const trigger = ref(0)
- let countWE = 0
- let countW = 0
- const Comp = {
- setup() {
- effectScope(true).run(() => {
- watchEffect(() => {
- trigger.value
- countWE++
- })
- watch(trigger, () => countW++)
- })
- return []
- },
- }
- const { app } = define(Comp).render()
- // only watchEffect as ran so far
- expect(countWE).toBe(1)
- expect(countW).toBe(0)
- trigger.value++
- await nextTick()
- // both watchers run while component is mounted
- expect(countWE).toBe(2)
- expect(countW).toBe(1)
-
- app.unmount()
- await nextTick()
- trigger.value++
- await nextTick()
- // both watchers run again event though component has been unmounted
- expect(countWE).toBe(3)
- expect(countW).toBe(2)
- })
-})
+++ /dev/null
-import {
- VaporFragment,
- insert,
- normalizeBlock,
- prepend,
- remove,
-} from '../src/block'
-
-const node1 = document.createTextNode('node1')
-const node2 = document.createTextNode('node2')
-const node3 = document.createTextNode('node3')
-const anchor = document.createTextNode('anchor')
-
-describe('block + node ops', () => {
- test('normalizeBlock', () => {
- expect(normalizeBlock([node1, node2, node3])).toEqual([node1, node2, node3])
- expect(normalizeBlock([node1, [node2, [node3]]])).toEqual([
- node1,
- node2,
- node3,
- ])
- const frag = new VaporFragment(node2)
- frag.anchor = anchor
- expect(normalizeBlock([node1, frag, [node3]])).toEqual([
- node1,
- node2,
- anchor,
- node3,
- ])
- })
-
- test('insert', () => {
- const container = document.createElement('div')
- insert([anchor], container)
- insert([node1], container)
- insert([node2], container, anchor)
- insert([], container, node3)
- expect(Array.from(container.childNodes)).toEqual([node2, anchor, node1])
-
- expect(() => insert(node3, container, node3)).toThrowError(
- 'The child can not be found in the parent.',
- )
- })
-
- test('prepend', () => {
- const container = document.createElement('div')
- prepend(container, [node1], node2)
- prepend(container, new VaporFragment(node3))
- expect(Array.from(container.childNodes)).toEqual([node3, node1, node2])
- })
-
- test('remove', () => {
- const container = document.createElement('div')
- container.append(node1, node2, node3)
- const frag = new VaporFragment(node3)
- remove([node1], container)
- remove(frag, container)
- expect(Array.from(container.childNodes)).toEqual([node2])
-
- expect(() => remove(anchor, container)).toThrowError(
- 'The node to be removed is not a child of this node.',
- )
- })
-})
+++ /dev/null
-import {
- type Ref,
- inject,
- nextTick,
- onMounted,
- onUpdated,
- provide,
- ref,
- watch,
- watchEffect,
-} from '@vue/runtime-dom'
-import {
- createComponent,
- createIf,
- createTextNode,
- renderEffect,
- setInsertionState,
- template,
-} from '../src'
-import { makeRender } from './_utils'
-import type { VaporComponentInstance } from '../src/component'
-import { setElementText, setText } from '../src/dom/prop'
-
-const define = makeRender()
-
-describe('component', () => {
- it('should update parent(hoc) component host el when child component self update', async () => {
- const value = ref(true)
- let childNode1: Node | null = null
- let childNode2: Node | null = null
-
- const { component: Child } = define({
- setup() {
- return createIf(
- () => value.value,
- () => (childNode1 = template('<div></div>')()),
- () => (childNode2 = template('<span></span>')()),
- )
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Child)
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div></div><!--if-->')
- expect(host.children[0]).toBe(childNode1)
-
- value.value = false
- await nextTick()
- expect(host.innerHTML).toBe('<span></span><!--if-->')
- expect(host.children[0]).toBe(childNode2)
- })
-
- it('should create a component with props', () => {
- const { component: Comp } = define({
- setup() {
- return template('<div>', true)()
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Comp, { id: () => 'foo', class: () => 'bar' })
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div id="foo" class="bar"></div>')
- })
-
- it('should not update Component if only changed props are declared emit listeners', async () => {
- const updatedSyp = vi.fn()
- const { component: Comp } = define({
- emits: ['foo'],
- setup() {
- onUpdated(updatedSyp)
- return template('<div>', true)()
- },
- })
-
- const toggle = ref(true)
- const fn1 = () => {}
- const fn2 = () => {}
- define({
- setup() {
- const _on_foo = () => (toggle.value ? fn1() : fn2())
- return createComponent(Comp, { onFoo: () => _on_foo })
- },
- }).render()
- expect(updatedSyp).toHaveBeenCalledTimes(0)
-
- toggle.value = false
- await nextTick()
- expect(updatedSyp).toHaveBeenCalledTimes(0)
- })
-
- it('component child synchronously updating parent state should trigger parent re-render', async () => {
- const { component: Child } = define({
- setup() {
- const n = inject<Ref<number>>('foo')!
- n.value++
- const n0 = template('<div></div>')()
- renderEffect(() => setElementText(n0, n.value))
- return n0
- },
- })
-
- const { host } = define({
- setup() {
- const n = ref(0)
- provide('foo', n)
- const n0 = template('<div></div>')()
- renderEffect(() => setElementText(n0, n.value))
- return [n0, createComponent(Child)]
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div>0</div><div>1</div>')
- await nextTick()
- expect(host.innerHTML).toBe('<div>1</div><div>1</div>')
- })
-
- it('component child updating parent state in pre-flush should trigger parent re-render', async () => {
- const { component: Child } = define({
- props: ['value'],
- setup(props: any, { emit }) {
- watch(
- () => props.value,
- val => emit('update', val),
- )
- const n0 = template('<div></div>')()
- renderEffect(() => setElementText(n0, props.value))
- return n0
- },
- })
-
- const outer = ref(0)
- const { host } = define({
- setup() {
- const inner = ref(0)
- const n0 = template('<div></div>')()
- renderEffect(() => setElementText(n0, inner.value))
- const n1 = createComponent(Child, {
- value: () => outer.value,
- onUpdate: () => (val: number) => (inner.value = val),
- })
- return [n0, n1]
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div>0</div><div>0</div>')
- outer.value++
- await nextTick()
- expect(host.innerHTML).toBe('<div>1</div><div>1</div>')
- })
-
- it('child only updates once when triggered in multiple ways', async () => {
- const a = ref(0)
- const calls: string[] = []
-
- const { component: Child } = define({
- props: ['count'],
- setup(props: any) {
- onUpdated(() => calls.push('update child'))
- const n = createTextNode()
- renderEffect(() => {
- setText(n, `${props.count} - ${a.value}`)
- })
- return n
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Child, { count: () => a.value })
- },
- }).render()
-
- expect(host.innerHTML).toBe('0 - 0')
- expect(calls).toEqual([])
-
- // This will trigger child rendering directly, as well as via a prop change
- a.value++
- await nextTick()
- expect(host.innerHTML).toBe('1 - 1')
- expect(calls).toEqual(['update child'])
- })
-
- it(`an earlier update doesn't lead to excessive subsequent updates`, async () => {
- const globalCount = ref(0)
- const parentCount = ref(0)
- const calls: string[] = []
-
- const { component: Child } = define({
- props: ['count'],
- setup(props: any) {
- watch(
- () => props.count,
- () => {
- calls.push('child watcher')
- globalCount.value = props.count
- },
- )
- onUpdated(() => calls.push('update child'))
- return []
- },
- })
-
- const { component: Parent } = define({
- props: ['count'],
- setup(props: any) {
- onUpdated(() => calls.push('update parent'))
- const n1 = createTextNode()
- const n2 = createComponent(Child, { count: () => parentCount.value })
- renderEffect(() => {
- setText(n1, `${globalCount.value} - ${props.count}`)
- })
- return [n1, n2]
- },
- })
-
- const { host } = define({
- setup() {
- onUpdated(() => calls.push('update root'))
- return createComponent(Parent, { count: () => globalCount.value })
- },
- }).render()
-
- expect(host.innerHTML).toBe(`0 - 0`)
- expect(calls).toEqual([])
-
- parentCount.value++
- await nextTick()
- expect(host.innerHTML).toBe(`1 - 1`)
- expect(calls).toEqual(['child watcher', 'update parent'])
- })
-
- it('child component props update should not lead to double update', async () => {
- const text = ref(0)
- const spy = vi.fn()
-
- const { component: Comp } = define({
- props: ['text'],
- setup(props: any) {
- const n1 = template('<h1></h1>')()
- renderEffect(() => {
- spy()
- setElementText(n1, props.text)
- })
- return n1
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Comp, { text: () => text.value })
- },
- }).render()
-
- expect(host.innerHTML).toBe('<h1>0</h1>')
- expect(spy).toHaveBeenCalledTimes(1)
-
- text.value++
- await nextTick()
- expect(host.innerHTML).toBe('<h1>1</h1>')
- expect(spy).toHaveBeenCalledTimes(2)
- })
-
- it('properly mount child component when using setInsertionState', async () => {
- const spy = vi.fn()
-
- const { component: Comp } = define({
- setup() {
- onMounted(spy)
- return template('<h1>hi</h1>')()
- },
- })
-
- const { host } = define({
- setup() {
- const n2 = template('<div></div>', true)()
- setInsertionState(n2 as any)
- createComponent(Comp)
- return n2
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div><h1>hi</h1></div>')
- expect(spy).toHaveBeenCalledTimes(1)
- })
-
- it('unmount component', async () => {
- const { host, app, instance } = define(() => {
- const count = ref(0)
- const t0 = template('<div></div>')
- const n0 = t0()
- watchEffect(() => {
- setElementText(n0, count.value)
- })
- renderEffect(() => {})
- return n0
- }).render()
-
- const i = instance as VaporComponentInstance
- // watchEffect + renderEffect + props validation effect
- expect(i.scope.effects.length).toBe(3)
- expect(host.innerHTML).toBe('<div>0</div>')
-
- app.unmount()
- expect(host.innerHTML).toBe('')
- expect(i.scope.effects.length).toBe(0)
- })
-
- test('should mount component only with template in production mode', () => {
- __DEV__ = false
- const { component: Child } = define({
- render() {
- return template('<div> HI </div>', true)()
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Child, null, null, true)
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div> HI </div>')
- __DEV__ = true
- })
-
- it('warn if functional vapor component not return a block', () => {
- define(() => {
- return () => {}
- }).render()
-
- expect(
- 'Functional vapor component must return a block directly',
- ).toHaveBeenWarned()
- })
-
- it('warn if setup return a function and no render function', () => {
- define({
- setup() {
- return () => []
- },
- }).render()
-
- expect(
- 'Vapor component setup() returned non-block value, and has no render function',
- ).toHaveBeenWarned()
- })
-})
+++ /dev/null
-import { type Ref, nextTick, ref } from '@vue/runtime-dom'
-import {
- createComponent,
- createDynamicComponent,
- createSlot,
- defineVaporComponent,
- renderEffect,
- setClass,
- setDynamicProps,
- setProp,
- setStyle,
- template,
-} from '../src'
-import { makeRender } from './_utils'
-import { stringifyStyle } from '@vue/shared'
-import { setElementText } from '../src/dom/prop'
-
-const define = makeRender<any>()
-
-// TODO: port more tests from rendererAttrsFallthrough.spec.ts
-
-describe('attribute fallthrough', () => {
- it('should allow attrs to fallthrough', async () => {
- const t0 = template('<div>', true)
- const { component: Child } = define({
- props: ['foo'],
- setup(props: any) {
- const n0 = t0() as Element
- renderEffect(() => setElementText(n0, props.foo))
- return n0
- },
- })
-
- const foo = ref(1)
- const id = ref('a')
- const { host } = define({
- setup() {
- return createComponent(
- Child,
- {
- foo: () => foo.value,
- id: () => id.value,
- },
- null,
- true,
- )
- },
- }).render()
- expect(host.innerHTML).toBe('<div id="a">1</div>')
-
- foo.value++
- await nextTick()
- expect(host.innerHTML).toBe('<div id="a">2</div>')
-
- id.value = 'b'
- await nextTick()
- expect(host.innerHTML).toBe('<div id="b">2</div>')
- })
-
- it('should not fallthrough if explicitly pass inheritAttrs: false', async () => {
- const t0 = template('<div>', true)
- const { component: Child } = define({
- props: ['foo'],
- inheritAttrs: false,
- setup(props: any) {
- const n0 = t0() as Element
- renderEffect(() => setElementText(n0, props.foo))
- return n0
- },
- })
-
- const foo = ref(1)
- const id = ref('a')
- const { host } = define({
- setup() {
- return createComponent(
- Child,
- {
- foo: () => foo.value,
- id: () => id.value,
- },
- null,
- true,
- )
- },
- }).render()
- expect(host.innerHTML).toBe('<div>1</div>')
-
- foo.value++
- await nextTick()
- expect(host.innerHTML).toBe('<div>2</div>')
-
- id.value = 'b'
- await nextTick()
- expect(host.innerHTML).toBe('<div>2</div>')
- })
-
- it('should pass through attrs in nested single root components', async () => {
- const t0 = template('<div>', true)
- const { component: Grandson } = define({
- props: ['custom-attr'],
- setup(_: any, { attrs }: any) {
- const n0 = t0() as Element
- renderEffect(() => setElementText(n0, attrs.foo))
- return n0
- },
- })
-
- const { component: Child } = define({
- setup() {
- const n0 = createComponent(
- Grandson,
- {
- 'custom-attr': () => 'custom-attr',
- },
- null,
- true,
- )
- return n0
- },
- })
-
- const foo = ref(1)
- const id = ref('a')
- const { host } = define({
- setup() {
- return createComponent(
- Child,
- {
- foo: () => foo.value,
- id: () => id.value,
- },
- null,
- true,
- )
- },
- }).render()
- expect(host.innerHTML).toBe('<div foo="1" id="a">1</div>')
-
- foo.value++
- await nextTick()
- expect(host.innerHTML).toBe('<div foo="2" id="a">2</div>')
-
- id.value = 'b'
- await nextTick()
- expect(host.innerHTML).toBe('<div foo="2" id="b">2</div>')
- })
-
- it('should merge classes', async () => {
- const rootClass = ref('root')
- const parentClass = ref('parent')
- const childClass = ref('child')
-
- const t0 = template('<div>', true /* root */)
- const Child = defineVaporComponent({
- setup() {
- const n = t0() as Element
- renderEffect(() => {
- // binding on template root generates incremental class setter
- setClass(n, childClass.value)
- })
- return n
- },
- })
-
- const Parent = defineVaporComponent({
- setup() {
- return createComponent(
- Child,
- {
- class: () => parentClass.value,
- },
- null,
- true, // pass single root flag
- )
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Parent, {
- class: () => rootClass.value,
- })
- },
- }).render()
-
- const list = host.children[0].classList
- // assert classes without being order-sensitive
- function assertClasses(cls: string[]) {
- expect(list.length).toBe(cls.length)
- for (const c of cls) {
- expect(list.contains(c)).toBe(true)
- }
- }
-
- assertClasses(['root', 'parent', 'child'])
-
- rootClass.value = 'root1'
- await nextTick()
- assertClasses(['root1', 'parent', 'child'])
-
- parentClass.value = 'parent1'
- await nextTick()
- assertClasses(['root1', 'parent1', 'child'])
-
- childClass.value = 'child1'
- await nextTick()
- assertClasses(['root1', 'parent1', 'child1'])
- })
-
- it('should merge styles', async () => {
- const rootStyle: Ref<string | Record<string, string>> = ref('color:red')
- const parentStyle: Ref<string | null> = ref('font-size:12px')
- const childStyle = ref('font-weight:bold')
-
- const t0 = template('<div>', true /* root */)
- const Child = defineVaporComponent({
- setup() {
- const n = t0() as Element
- renderEffect(() => {
- // binding on template root generates incremental class setter
- setStyle(n, childStyle.value)
- })
- return n
- },
- })
-
- const Parent = defineVaporComponent({
- setup() {
- return createComponent(
- Child,
- {
- style: () => parentStyle.value,
- },
- null,
- true, // pass single root flag
- )
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Parent, {
- style: () => rootStyle.value,
- })
- },
- }).render()
-
- const el = host.children[0] as HTMLElement
-
- function getCSS() {
- return el.style.cssText.replace(/\s+/g, '')
- }
-
- function assertStyles() {
- const css = getCSS()
- expect(css).toContain(stringifyStyle(rootStyle.value))
- if (parentStyle.value) {
- expect(css).toContain(stringifyStyle(parentStyle.value))
- }
- expect(css).toContain(stringifyStyle(childStyle.value))
- }
-
- assertStyles()
-
- rootStyle.value = { color: 'green' }
- await nextTick()
- assertStyles()
- expect(getCSS()).not.toContain('color:red')
-
- parentStyle.value = null
- await nextTick()
- assertStyles()
- expect(getCSS()).not.toContain('font-size:12px')
-
- childStyle.value = 'font-weight:500'
- await nextTick()
- assertStyles()
- expect(getCSS()).not.toContain('font-size:bold')
- })
-
- it('should fallthrough attrs to dynamic component', async () => {
- const Comp = defineVaporComponent({
- setup() {
- const n1 = createDynamicComponent(
- () => 'button',
- null,
- {
- default: () => {
- const n0 = createSlot('default', null)
- return n0
- },
- },
- true,
- )
- return n1
- },
- })
-
- const { html } = define({
- setup() {
- return createComponent(
- Comp,
- {
- class: () => 'foo',
- },
- null,
- true,
- )
- },
- }).render()
-
- expect(html()).toBe(
- '<button class="foo"><!--slot--></button><!--dynamic-component-->',
- )
- })
-
- it('parent value should take priority', async () => {
- const parentVal = ref('parent')
- const childVal = ref('child')
-
- const t0 = template('<div>', true /* root */)
- const Child = defineVaporComponent({
- setup() {
- const n = t0()
- renderEffect(() => {
- // prop bindings on template root generates extra `root: true` flag
- setProp(n, 'id', childVal.value)
- setProp(n, 'aria-x', childVal.value)
- setDynamicProps(n, [{ 'aria-y': childVal.value }])
- })
- return n
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Child, {
- id: () => parentVal.value,
- 'aria-x': () => parentVal.value,
- 'aria-y': () => parentVal.value,
- })
- },
- }).render()
-
- const el = host.children[0]
- expect(el.id).toBe(parentVal.value)
- expect(el.getAttribute('aria-x')).toBe(parentVal.value)
- expect(el.getAttribute('aria-y')).toBe(parentVal.value)
-
- childVal.value = 'child1'
- await nextTick()
- expect(el.id).toBe(parentVal.value)
- expect(el.getAttribute('aria-x')).toBe(parentVal.value)
- expect(el.getAttribute('aria-y')).toBe(parentVal.value)
-
- parentVal.value = 'parent1'
- await nextTick()
- expect(el.id).toBe(parentVal.value)
- expect(el.getAttribute('aria-x')).toBe(parentVal.value)
- expect(el.getAttribute('aria-y')).toBe(parentVal.value)
- })
-
- it('empty string should not be passed to classList.add', async () => {
- const t0 = template('<div>', true /* root */)
- const Child = defineVaporComponent({
- setup() {
- const n = t0() as Element
- renderEffect(() => {
- setClass(n, {
- foo: false,
- })
- })
- return n
- },
- })
-
- const Parent = defineVaporComponent({
- setup() {
- return createComponent(
- Child,
- {
- class: () => ({
- bar: false,
- }),
- },
- null,
- true,
- )
- },
- })
-
- const { host } = define({
- setup() {
- return createComponent(Parent)
- },
- }).render()
-
- const el = host.children[0]
- expect(el.classList.length).toBe(0)
- })
-})
+++ /dev/null
-// NOTE: this test cases are based on paclages/runtime-core/__tests__/componentEmits.spec.ts
-
-// Note: emits and listener fallthrough is tested in
-// ./rendererAttrsFallthrough.spec.ts.
-
-import {
- isEmitListener,
- nextTick,
- onBeforeUnmount,
- toHandlers,
-} from '@vue/runtime-dom'
-import { createComponent, defineVaporComponent } from '../src'
-import { makeRender } from './_utils'
-
-const define = makeRender()
-
-describe('component: emit', () => {
- test('trigger handlers', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('foo')
- emit('bar')
- emit('!baz')
- return []
- },
- })
- const onFoo = vi.fn()
- const onBar = vi.fn()
- const onBaz = vi.fn()
- render({
- onfoo: () => onFoo,
- onBar: () => onBar,
- ['on!baz']: () => onBaz,
- })
-
- expect(onFoo).not.toHaveBeenCalled()
- expect(onBar).toHaveBeenCalled()
- expect(onBaz).toHaveBeenCalled()
- })
-
- test('trigger dynamic emits', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('foo')
- emit('bar')
- emit('!baz')
- return []
- },
- })
- const onFoo = vi.fn()
- const onBar = vi.fn()
- const onBaz = vi.fn()
- render({
- onfoo: () => onFoo,
- onBar: () => onBar,
- ['on!baz']: () => onBaz,
- })
-
- expect(onFoo).not.toHaveBeenCalled()
- expect(onBar).toHaveBeenCalled()
- expect(onBaz).toHaveBeenCalled()
- })
-
- test('trigger camelCase handler', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('test-event')
- return []
- },
- })
-
- const fooSpy = vi.fn()
- render({ onTestEvent: () => fooSpy })
- expect(fooSpy).toHaveBeenCalled()
- })
-
- test('trigger kebab-case handler', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('test-event')
- return []
- },
- })
-
- const fooSpy = vi.fn()
- render({ ['onTest-event']: () => fooSpy })
- expect(fooSpy).toHaveBeenCalledTimes(1)
- })
-
- // #3527
- test('trigger mixed case handlers', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('test-event')
- emit('testEvent')
- return []
- },
- })
-
- const fooSpy = vi.fn()
- const barSpy = vi.fn()
- render(
- toHandlers({
- 'test-event': () => fooSpy,
- testEvent: () => barSpy,
- }),
- )
- expect(fooSpy).toHaveBeenCalledTimes(1)
- expect(barSpy).toHaveBeenCalledTimes(1)
- })
-
- // for v-model:foo-bar usage in DOM templates
- test('trigger hyphenated events for update:xxx events', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('update:fooProp')
- emit('update:barProp')
- return []
- },
- })
-
- const fooSpy = vi.fn()
- const barSpy = vi.fn()
- render({
- ['onUpdate:fooProp']: () => fooSpy,
- ['onUpdate:bar-prop']: () => barSpy,
- })
-
- expect(fooSpy).toHaveBeenCalled()
- expect(barSpy).toHaveBeenCalled()
- })
-
- test('should trigger array of listeners', async () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('foo', 1)
- return []
- },
- })
-
- const fn1 = vi.fn()
- const fn2 = vi.fn()
-
- render({ onFoo: () => [fn1, fn2] })
- expect(fn1).toHaveBeenCalledTimes(1)
- expect(fn1).toHaveBeenCalledWith(1)
- expect(fn2).toHaveBeenCalledTimes(1)
- expect(fn2).toHaveBeenCalledWith(1)
- })
-
- test('warning for undeclared event (array)', () => {
- const { render } = define({
- emits: ['foo'],
-
- setup(_, { emit }) {
- emit('bar')
- return []
- },
- })
- render()
- expect(
- `Component emitted event "bar" but it is neither declared`,
- ).toHaveBeenWarned()
- })
-
- test('warning for undeclared event (object)', () => {
- const { render } = define({
- emits: {
- foo: null,
- },
-
- setup(_, { emit }) {
- emit('bar')
- return []
- },
- })
- render()
- expect(
- `Component emitted event "bar" but it is neither declared`,
- ).toHaveBeenWarned()
- })
-
- test('should not warn if has equivalent onXXX prop', () => {
- define({
- props: ['onFoo'],
- emits: [],
-
- setup(_, { emit }) {
- emit('foo')
- return []
- },
- }).render()
- expect(
- `Component emitted event "foo" but it is neither declared`,
- ).not.toHaveBeenWarned()
- })
-
- test('validator warning', () => {
- define({
- emits: {
- foo: (arg: number) => arg > 0,
- },
- setup(_, { emit }) {
- emit('foo', -1)
- return []
- },
- }).render()
- expect(`event validation failed for event "foo"`).toHaveBeenWarned()
- })
-
- test('.once', () => {
- const { render } = define({
- emits: {
- foo: null,
- bar: null,
- },
- setup(_, { emit }) {
- emit('foo')
- emit('foo')
- emit('bar')
- emit('bar')
- return []
- },
- })
- const fn = vi.fn()
- const barFn = vi.fn()
- render({
- onFooOnce: () => fn,
- onBarOnce: () => barFn,
- })
- expect(fn).toHaveBeenCalledTimes(1)
- expect(barFn).toHaveBeenCalledTimes(1)
- })
-
- test('.once with normal listener of the same name', () => {
- const { render } = define({
- emits: {
- foo: null,
- },
- setup(_, { emit }) {
- emit('foo')
- emit('foo')
- return []
- },
- })
- const onFoo = vi.fn()
- const onFooOnce = vi.fn()
- render({
- onFoo: () => onFoo,
- onFooOnce: () => onFooOnce,
- })
- expect(onFoo).toHaveBeenCalledTimes(2)
- expect(onFooOnce).toHaveBeenCalledTimes(1)
- })
-
- test('.number modifier should work with v-model on component', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('update:modelValue', '1')
- emit('update:foo', '2')
- return []
- },
- })
- const fn1 = vi.fn()
- const fn2 = vi.fn()
- render({
- modelValue: () => null,
- modelModifiers: () => ({ number: true }),
- ['onUpdate:modelValue']: () => fn1,
- foo: () => null,
- fooModifiers: () => ({ number: true }),
- ['onUpdate:foo']: () => fn2,
- })
- expect(fn1).toHaveBeenCalledTimes(1)
- expect(fn1).toHaveBeenCalledWith(1)
- expect(fn2).toHaveBeenCalledTimes(1)
- expect(fn2).toHaveBeenCalledWith(2)
- })
-
- test('.trim modifier should work with v-model on component', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('update:modelValue', ' one ')
- emit('update:foo', ' two ')
- return []
- },
- })
- const fn1 = vi.fn()
- const fn2 = vi.fn()
- render({
- modelValue() {
- return null
- },
- modelModifiers() {
- return { trim: true }
- },
- ['onUpdate:modelValue']() {
- return fn1
- },
- foo() {
- return null
- },
- fooModifiers() {
- return { trim: true }
- },
- 'onUpdate:foo'() {
- return fn2
- },
- })
- expect(fn1).toHaveBeenCalledTimes(1)
- expect(fn1).toHaveBeenCalledWith('one')
- expect(fn2).toHaveBeenCalledTimes(1)
- expect(fn2).toHaveBeenCalledWith('two')
- })
-
- test('.trim and .number modifiers should work with v-model on component', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('update:modelValue', ' +01.2 ')
- emit('update:foo', ' 1 ')
- return []
- },
- })
- const fn1 = vi.fn()
- const fn2 = vi.fn()
- render({
- modelValue() {
- return null
- },
- modelModifiers() {
- return { trim: true, number: true }
- },
- ['onUpdate:modelValue']() {
- return fn1
- },
- foo() {
- return null
- },
- fooModifiers() {
- return { trim: true, number: true }
- },
- ['onUpdate:foo']() {
- return fn2
- },
- })
- expect(fn1).toHaveBeenCalledTimes(1)
- expect(fn1).toHaveBeenCalledWith(1.2)
- expect(fn2).toHaveBeenCalledTimes(1)
- expect(fn2).toHaveBeenCalledWith(1)
- })
-
- test('only trim string parameter when work with v-model on component', () => {
- const { render } = define({
- setup(_, { emit }) {
- emit('update:modelValue', ' foo ', { bar: ' bar ' })
- return []
- },
- })
- const fn = vi.fn()
- render({
- modelValue() {
- return null
- },
- modelModifiers() {
- return { trim: true }
- },
- ['onUpdate:modelValue']() {
- return fn
- },
- })
- expect(fn).toHaveBeenCalledTimes(1)
- expect(fn).toHaveBeenCalledWith('foo', { bar: ' bar ' })
- })
-
- test('isEmitListener', () => {
- const options = {
- get click() {
- return null
- },
- get 'test-event'() {
- return null
- },
- get fooBar() {
- return null
- },
- get FooBaz() {
- return null
- },
- }
- expect(isEmitListener(options, 'onClick')).toBe(true)
- expect(isEmitListener(options, 'onclick')).toBe(false)
- expect(isEmitListener(options, 'onBlick')).toBe(false)
- // .once listeners
- expect(isEmitListener(options, 'onClickOnce')).toBe(true)
- expect(isEmitListener(options, 'onclickOnce')).toBe(false)
- // kebab-case option
- expect(isEmitListener(options, 'onTestEvent')).toBe(true)
- // camelCase option
- expect(isEmitListener(options, 'onFooBar')).toBe(true)
- // PascalCase option
- expect(isEmitListener(options, 'onFooBaz')).toBe(true)
- })
-
- test('does not emit after unmount', async () => {
- const fn = vi.fn()
-
- const Foo = defineVaporComponent({
- emits: ['closing'],
- setup(_, { emit }) {
- onBeforeUnmount(async () => {
- await nextTick()
- emit('closing', true)
- })
- return []
- },
- })
-
- const { app } = define(() =>
- createComponent(Foo, { onClosing: () => fn }),
- ).render()
-
- await nextTick()
- app.unmount()
- await nextTick()
- expect(fn).not.toHaveBeenCalled()
- })
-})
+++ /dev/null
-// NOTE: This test is implemented based on the case of `runtime-core/__test__/componentProps.spec.ts`.
-
-import {
- // currentInstance,
- inject,
- nextTick,
- provide,
- ref,
- toRefs,
- watch,
-} from '@vue/runtime-dom'
-import {
- createComponent,
- defineVaporComponent,
- renderEffect,
- template,
-} from '../src'
-import { makeRender } from './_utils'
-import { setElementText } from '../src/dom/prop'
-
-const define = makeRender<any>()
-
-describe('component: props', () => {
- test('stateful', () => {
- let props: any
- let attrs: any
-
- const { render } = define({
- props: ['fooBar', 'barBaz'],
- setup(_props: any, { attrs: _attrs }: any) {
- props = _props
- attrs = _attrs
- return []
- },
- })
-
- render({ fooBar: () => 1, bar: () => 2 })
- expect(props).toEqual({ fooBar: 1 })
- expect(attrs).toEqual({ bar: 2 })
-
- // test passing kebab-case and resolving to camelCase
- render({ 'foo-bar': () => 2, bar: () => 3, baz: () => 4 })
- expect(props).toEqual({ fooBar: 2 })
- expect(attrs).toEqual({ bar: 3, baz: 4 })
-
- // test updating kebab-case should not delete it (#955)
- render({ 'foo-bar': () => 3, bar: () => 3, baz: () => 4, barBaz: () => 5 })
- expect(props).toEqual({ fooBar: 3, barBaz: 5 })
- expect(attrs).toEqual({ bar: 3, baz: 4 })
-
- // remove the props with camelCase key (#1412)
- render({ qux: () => 5 })
- expect(props).toEqual({})
- expect(attrs).toEqual({ qux: 5 })
- })
-
- test('stateful with setup', () => {
- let props: any
- let attrs: any
-
- const { render } = define({
- props: ['foo'],
- setup(_props: any, { attrs: _attrs }: any) {
- props = _props
- attrs = _attrs
- return []
- },
- })
-
- render({ foo: () => 1, bar: () => 2 })
- expect(props).toEqual({ foo: 1 })
- expect(attrs).toEqual({ bar: 2 })
-
- render({ foo: () => 2, bar: () => 3, baz: () => 4 })
- expect(props).toEqual({ foo: 2 })
- expect(attrs).toEqual({ bar: 3, baz: 4 })
-
- render({ qux: () => 5 })
- expect(props).toEqual({})
- expect(attrs).toEqual({ qux: 5 })
- })
-
- test('functional with declaration', () => {
- let props: any
- let attrs: any
-
- const { component: Comp, render } = define(
- (_props: any, { attrs: _attrs }: any) => {
- props = _props
- attrs = _attrs
- return []
- },
- )
- Comp.props = ['foo']
-
- render({ foo: () => 1, bar: () => 2 })
- expect(props).toEqual({ foo: 1 })
- expect(attrs).toEqual({ bar: 2 })
-
- render({ foo: () => 2, bar: () => 3, baz: () => 4 })
- expect(props).toEqual({ foo: 2 })
- expect(attrs).toEqual({ bar: 3, baz: 4 })
-
- render({ qux: () => 5 })
- expect(props).toEqual({})
- expect(attrs).toEqual({ qux: 5 })
- })
-
- test('functional without declaration', () => {
- let props: any
- let attrs: any
-
- const { render } = define((_props: any, { attrs: _attrs }: any) => {
- props = _props
- attrs = _attrs
- return []
- })
-
- render({ foo: () => 1 })
- expect(props).toEqual({ foo: 1 })
- expect(attrs).toEqual({ foo: 1 })
- expect(props).toBe(attrs)
-
- render({ bar: () => 2 })
- expect(props).toEqual({ bar: 2 })
- expect(attrs).toEqual({ bar: 2 })
- expect(props).toBe(attrs)
- })
-
- test('functional defineVaporComponent without declaration', () => {
- let props: any
- let attrs: any
-
- const { render } = define(
- defineVaporComponent((_props: any, { attrs: _attrs }: any) => {
- props = _props
- attrs = _attrs
- return []
- }),
- )
-
- render({ foo: () => 1 })
- expect(props).toEqual({})
- expect(attrs).toEqual({ foo: 1 })
-
- render({ bar: () => 2 })
- expect(props).toEqual({})
- expect(attrs).toEqual({ bar: 2 })
- })
-
- test('boolean casting', () => {
- let props: any
- const { render } = define({
- props: {
- foo: Boolean,
- bar: Boolean,
- baz: Boolean,
- qux: Boolean,
- },
- setup(_props: any) {
- props = _props
- return []
- },
- })
-
- render({
- // absent should cast to false
- bar: () => '', // empty string should cast to true
- baz: () => 'baz', // same string should cast to true
- qux: () => 'ok', // other values should be left in-tact (but raise warning)
- })
-
- expect(props.foo).toBe(false)
- expect(props.bar).toBe(true)
- expect(props.baz).toBe(true)
- expect(props.qux).toBe('ok')
- expect('type check failed for prop "qux"').toHaveBeenWarned()
- })
-
- test('default value', () => {
- let props: any
- const defaultFn = vi.fn(() => ({ a: 1 }))
- const defaultBaz = vi.fn(() => ({ b: 1 }))
-
- const { render } = define({
- props: {
- foo: {
- default: 1,
- },
- bar: {
- default: defaultFn,
- },
- baz: {
- type: Function,
- default: defaultBaz,
- },
- },
- setup(_props: any) {
- props = _props
- return []
- },
- })
-
- render({ foo: () => 2 })
- expect(props.foo).toBe(2)
- expect(props.bar).toEqual({ a: 1 })
- expect(props.baz).toEqual(defaultBaz)
- expect(defaultFn).toHaveBeenCalledTimes(1)
- expect(defaultBaz).toHaveBeenCalledTimes(0)
-
- // #999: updates should not cause default factory of unchanged prop to be
- // called again
- render({ foo: () => 3 })
-
- expect(props.foo).toBe(3)
- expect(props.bar).toEqual({ a: 1 })
-
- render({ bar: () => ({ b: 2 }) })
- expect(props.foo).toBe(1)
- expect(props.bar).toEqual({ b: 2 })
-
- render({
- foo: () => 3,
- bar: () => ({ b: 3 }),
- })
- expect(props.foo).toBe(3)
- expect(props.bar).toEqual({ b: 3 })
-
- render({ bar: () => ({ b: 4 }) })
- expect(props.foo).toBe(1)
- expect(props.bar).toEqual({ b: 4 })
- })
-
- test('using inject in default value factory', () => {
- let props: any
-
- const Child = defineVaporComponent({
- props: {
- test: {
- default: () => inject('test', 'default'),
- },
- },
- setup(_props) {
- props = _props
- return []
- },
- })
-
- const { render } = define({
- setup() {
- provide('test', 'injected')
- return createComponent(Child)
- },
- })
-
- render()
-
- expect(props.test).toBe('injected')
- })
-
- test('optimized props updates', async () => {
- const t0 = template('<div>')
- const { component: Child } = define({
- props: ['foo'],
- setup(props: any) {
- const n0 = t0()
- renderEffect(() => setElementText(n0, props.foo))
- return n0
- },
- })
-
- const foo = ref(1)
- const id = ref('a')
- const { host } = define({
- setup() {
- return { foo, id }
- },
- render(_ctx: Record<string, any>) {
- return createComponent(
- Child,
- {
- foo: () => _ctx.foo,
- id: () => _ctx.id,
- },
- null,
- true,
- )
- },
- }).render()
- expect(host.innerHTML).toBe('<div id="a">1</div>')
-
- foo.value++
- await nextTick()
- expect(host.innerHTML).toBe('<div id="a">2</div>')
-
- id.value = 'b'
- await nextTick()
- expect(host.innerHTML).toBe('<div id="b">2</div>')
- })
-
- describe('validator', () => {
- test('validator should be called with two arguments', () => {
- const mockFn = vi.fn((...args: any[]) => true)
- const props = {
- foo: () => 1,
- bar: () => 2,
- }
-
- const t0 = template('<div/>')
- define({
- props: {
- foo: {
- type: Number,
- validator: (value: any, props: any) => mockFn(value, props),
- },
- bar: {
- type: Number,
- },
- },
- setup() {
- return t0()
- },
- }).render(props)
-
- expect(mockFn).toHaveBeenCalledWith(1, { foo: 1, bar: 2 })
- })
-
- test('validator should not be able to mutate other props', async () => {
- const mockFn = vi.fn((...args: any[]) => true)
- define({
- props: {
- foo: {
- type: Number,
- validator: (value: any, props: any) => !!(props.bar = 1),
- },
- bar: {
- type: Number,
- validator: (value: any) => mockFn(value),
- },
- },
- setup() {
- const t0 = template('<div/>')
- const n0 = t0()
- return n0
- },
- }).render!({
- foo() {
- return 1
- },
- bar() {
- return 2
- },
- })
-
- expect(
- `Set operation on key "bar" failed: target is readonly.`,
- ).toHaveBeenWarnedLast()
- expect(mockFn).toHaveBeenCalledWith(2)
- })
- })
-
- test('warn props mutation', () => {
- let props: any
- const { render } = define({
- props: ['foo'],
- setup(_props: any) {
- props = _props
- return []
- },
- })
- render({ foo: () => 1 })
- expect(props.foo).toBe(1)
-
- props.foo = 2
- expect(`Attempt to mutate prop "foo" failed`).toHaveBeenWarned()
- })
-
- test('warn absent required props', () => {
- define({
- props: {
- bool: { type: Boolean, required: true },
- str: { type: String, required: true },
- num: { type: Number, required: true },
- },
- setup() {
- return []
- },
- }).render()
- expect(`Missing required prop: "bool"`).toHaveBeenWarned()
- expect(`Missing required prop: "str"`).toHaveBeenWarned()
- expect(`Missing required prop: "num"`).toHaveBeenWarned()
- })
-
- // NOTE: type check is not supported in vapor
- // test('warn on type mismatch', () => {})
-
- // #3495
- test('should not warn required props using kebab-case', async () => {
- define({
- props: {
- fooBar: { type: String, required: true },
- },
- setup() {
- return []
- },
- }).render({
- ['foo-bar']: () => 'hello',
- })
- expect(`Missing required prop: "fooBar"`).not.toHaveBeenWarned()
- })
-
- test('props type support BigInt', () => {
- const t0 = template('<div>')
- const { host } = define({
- props: {
- foo: BigInt,
- },
- setup(props: any) {
- const n0 = t0()
- renderEffect(() => setElementText(n0, props.foo))
- return n0
- },
- }).render({
- foo: () =>
- BigInt(BigInt(100000111)) + BigInt(2000000000) * BigInt(30000000),
- })
- expect(host.innerHTML).toBe('<div>60000000100000111</div>')
- })
-
- // #3474
- test('should cache the value returned from the default factory to avoid unnecessary watcher trigger', async () => {
- let count = 0
-
- const { render, html } = define({
- props: {
- foo: {
- type: Object,
- default: () => ({ val: 1 }),
- },
- bar: Number,
- },
- setup(props: any) {
- watch(
- () => props.foo,
- () => {
- count++
- },
- )
- const t0 = template('<h1></h1>')
- const n0 = t0()
- renderEffect(() => {
- setElementText(n0, String(props.foo.val) + String(props.bar))
- })
- return n0
- },
- })
-
- const foo = ref()
- const bar = ref(0)
- render({ foo: () => foo.value, bar: () => bar.value })
- expect(html()).toBe(`<h1>10</h1>`)
- expect(count).toBe(0)
-
- bar.value++
- await nextTick()
- expect(html()).toBe(`<h1>11</h1>`)
- expect(count).toBe(0)
- })
-
- // #3288
- test('declared prop key should be present even if not passed', async () => {
- let initialKeys: string[] = []
- const changeSpy = vi.fn()
- const passFoo = ref(false)
-
- const Comp: any = {
- props: {
- foo: String,
- },
- setup(props: any) {
- initialKeys = Object.keys(props)
- const { foo } = toRefs(props)
- watch(foo, changeSpy)
- return []
- },
- }
-
- define(() =>
- createComponent(Comp, {
- $: [() => (passFoo.value ? { foo: 'ok' } : {})],
- }),
- ).render()
-
- expect(initialKeys).toMatchObject(['foo'])
- passFoo.value = true
- await nextTick()
- expect(changeSpy).toHaveBeenCalledTimes(1)
- })
-
- test('should not warn invalid watch source when directly watching props', async () => {
- const changeSpy = vi.fn()
- const { render, html } = define({
- props: {
- foo: {
- type: String,
- },
- },
- setup(props: any) {
- watch(props, changeSpy)
- const t0 = template('<h1></h1>')
- const n0 = t0()
- renderEffect(() => {
- setElementText(n0, String(props.foo))
- })
- return n0
- },
- })
-
- const foo = ref('foo')
- render({ foo: () => foo.value })
- expect(html()).toBe(`<h1>foo</h1>`)
- expect('Invalid watch source').not.toHaveBeenWarned()
-
- foo.value = 'bar'
- await nextTick()
- expect(html()).toBe(`<h1>bar</h1>`)
- expect(changeSpy).toHaveBeenCalledTimes(1)
- })
-
- test('support null in required + multiple-type declarations', () => {
- const { render } = define({
- props: {
- foo: { type: [Function, null], required: true },
- },
- setup() {
- return []
- },
- })
-
- expect(() => {
- render({ foo: () => () => {} })
- }).not.toThrow()
-
- expect(() => {
- render({ foo: () => null })
- }).not.toThrow()
- })
-
- // #5016
- test('handling attr with undefined value', () => {
- const { render, host } = define({
- inheritAttrs: false,
- setup(_: any, { attrs }: any) {
- const t0 = template('<div></div>')
- const n0 = t0()
- renderEffect(() =>
- setElementText(n0, JSON.stringify(attrs) + Object.keys(attrs)),
- )
- return n0
- },
- })
-
- const attrs: any = { foo: () => undefined }
- render(attrs)
-
- expect(host.innerHTML).toBe(
- `<div>${JSON.stringify(attrs) + Object.keys(attrs)}</div>`,
- )
- })
-
- // #6915
- test('should not mutate original props long-form definition object', () => {
- const props = {
- msg: {
- type: String,
- },
- }
- define({ props, setup: () => [] }).render({ msg: () => 'test' })
-
- expect(Object.keys(props.msg).length).toBe(1)
- })
-
- test('should warn against reserved prop names', () => {
- const { render } = define({
- props: {
- $foo: String,
- },
- setup: () => [],
- })
-
- render({ msg: () => 'test' })
- expect(`Invalid prop name: "$foo"`).toHaveBeenWarned()
- })
-})
+++ /dev/null
-// NOTE: This test is implemented based on the case of `runtime-core/__test__/componentSlots.spec.ts`.
-
-import {
- createComponent,
- createForSlots,
- createIf,
- createSlot,
- createVaporApp,
- defineVaporComponent,
- insert,
- prepend,
- renderEffect,
- template,
-} from '../src'
-import { currentInstance, nextTick, ref } from '@vue/runtime-dom'
-import { makeRender } from './_utils'
-import type { DynamicSlot } from '../src/componentSlots'
-import { setElementText } from '../src/dom/prop'
-
-const define = makeRender<any>()
-
-function renderWithSlots(slots: any): any {
- let instance: any
- const Comp = defineVaporComponent({
- setup() {
- const t0 = template('<div></div>')
- const n0 = t0()
- instance = currentInstance
- return n0
- },
- })
-
- const { render } = define({
- render() {
- return createComponent(Comp, {}, slots)
- },
- })
-
- render()
- return instance
-}
-
-describe('component: slots', () => {
- test('initSlots: instance.slots should be set correctly', () => {
- const { slots } = renderWithSlots({
- default: () => template('<span></span>')(),
- })
-
- expect(slots.default()).toMatchObject(document.createElement('span'))
- })
-
- test('updateSlots: instance.slots should be updated correctly', async () => {
- const flag1 = ref(true)
-
- let instance: any
- const Child = () => {
- instance = currentInstance
- return template('child')()
- }
-
- const { render } = define({
- render() {
- return createComponent(
- Child,
- {},
- {
- $: [
- () =>
- flag1.value
- ? { name: 'one', fn: () => template('<span></span>')() }
- : { name: 'two', fn: () => template('<div></div>')() },
- ],
- },
- )
- },
- })
-
- render()
-
- expect(instance.slots).toHaveProperty('one')
- expect(instance.slots).not.toHaveProperty('two')
-
- flag1.value = false
- await nextTick()
-
- expect(instance.slots).not.toHaveProperty('one')
- expect(instance.slots).toHaveProperty('two')
- })
-
- test('should work with createFlorSlots', async () => {
- const loop = ref([1, 2, 3])
-
- let instance: any
- const Child = () => {
- instance = currentInstance
- return template('child')()
- }
-
- const { render } = define({
- setup() {
- return createComponent(Child, null, {
- $: [
- () =>
- createForSlots(loop.value, (item, i) => ({
- name: item,
- fn: () => template(item + i)(),
- })),
- ],
- })
- },
- })
- render()
-
- expect(instance.slots).toHaveProperty('1')
- expect(instance.slots).toHaveProperty('2')
- expect(instance.slots).toHaveProperty('3')
- loop.value.push(4)
- await nextTick()
- expect(instance.slots).toHaveProperty('4')
- loop.value.shift()
- await nextTick()
- expect(instance.slots).not.toHaveProperty('1')
- })
-
- // passes but no warning for slot invocation in vapor currently
- test.todo('should not warn when mounting another app in setup', () => {
- const Comp = defineVaporComponent({
- setup(_, { slots }) {
- return slots.default!()
- },
- })
- const mountComp = () => {
- createVaporApp({
- render() {
- return createComponent(
- Comp,
- {},
- { default: () => template('msg')() },
- )!
- },
- })
- }
- const App = {
- setup() {
- mountComp()
- return []
- },
- }
- createVaporApp(App).mount(document.createElement('div'))
- expect(
- 'Slot "default" invoked outside of the render function',
- ).not.toHaveBeenWarned()
- })
-
- describe('createSlot', () => {
- test('slot should be rendered correctly', () => {
- const Comp = defineVaporComponent(() => {
- const n0 = template('<div>')()
- insert(createSlot('header'), n0 as any as ParentNode)
- return n0
- })
-
- const { host } = define(() => {
- return createComponent(Comp, null, {
- header: () => template('header')(),
- })
- }).render()
-
- expect(host.innerHTML).toBe('<div>header<!--slot--></div>')
- })
-
- test('slot should be rendered correctly with slot props', async () => {
- const src = ref('header')
-
- const Comp = defineVaporComponent(() => {
- const n0 = template('<div></div>')()
- insert(
- createSlot('header', { title: () => src.value }),
- n0 as any as ParentNode,
- )
- return n0
- })
-
- const { host } = define(() => {
- return createComponent(Comp, null, {
- header: props => {
- const el = template('<h1></h1>')()
- renderEffect(() => {
- setElementText(el, props.title)
- })
- return el
- },
- })
- }).render()
-
- expect(host.innerHTML).toBe('<div><h1>header</h1><!--slot--></div>')
-
- src.value = 'footer'
- await nextTick()
- expect(host.innerHTML).toBe('<div><h1>footer</h1><!--slot--></div>')
- })
-
- test('dynamic slot props', async () => {
- let props: any
-
- const bindObj = ref<Record<string, any>>({ foo: 1, baz: 'qux' })
- const Comp = defineVaporComponent(() =>
- createSlot('default', { $: [() => bindObj.value] }),
- )
- define(() =>
- createComponent(Comp, null, {
- default: _props => ((props = _props), []),
- }),
- ).render()
-
- expect(props).toEqual({ foo: 1, baz: 'qux' })
-
- bindObj.value.foo = 2
- await nextTick()
- expect(props).toEqual({ foo: 2, baz: 'qux' })
-
- delete bindObj.value.baz
- await nextTick()
- expect(props).toEqual({ foo: 2 })
- })
-
- test('dynamic slot props with static slot props', async () => {
- let props: any
-
- const foo = ref(0)
- const bindObj = ref<Record<string, any>>({ foo: 100, baz: 'qux' })
- const Comp = defineVaporComponent(() =>
- createSlot('default', {
- foo: () => foo.value,
- $: [() => bindObj.value],
- }),
- )
- define(() =>
- createComponent(Comp, null, {
- default: _props => ((props = _props), []),
- }),
- ).render()
-
- expect(props).toEqual({ foo: 100, baz: 'qux' })
-
- foo.value = 2
- await nextTick()
- expect(props).toEqual({ foo: 100, baz: 'qux' })
-
- delete bindObj.value.foo
- await nextTick()
- expect(props).toEqual({ foo: 2, baz: 'qux' })
- })
-
- test('dynamic slot should be rendered correctly with slot props', async () => {
- const val = ref('header')
-
- const Comp = defineVaporComponent(() => {
- const n0 = template('<div></div>')()
- prepend(
- n0 as any as ParentNode,
- createSlot('header', { title: () => val.value }),
- )
- return n0
- })
-
- const { host } = define(() => {
- // dynamic slot
- return createComponent(Comp, null, {
- $: [
- () => ({
- name: 'header',
- fn: (props: any) => {
- const el = template('<h1></h1>')()
- renderEffect(() => {
- setElementText(el, props.title)
- })
- return el
- },
- }),
- ],
- })
- }).render()
-
- expect(host.innerHTML).toBe('<div><h1>header</h1><!--slot--></div>')
-
- val.value = 'footer'
- await nextTick()
- expect(host.innerHTML).toBe('<div><h1>footer</h1><!--slot--></div>')
- })
-
- test('dynamic slot outlet should be render correctly with slot props', async () => {
- const val = ref('header')
-
- const Comp = defineVaporComponent(() => {
- const n0 = template('<div></div>')()
- prepend(
- n0 as any as ParentNode,
- createSlot(
- () => val.value, // dynamic slot outlet name
- ),
- )
- return n0
- })
-
- const { host } = define(() => {
- return createComponent(Comp, null, {
- header: () => template('header')(),
- footer: () => template('footer')(),
- })
- }).render()
-
- expect(host.innerHTML).toBe('<div>header<!--slot--></div>')
-
- val.value = 'footer'
- await nextTick()
- expect(host.innerHTML).toBe('<div>footer<!--slot--></div>')
- })
-
- test('fallback should be render correctly', () => {
- const Comp = defineVaporComponent(() => {
- const n0 = template('<div></div>')()
- insert(
- createSlot('header', undefined, () => template('fallback')()),
- n0 as any as ParentNode,
- )
- return n0
- })
-
- const { host } = define(() => {
- return createComponent(Comp, {}, {})
- }).render()
-
- expect(host.innerHTML).toBe('<div>fallback<!--slot--></div>')
- })
-
- test('dynamic slot should be updated correctly', async () => {
- const flag1 = ref(true)
-
- const Child = defineVaporComponent(() => {
- const temp0 = template('<p></p>')
- const el0 = temp0()
- const el1 = temp0()
- const slot1 = createSlot('one', null, () => template('one fallback')())
- const slot2 = createSlot('two', null, () => template('two fallback')())
- insert(slot1, el0 as any as ParentNode)
- insert(slot2, el1 as any as ParentNode)
- return [el0, el1]
- })
-
- const { host } = define(() => {
- return createComponent(Child, null, {
- $: [
- () =>
- flag1.value
- ? { name: 'one', fn: () => template('one content')() }
- : { name: 'two', fn: () => template('two content')() },
- ],
- })
- }).render()
-
- expect(host.innerHTML).toBe(
- '<p>one content<!--slot--></p><p>two fallback<!--slot--></p>',
- )
-
- flag1.value = false
- await nextTick()
-
- expect(host.innerHTML).toBe(
- '<p>one fallback<!--slot--></p><p>two content<!--slot--></p>',
- )
-
- flag1.value = true
- await nextTick()
-
- expect(host.innerHTML).toBe(
- '<p>one content<!--slot--></p><p>two fallback<!--slot--></p>',
- )
- })
-
- test('dynamic slot outlet should be updated correctly', async () => {
- const slotOutletName = ref('one')
-
- const Child = defineVaporComponent(() => {
- const temp0 = template('<p>')
- const el0 = temp0()
- const slot1 = createSlot(
- () => slotOutletName.value,
- undefined,
- () => template('fallback')(),
- )
- insert(slot1, el0 as any as ParentNode)
- return el0
- })
-
- const { host } = define(() => {
- return createComponent(
- Child,
- {},
- {
- one: () => template('one content')(),
- two: () => template('two content')(),
- },
- )
- }).render()
-
- expect(host.innerHTML).toBe('<p>one content<!--slot--></p>')
-
- slotOutletName.value = 'two'
- await nextTick()
-
- expect(host.innerHTML).toBe('<p>two content<!--slot--></p>')
-
- slotOutletName.value = 'none'
- await nextTick()
-
- expect(host.innerHTML).toBe('<p>fallback<!--slot--></p>')
- })
-
- test('non-exist slot', async () => {
- const Child = defineVaporComponent(() => {
- const el0 = template('<p>')()
- const slot = createSlot('not-exist', undefined)
- insert(slot, el0 as any as ParentNode)
- return el0
- })
-
- const { host } = define(() => {
- return createComponent(Child)
- }).render()
-
- expect(host.innerHTML).toBe('<p><!--slot--></p>')
- })
-
- test('use fallback when inner content changes', async () => {
- const Child = {
- setup() {
- return createSlot('default', null, () =>
- document.createTextNode('fallback'),
- )
- },
- }
-
- const toggle = ref(true)
-
- const { html } = define({
- setup() {
- return createComponent(Child, null, {
- default: () => {
- return createIf(
- () => toggle.value,
- () => {
- return document.createTextNode('content')
- },
- )
- },
- })
- },
- }).render()
-
- expect(html()).toBe('content<!--if--><!--slot-->')
-
- toggle.value = false
- await nextTick()
- expect(html()).toBe('fallback<!--if--><!--slot-->')
-
- toggle.value = true
- await nextTick()
- expect(html()).toBe('content<!--if--><!--slot-->')
- })
-
- test('dynamic slot work with v-if', async () => {
- const val = ref('header')
- const toggle = ref(false)
-
- const Comp = defineVaporComponent(() => {
- const n0 = template('<div></div>')()
- prepend(n0 as any as ParentNode, createSlot('header', null))
- return n0
- })
-
- const { host } = define(() => {
- // dynamic slot
- return createComponent(Comp, null, {
- $: [
- () =>
- (toggle.value
- ? {
- name: val.value,
- fn: () => {
- return template('<h1></h1>')()
- },
- }
- : void 0) as DynamicSlot,
- ],
- })
- }).render()
-
- expect(host.innerHTML).toBe('<div><!--slot--></div>')
-
- toggle.value = true
- await nextTick()
- expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
- })
- })
-})
+++ /dev/null
-import { effectScope, ref } from '@vue/reactivity'
-import { type VaporDirective, withVaporDirectives } from '../../src'
-import { nextTick, watchEffect } from '@vue/runtime-dom'
-
-describe('custom directive', () => {
- it('should work', async () => {
- const teardown = vi.fn()
- const dir: VaporDirective = vi.fn((el, source) => {
- watchEffect(() => {
- el.textContent = source()
- })
- return teardown
- })
- const scope = effectScope()
- const el = document.createElement('div')
- const n = ref(1)
- const source = () => n.value
- const modifiers = { mod: true }
- scope.run(() => {
- withVaporDirectives(el, [[dir, source, undefined, modifiers]])
- })
- expect(dir).toHaveBeenCalledWith(el, source, undefined, modifiers)
- expect(teardown).not.toHaveBeenCalled()
-
- expect(el.textContent).toBe('1')
-
- n.value = 2
- await nextTick()
- expect(el.textContent).toBe('2')
-
- scope.stop()
- expect(teardown).toHaveBeenCalled()
-
- n.value = 3
- await nextTick()
- // should be stopped and not update
- expect(el.textContent).toBe('2')
- })
-})
+++ /dev/null
-import { reactive, ref } from '@vue/reactivity'
-import {
- applyCheckboxModel,
- applyRadioModel,
- applySelectModel,
- applyTextModel,
- delegate,
- delegateEvents,
- on,
- setClass,
- setProp,
- setValue,
- template,
-} from '../../src'
-import { makeRender } from '../_utils'
-import { nextTick } from '@vue/runtime-dom'
-
-const define = makeRender()
-
-const triggerEvent = (type: string, el: Element) => {
- const event = new Event(type, { bubbles: true })
- el.dispatchEvent(event)
-}
-
-const setDOMProps = (el: any, props: Array<[key: string, value: any]>) => {
- props.forEach(prop => {
- const [key, value] = prop
- key === 'class' ? setClass(el, value) : setProp(el, key, value)
- })
-}
-
-describe('directive: v-model', () => {
- test('should work with text input', async () => {
- const spy = vi.fn()
-
- const data = ref<string | null | undefined>('')
- const { host } = define(() => {
- const t0 = template('<input />')
- delegateEvents('input')
- const n0 = t0() as HTMLInputElement
- applyTextModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- delegate(n0, 'input', () => spy(data.value))
- return n0
- }).render()
-
- const input = host.querySelector('input')!
- expect(input.value).toEqual('')
-
- input.value = 'foo'
- triggerEvent('input', input)
- await nextTick()
- expect(data.value).toEqual('foo')
- expect(spy).toHaveBeenCalledWith('foo')
-
- data.value = 'bar'
- await nextTick()
- expect(input.value).toEqual('bar')
-
- data.value = undefined
- await nextTick()
- expect(input.value).toEqual('')
- })
-
- test('should work with select', async () => {
- const spy = vi.fn()
- const data = ref<string | null>('')
- const { host } = define(() => {
- const t0 = template(
- '<select><option>red</option><option>green</option><option>blue</option></select>',
- )
- const n0 = t0() as HTMLSelectElement
- applySelectModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- on(n0, 'change', () => spy(data.value))
- return n0
- }).render()
-
- const select = host.querySelector('select')!
- expect(select.value).toEqual('')
-
- select.value = 'red'
- triggerEvent('change', select)
- await nextTick()
- expect(data.value).toEqual('red')
- expect(spy).toHaveBeenCalledWith('red')
-
- data.value = 'blue'
- await nextTick()
- expect(select.value).toEqual('blue')
- })
-
- test('should work with number input', async () => {
- const data = ref<number | null>(null)
- const { host } = define(() => {
- const t0 = template('<input />')
- const n0 = t0() as HTMLInputElement
- applyTextModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- n0.type = 'number'
- return n0
- }).render()
-
- const input = host.querySelector('input')!
- expect(input.value).toEqual('')
- expect(input.type).toEqual('number')
-
- // @ts-expect-error
- input.value = 1
- triggerEvent('input', input)
- await nextTick()
- expect(typeof data.value).toEqual('number')
- expect(data.value).toEqual(1)
- })
-
- test('should work with textarea', async () => {
- const data = ref<string>('')
- const { host } = define(() => {
- const t0 = template('<textarea />')
- const n0 = t0() as HTMLInputElement
- applyTextModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- const input = host.querySelector('textarea')!
-
- input.value = 'foo'
- triggerEvent('input', input)
- await nextTick()
- expect(data.value).toEqual('foo')
-
- data.value = 'bar'
- await nextTick()
- expect(input.value).toEqual('bar')
- })
-
- test('should support modifiers', async () => {
- const data = reactive<{
- number: number | null
- trim: string | null
- lazy: string | null
- trimNumber: number | null
- }>({ number: null, trim: null, lazy: null, trimNumber: null })
-
- const { host } = define(() => {
- const t0 = template(`<div>${'<input/>'.repeat(4)}</div>`)
- const n0 = t0() as HTMLInputElement
- const [input1, input2, input3, input4] = Array.from(
- n0.children,
- ) as Array<HTMLInputElement>
-
- // number
- setClass(input1, 'number')
- applyTextModel(
- input1,
- () => data.number,
- val => (data.number = val),
- { number: true },
- )
-
- // trim
- setClass(input2, 'trim')
- applyTextModel(
- input2,
- () => data.trim,
- val => (data.trim = val),
- { trim: true },
- )
-
- // trim & number
- setClass(input3, 'trim-number')
- applyTextModel(
- input3,
- () => data.trimNumber,
- val => (data.trimNumber = val),
- { trim: true, number: true },
- )
-
- // lazy
- setClass(input4, 'lazy')
- applyTextModel(
- input4,
- () => data.lazy,
- val => (data.lazy = val),
- { lazy: true },
- )
-
- return n0
- }).render()
-
- const number = host.querySelector('.number') as HTMLInputElement
- const trim = host.querySelector('.trim') as HTMLInputElement
- const trimNumber = host.querySelector('.trim-number') as HTMLInputElement
- const lazy = host.querySelector('.lazy') as HTMLInputElement
-
- number.value = '+01.2'
- triggerEvent('input', number)
- await nextTick()
- expect(data.number).toEqual(1.2)
-
- trim.value = ' hello, world '
- triggerEvent('input', trim)
- await nextTick()
- expect(data.trim).toEqual('hello, world')
-
- trimNumber.value = ' 1 '
- triggerEvent('input', trimNumber)
- await nextTick()
- expect(data.trimNumber).toEqual(1)
-
- trimNumber.value = ' +01.2 '
- triggerEvent('input', trimNumber)
- await nextTick()
- expect(data.trimNumber).toEqual(1.2)
-
- lazy.value = 'foo'
- triggerEvent('change', lazy)
- await nextTick()
- expect(data.lazy).toEqual('foo')
- })
-
- test('should work with range', async () => {
- const data = ref<number>(25)
- let n1: HTMLInputElement, n2: HTMLInputElement
- define(() => {
- const t0 = template(
- `<div>` +
- `<input type="range" min="1" max="100">` +
- `<input type="range" min="1" max="100">` +
- `</div>`,
- )
- const n0 = t0() as HTMLInputElement
- ;[n1, n2] = Array.from(n0.children) as Array<HTMLInputElement>
-
- applyTextModel(
- n1,
- () => data.value,
- val => (data.value = val),
- { number: true },
- )
-
- applyTextModel(
- n2,
- () => data.value,
- val => (data.value = val),
- {
- lazy: true,
- },
- )
-
- return n0
- }).render()
-
- // @ts-expect-error
- n1.value = 20
- triggerEvent('input', n1!)
- await nextTick()
- expect(data.value).toEqual(20)
-
- // @ts-expect-error
- n1.value = 200
- triggerEvent('input', n1!)
- await nextTick()
- expect(data.value).toEqual(100)
-
- // @ts-expect-error
- n1.value = -1
- triggerEvent('input', n1!)
- await nextTick()
- expect(data.value).toEqual(1)
-
- // @ts-expect-error
- n2.value = 30
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toEqual('30')
-
- // @ts-expect-error
- n2.value = 200
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toEqual('100')
-
- // @ts-expect-error
- n2.value = -1
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toEqual('1')
-
- data.value = 60
- await nextTick()
- expect(n1!.value).toEqual('60')
- expect(n2!.value).toEqual('60')
-
- data.value = -1
- await nextTick()
- expect(n1!.value).toEqual('1')
- expect(n2!.value).toEqual('1')
-
- data.value = 200
- await nextTick()
- expect(n1!.value).toEqual('100')
- expect(n2!.value).toEqual('100')
- })
-
- test('should work with checkbox', async () => {
- const data = ref<boolean | null>(null)
- const { host } = define(() => {
- const t0 = template('<input type="checkbox" />')
- const n0 = t0() as HTMLInputElement
- applyCheckboxModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- const input = host.querySelector('input') as HTMLInputElement
-
- input.checked = true
- triggerEvent('change', input)
- await nextTick()
- expect(data.value).toEqual(true)
-
- data.value = false
- await nextTick()
- expect(input.checked).toEqual(false)
-
- data.value = true
- await nextTick()
- expect(input.checked).toEqual(true)
-
- input.checked = false
- triggerEvent('change', input)
- await nextTick()
- expect(data.value).toEqual(false)
- })
-
- test('should work with checkbox and true-value/false-value', async () => {
- const data = ref<string | null>('yes')
- const { host } = define(() => {
- const t0 = template(
- '<input type="checkbox" true-value="yes" false-value="no" />',
- )
- const n0 = t0() as HTMLInputElement
- applyCheckboxModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- const input = host.querySelector('input') as HTMLInputElement
-
- // DOM checked state should respect initial true-value/false-value
- expect(input.checked).toEqual(true)
- input.checked = false
- triggerEvent('change', input)
- await nextTick()
- expect(data.value).toEqual('no')
-
- data.value = 'yes'
- await nextTick()
- expect(input.checked).toEqual(true)
-
- data.value = 'no'
- await nextTick()
- expect(input.checked).toEqual(false)
-
- input.checked = true
- triggerEvent('change', input)
- await nextTick()
- expect(data.value).toEqual('yes')
- })
-
- test('should work with checkbox and true-value/false-value with object values', async () => {
- const data = ref<{ yes?: 'yes'; no?: 'no' } | null>(null)
- const { host } = define(() => {
- const t0 = template('<input type="checkbox" />')
- const n0 = t0() as HTMLInputElement
- setDOMProps(n0, [
- ['true-value', { yes: 'yes' }],
- ['false-value', { no: 'no' }],
- ])
- applyCheckboxModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- const input = host.querySelector('input') as HTMLInputElement
- input.checked = true
- triggerEvent('change', input)
- await nextTick()
- expect(data.value).toEqual({ yes: 'yes' })
-
- data.value = { no: 'no' }
- await nextTick()
- expect(input.checked).toEqual(false)
-
- data.value = { yes: 'yes' }
- await nextTick()
- expect(input.checked).toEqual(true)
-
- input.checked = false
- triggerEvent('change', input)
- await nextTick()
- expect(data.value).toEqual({ no: 'no' })
- })
-
- test(`should support array as a checkbox model`, async () => {
- const data = ref<Array<string>>([])
- let n1: HTMLInputElement, n2: HTMLInputElement
- define(() => {
- const t0 = template(
- `<div>` +
- `<input type="checkbox" value="foo">` +
- `<input type="checkbox" value="bar">` +
- `</div>`,
- )
- const n0 = t0() as HTMLInputElement
- ;[n1, n2] = Array.from(n0.children) as Array<HTMLInputElement>
-
- applyCheckboxModel(
- n1,
- () => data.value,
- val => (data.value = val),
- )
- applyCheckboxModel(
- n2,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- n1!.checked = true
- triggerEvent('change', n1!)
- await nextTick()
- expect(data.value).toMatchObject(['foo'])
-
- n2!.checked = true
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toMatchObject(['foo', 'bar'])
-
- n2!.checked = false
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toMatchObject(['foo'])
-
- n1!.checked = false
- triggerEvent('change', n1!)
- await nextTick()
- expect(data.value).toMatchObject([])
-
- data.value = ['foo']
- await nextTick()
- expect(n2!.checked).toEqual(false)
- expect(n1!.checked).toEqual(true)
-
- data.value = ['bar']
- await nextTick()
- expect(n1!.checked).toEqual(false)
- expect(n2!.checked).toEqual(true)
-
- data.value = []
- await nextTick()
- expect(n1!.checked).toEqual(false)
- expect(n2!.checked).toEqual(false)
- })
-
- test(`should support Set as a checkbox model`, async () => {
- const data = ref<Set<string>>(new Set())
- let n1: HTMLInputElement, n2: HTMLInputElement
- define(() => {
- const t0 = template(
- `<div>` +
- `<input type="checkbox" value="foo">` +
- `<input type="checkbox" value="bar">` +
- `</div>`,
- )
- const n0 = t0() as HTMLInputElement
- ;[n1, n2] = Array.from(n0.children) as Array<HTMLInputElement>
-
- applyCheckboxModel(
- n1,
- () => data.value,
- val => (data.value = val),
- )
- applyCheckboxModel(
- n2,
- () => data.value,
- val => (data.value = val),
- )
-
- return n0
- }).render()
-
- n1!.checked = true
- triggerEvent('change', n1!)
- await nextTick()
- expect(data.value).toMatchObject(new Set(['foo']))
-
- n2!.checked = true
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toMatchObject(new Set(['foo', 'bar']))
-
- n2!.checked = false
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toMatchObject(new Set(['foo']))
-
- n1!.checked = false
- triggerEvent('change', n1!)
- await nextTick()
- expect(data.value).toMatchObject(new Set())
-
- data.value = new Set(['foo'])
- await nextTick()
- expect(n2!.checked).toEqual(false)
- expect(n1!.checked).toEqual(true)
-
- data.value = new Set(['bar'])
- await nextTick()
- expect(n1!.checked).toEqual(false)
- expect(n2!.checked).toEqual(true)
-
- data.value = new Set()
- await nextTick()
- expect(n1!.checked).toEqual(false)
- expect(n2!.checked).toEqual(false)
- })
-
- test('should work with radio', async () => {
- const data = ref<string | null>(null)
- let n1: HTMLInputElement, n2: HTMLInputElement
- define(() => {
- const t0 = template(
- `<div>` +
- `<input type="radio" value="foo">` +
- `<input type="radio" value="bar">` +
- `</div>`,
- )
- const n0 = t0() as HTMLInputElement
- ;[n1, n2] = Array.from(n0.children) as Array<HTMLInputElement>
-
- applyRadioModel(
- n1,
- () => data.value,
- val => (data.value = val),
- )
- applyRadioModel(
- n2,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- n1!.checked = true
- triggerEvent('change', n1!)
- await nextTick()
- expect(data.value).toEqual('foo')
-
- n2!.checked = true
- triggerEvent('change', n2!)
- await nextTick()
- expect(data.value).toEqual('bar')
-
- data.value = null
- await nextTick()
- expect(n1!.checked).toEqual(false)
- expect(n2!.checked).toEqual(false)
-
- data.value = 'foo'
- await nextTick()
- expect(n1!.checked).toEqual(true)
- expect(n2!.checked).toEqual(false)
-
- data.value = 'bar'
- await nextTick()
- expect(n1!.checked).toEqual(false)
- expect(n2!.checked).toEqual(true)
- })
-
- test('should work with single select', async () => {
- const data = ref<string | null>(null)
- let select: HTMLSelectElement, n1: HTMLOptionElement, n2: HTMLOptionElement
- define(() => {
- const t0 = template(
- '<select><option value="foo"></option><option value="bar"></option></select>',
- )
- select = t0() as HTMLSelectElement
- ;[n1, n2] = Array.from(select.childNodes) as Array<HTMLOptionElement>
-
- applySelectModel(
- select,
- () => data.value,
- val => (data.value = val),
- )
- return select
- }).render()
-
- n1!.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toEqual('foo')
-
- n1!.selected = false
- n2!.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toEqual('bar')
-
- n1!.selected = false
- n2!.selected = false
- data.value = 'foo'
- await nextTick()
- expect(select!.value).toEqual('foo')
- expect(n1!.selected).toEqual(true)
- expect(n2!.selected).toEqual(false)
-
- n1!.selected = true
- n2!.selected = false
- data.value = 'bar'
- await nextTick()
- expect(select!.value).toEqual('bar')
- expect(n1!.selected).toEqual(false)
- expect(n2!.selected).toEqual(true)
- })
-
- test('should work with multiple select (model is Array)', async () => {
- const data = ref<Array<string>>([])
- let select: HTMLSelectElement, n1: HTMLOptionElement, n2: HTMLOptionElement
- define(() => {
- const t0 = template(
- '<select multiple>' +
- '<option value="foo"></option><option value="bar"></option>' +
- '</select>',
- )
- select = t0() as HTMLSelectElement
- ;[n1, n2] = Array.from(select.childNodes) as Array<HTMLOptionElement>
-
- applySelectModel(
- select,
- () => data.value,
- val => (data.value = val),
- )
- return select
- }).render()
-
- n1!.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject(['foo'])
-
- n1!.selected = false
- n2!.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject(['bar'])
-
- n1!.selected = true
- n2!.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject(['foo', 'bar'])
-
- n1!.selected = false
- n2!.selected = false
- data.value = ['foo']
- await nextTick()
- expect(select!.value).toEqual('foo')
- expect(n1!.selected).toEqual(true)
- expect(n2!.selected).toEqual(false)
-
- n1!.selected = false
- n2!.selected = false
- data.value = ['foo', 'bar']
- await nextTick()
- expect(n1!.selected).toEqual(true)
- expect(n2!.selected).toEqual(true)
- })
-
- test('v-model.number should work with single select', async () => {
- const data = ref<string | null>(null)
- let select: HTMLSelectElement, n1: HTMLOptionElement
- define(() => {
- const t0 = template(
- '<select><option value="1"></option><option value="2"></option></select>',
- )
- select = t0() as HTMLSelectElement
- n1 = select.childNodes[0] as HTMLOptionElement
- applySelectModel(
- select,
- () => data.value,
- val => (data.value = val),
- { number: true },
- )
- return select
- }).render()
-
- n1!.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(typeof data.value).toEqual('number')
- expect(data.value).toEqual(1)
- })
-
- test('v-model.number should work with multiple select', async () => {
- const data = ref<Array<number>>([])
- let select: HTMLSelectElement
- const { host } = define(() => {
- const t0 = template(
- '<select multiple>' +
- '<option value="1"></option><option value="2"></option>' +
- '</select>',
- )
- select = t0() as HTMLSelectElement
- applySelectModel(
- select,
- () => data.value,
- val => (data.value = val),
- { number: true },
- )
- return select
- }).render()
-
- const one = host.querySelector('option[value="1"]') as HTMLOptionElement
- const two = host.querySelector('option[value="2"]') as HTMLOptionElement
-
- one.selected = true
- two.selected = false
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([1])
-
- one.selected = false
- two.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([2])
-
- one.selected = true
- two.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([1, 2])
-
- one.selected = false
- two.selected = false
- data.value = [1]
- await nextTick()
- expect(one.selected).toEqual(true)
- expect(two.selected).toEqual(false)
-
- one.selected = false
- two.selected = false
- data.value = [1, 2]
- await nextTick()
- expect(one.selected).toEqual(true)
- expect(two.selected).toEqual(true)
- })
-
- test('multiple select (model is Array, option value is object)', async () => {
- const fooValue = { foo: 1 }
- const barValue = { bar: 1 }
-
- const data = ref<Array<number>>([])
-
- let select: HTMLSelectElement
- const { host } = define(() => {
- const t0 = template(
- '<select multiple><option></option><option></option></select>',
- )
- select = t0() as HTMLSelectElement
- const [n1, n2] = Array.from(select.childNodes) as Array<HTMLOptionElement>
- setValue(n1, fooValue)
- setValue(n2, barValue)
- applySelectModel(
- select,
- () => data.value,
- val => (data.value = val),
- )
- return select
- }).render()
-
- const [foo, bar] = Array.from(
- host.querySelectorAll('option'),
- ) as Array<HTMLOptionElement>
-
- foo.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([fooValue])
-
- foo.selected = false
- bar.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([barValue])
-
- foo.selected = true
- bar.selected = true
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([fooValue, barValue])
-
- // reset
- foo.selected = false
- bar.selected = false
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([])
-
- // @ts-expect-error
- data.value = [fooValue, barValue]
- await nextTick()
- expect(foo.selected).toEqual(true)
- expect(bar.selected).toEqual(true)
-
- // reset
- foo.selected = false
- bar.selected = false
- triggerEvent('change', select!)
- await nextTick()
- expect(data.value).toMatchObject([])
-
- // @ts-expect-error
- data.value = [{ foo: 1 }, { bar: 1 }]
- await nextTick()
- // looseEqual
- expect(foo.selected).toEqual(true)
- expect(bar.selected).toEqual(true)
- })
-
- test('multiple select (model is Set)', async () => {
- const data = ref<Set<string>>(new Set())
- const { host } = define(() => {
- const t0 = template(
- '<select multiple><option value="foo"></option><option value="bar"></option></select>',
- )
- const n0 = t0() as HTMLSelectElement
- applySelectModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- const select = host.querySelector('select') as HTMLSelectElement
- const foo = host.querySelector('option[value=foo]') as HTMLOptionElement
- const bar = host.querySelector('option[value=bar]') as HTMLOptionElement
-
- foo.selected = true
- triggerEvent('change', select)
- await nextTick()
- expect(data.value).toBeInstanceOf(Set)
- expect(data.value).toMatchObject(new Set(['foo']))
-
- foo.selected = false
- bar.selected = true
- triggerEvent('change', select)
- await nextTick()
- expect(data.value).toBeInstanceOf(Set)
- expect(data.value).toMatchObject(new Set(['bar']))
-
- foo.selected = true
- bar.selected = true
- triggerEvent('change', select)
- await nextTick()
- expect(data.value).toBeInstanceOf(Set)
- expect(data.value).toMatchObject(new Set(['foo', 'bar']))
-
- foo.selected = false
- bar.selected = false
- data.value = new Set(['foo'])
- await nextTick()
- expect(select.value).toEqual('foo')
- expect(foo.selected).toEqual(true)
- expect(bar.selected).toEqual(false)
-
- foo.selected = false
- bar.selected = false
- data.value = new Set(['foo', 'bar'])
- await nextTick()
- expect(foo.selected).toEqual(true)
- expect(bar.selected).toEqual(true)
- })
-
- test('multiple select (model is set, option value is object)', async () => {
- const fooValue = { foo: 1 }
- const barValue = { bar: 1 }
-
- const data = ref<Set<string>>(new Set())
- const { host } = define(() => {
- const t0 = template(
- '<select multiple><option></option><option></option></select>',
- )
- const n0 = t0() as HTMLSelectElement
- const [n1, n2] = Array.from(n0.childNodes) as Array<HTMLOptionElement>
- setValue(n1, fooValue)
- setValue(n2, barValue)
- applySelectModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- const select = host.querySelector('select') as HTMLSelectElement
- const [foo, bar] = Array.from(
- host.querySelectorAll('option'),
- ) as Array<HTMLOptionElement>
-
- foo.selected = true
- triggerEvent('change', select)
- await nextTick()
- expect(data.value).toMatchObject(new Set([fooValue]))
-
- foo.selected = false
- bar.selected = true
- triggerEvent('change', select)
- await nextTick()
- expect(data.value).toMatchObject(new Set([barValue]))
-
- foo.selected = true
- bar.selected = true
- triggerEvent('change', select)
- await nextTick()
- expect(data.value).toMatchObject(new Set([fooValue, barValue]))
-
- foo.selected = false
- bar.selected = false
- // @ts-expect-error
- data.value = new Set([fooValue, barValue])
- await nextTick()
- expect(foo.selected).toEqual(true)
- expect(bar.selected).toEqual(true)
-
- foo.selected = false
- bar.selected = false
- // @ts-expect-error
- data.value = new Set([{ foo: 1 }, { bar: 1 }])
- await nextTick()
- // without looseEqual, here is different from Array
- expect(foo.selected).toEqual(false)
- expect(bar.selected).toEqual(false)
- })
-
- test('should work with composition session', async () => {
- const data = ref<string>('')
- const { host } = define(() => {
- const t0 = template('<input />')
- const n0 = t0() as HTMLInputElement
- applyTextModel(
- n0,
- () => data.value,
- val => (data.value = val),
- )
- return n0
- }).render()
-
- const input = host.querySelector('input') as HTMLInputElement
-
- //developer.mozilla.org/en-US/docs/Web/API/Element/compositionstart_event
- //compositionstart event could be fired after a user starts entering a Chinese character using a Pinyin IME
- input.value = '使用拼音'
- triggerEvent('compositionstart', input)
- await nextTick()
- expect(data.value).toEqual('')
-
- // input event has no effect during composition session
- input.value = '使用拼音输入'
- triggerEvent('input', input)
- await nextTick()
- expect(data.value).toEqual('')
-
- // After compositionend event being fired, an input event will be automatically trigger
- triggerEvent('compositionend', input)
- await nextTick()
- expect(data.value).toEqual('使用拼音输入')
- })
-})
+++ /dev/null
-import {
- applyVShow,
- createComponent,
- createIf,
- defineVaporComponent,
- on,
- template,
-} from '../../src'
-import { type VShowElement, nextTick, ref } from 'vue'
-import { describe, expect, test } from 'vitest'
-import { makeRender } from '../_utils'
-
-const define = makeRender()
-
-const createDemo = (defaultValue: boolean) =>
- define(() => {
- const visible = ref(defaultValue)
- function handleClick() {
- visible.value = !visible.value
- }
- const t0 = template(
- '<div><button>toggle</button><h1>hello world</h1></div>',
- )
- const n0 = t0()
- const n1 = n0.firstChild!
- const n2 = n1.nextSibling
- applyVShow(n2 as VShowElement, () => visible.value)
- on(n1 as HTMLElement, 'click', handleClick)
- return n0
- })
-
-describe('directive: v-show', () => {
- test('basic', async () => {
- const { host } = createDemo(true).render()
- const btn = host.querySelector('button')
- expect(host.innerHTML).toBe(
- '<div><button>toggle</button><h1>hello world</h1></div>',
- )
- btn?.click()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<div><button>toggle</button><h1 style="display: none;">hello world</h1></div>',
- )
- })
- test('should hide content when default value is false', async () => {
- const { host } = createDemo(false).render()
- const btn = host.querySelector('button')
- const h1 = host.querySelector('h1')
- expect(h1?.style.display).toBe('none')
- btn?.click()
- await nextTick()
- expect(h1?.style.display).toBe('')
- })
-
- test('should work on component', async () => {
- const t0 = template('<div>child</div>')
- const visible = ref(true)
-
- const { component: Child } = define({
- setup() {
- return t0()
- },
- })
-
- const { host } = define({
- setup() {
- const n1 = createComponent(Child, null, null, true)
- applyVShow(n1, () => visible.value)
- return n1
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div>child</div>')
-
- visible.value = !visible.value
- await nextTick()
- expect(host.innerHTML).toBe('<div style="display: none;">child</div>')
- })
-
- test('warn on non-single-element-root component', () => {
- const Child = defineVaporComponent({
- setup() {
- return document.createTextNode('b')
- },
- })
- define({
- setup() {
- const n1 = createComponent(Child)
- applyVShow(n1, () => true)
- return n1
- },
- }).render()
- expect(
- 'v-show used on component with non-single-element root node',
- ).toHaveBeenWarned()
- })
-
- test('should work on component with dynamic fragment root', async () => {
- const t0 = template('<div>child</div>')
- const t1 = template('<span>child</span>')
- const childIf = ref(true)
- const visible = ref(true)
-
- const { component: Child } = define({
- setup() {
- return createIf(
- () => childIf.value,
- () => t0(),
- () => t1(),
- )
- },
- })
-
- const { host } = define({
- setup() {
- const n1 = createComponent(Child, null, null, true)
- applyVShow(n1, () => visible.value)
- return n1
- },
- }).render()
-
- expect(host.innerHTML).toBe('<div>child</div><!--if-->')
-
- visible.value = !visible.value
- await nextTick()
- expect(host.innerHTML).toBe(
- '<div style="display: none;">child</div><!--if-->',
- )
-
- childIf.value = !childIf.value
- await nextTick()
- expect(host.innerHTML).toBe(
- '<span style="display: none;">child</span><!--if-->',
- )
-
- visible.value = !visible.value
- await nextTick()
- expect(host.innerHTML).toBe('<span style="">child</span><!--if-->')
- })
-})
+++ /dev/null
-import { effectScope } from '@vue/reactivity'
-import {
- delegate,
- delegateEvents,
- on,
- renderEffect,
- setDynamicEvents,
-} from '../../src'
-
-describe('dom event', () => {
- delegateEvents('click')
-
- test('on', () => {
- const el = document.createElement('div')
- const handler = vi.fn()
- on(el, 'click', handler)
- el.click()
- expect(handler).toHaveBeenCalled()
- })
-
- test('delegate with direct attachment', () => {
- const el = document.createElement('div')
- document.body.appendChild(el)
- const handler = vi.fn()
- ;(el as any).$evtclick = handler
- el.click()
- expect(handler).toHaveBeenCalled()
- })
-
- test('delegate', () => {
- const el = document.createElement('div')
- document.body.appendChild(el)
- const handler = vi.fn()
- delegate(el, 'click', handler)
- el.click()
- expect(handler).toHaveBeenCalled()
- })
-
- test('delegate with stopPropagation', () => {
- const parent = document.createElement('div')
- const child = document.createElement('div')
- parent.appendChild(child)
- document.body.appendChild(parent)
- const parentHandler = vi.fn()
- delegate(parent, 'click', parentHandler)
- const childHandler = vi.fn(e => e.stopPropagation())
- delegate(child, 'click', childHandler)
- child.click()
- expect(parentHandler).not.toHaveBeenCalled()
- expect(childHandler).toHaveBeenCalled()
- })
-
- test('delegate with stopImmediatePropagation', () => {
- const parent = document.createElement('div')
- const child = document.createElement('div')
- parent.appendChild(child)
- document.body.appendChild(parent)
- const parentHandler = vi.fn()
- delegate(parent, 'click', parentHandler)
- const childHandler = vi.fn(e => e.stopImmediatePropagation())
- delegate(child, 'click', childHandler)
- child.click()
- expect(parentHandler).not.toHaveBeenCalled()
- expect(childHandler).toHaveBeenCalled()
- })
-
- test('delegate with multiple handlers', () => {
- const el = document.createElement('div')
- document.body.appendChild(el)
- const handler1 = vi.fn()
- const handler2 = vi.fn()
- delegate(el, 'click', handler1)
- delegate(el, 'click', handler2)
- el.click()
- expect(handler1).toHaveBeenCalled()
- expect(handler2).toHaveBeenCalled()
- })
-
- test('delegate with multiple handlers + stopImmediatePropagation', () => {
- const el = document.createElement('div')
- document.body.appendChild(el)
- const handler1 = vi.fn(e => e.stopImmediatePropagation())
- const handler2 = vi.fn()
- delegate(el, 'click', handler1)
- delegate(el, 'click', handler2)
- el.click()
- expect(handler1).toHaveBeenCalled()
- expect(handler2).not.toHaveBeenCalled()
- })
-
- test('setDynamicEvents', () => {
- const el = document.createElement('div')
- const handler = vi.fn()
- const scope = effectScope()
- scope.run(() => {
- renderEffect(() => {
- setDynamicEvents(el, {
- click: handler,
- })
- })
- })
- el.click()
- expect(handler).toHaveBeenCalled()
- scope.stop()
- })
-})
+++ /dev/null
-import { NOOP } from '@vue/shared'
-import {
- setDynamicProp as _setDynamicProp,
- setAttr,
- setClass,
- setDynamicProps,
- setElementText,
- setHtml,
- setProp,
- setText,
- setValue,
-} from '../../src/dom/prop'
-import { setStyle } from '../../src/dom/prop'
-import { VaporComponentInstance } from '../../src/component'
-import {
- currentInstance,
- ref,
- simpleSetCurrentInstance,
-} from '@vue/runtime-dom'
-
-let removeComponentInstance = NOOP
-beforeEach(() => {
- const instance = new VaporComponentInstance({}, {}, null)
- const prev = currentInstance
- simpleSetCurrentInstance(instance)
- removeComponentInstance = () => {
- simpleSetCurrentInstance(prev)
- }
-})
-afterEach(() => {
- removeComponentInstance()
-})
-
-describe('patchProp', () => {
- describe('setClass', () => {
- test('should set class', () => {
- const el = document.createElement('div')
- setClass(el, 'foo')
- expect(el.className).toBe('foo')
- setClass(el, ['bar', 'baz'])
- expect(el.className).toBe('bar baz')
- setClass(el, { a: true, b: false })
- expect(el.className).toBe('a')
- })
- })
-
- describe('setStyle', () => {
- test('should set style', () => {
- const el = document.createElement('div')
- setStyle(el, 'color: red')
- expect(el.style.cssText).toBe('color: red;')
- })
-
- test('should work with camelCase', () => {
- const el = document.createElement('div')
- setStyle(el, { fontSize: '12px' })
- expect(el.style.cssText).toBe('font-size: 12px;')
- })
-
- test('shoud set style with object and array property', () => {
- const el = document.createElement('div')
- setStyle(el, { color: 'red' })
- expect(el.style.cssText).toBe('color: red;')
- setStyle(el, [{ color: 'blue' }, { fontSize: '12px' }])
- expect(el.style.cssText).toBe('color: blue; font-size: 12px;')
- })
-
- test('should remove if falsy value', () => {
- const el = document.createElement('div')
- setStyle(el, { color: undefined, borderRadius: null })
- expect(el.style.cssText).toBe('')
- setStyle(el, { color: 'red' })
- expect(el.style.cssText).toBe('color: red;')
- setStyle(el, { color: undefined, borderRadius: null })
- expect(el.style.cssText).toBe('')
- })
-
- test('should work with !important', () => {
- const el = document.createElement('div')
- setStyle(el, { color: 'red !important' })
- expect(el.style.cssText).toBe('color: red !important;')
- })
-
- test('should work with camelCase and !important', () => {
- const el = document.createElement('div')
- setStyle(el, { fontSize: '12px !important' })
- expect(el.style.cssText).toBe('font-size: 12px !important;')
- })
-
- test('should work with multiple entries', () => {
- const el = document.createElement('div')
- setStyle(el, { color: 'red', marginRight: '10px' })
- expect(el.style.getPropertyValue('color')).toBe('red')
- expect(el.style.getPropertyValue('margin-right')).toBe('10px')
- })
-
- test('should patch with falsy style value', () => {
- const el = document.createElement('div')
- setStyle(el, { width: '100px' })
- expect(el.style.cssText).toBe('width: 100px;')
- setStyle(el, { width: 0 })
- expect(el.style.cssText).toBe('width: 0px;')
- })
-
- test('should remove style attribute on falsy value', () => {
- const el = document.createElement('div')
- setStyle(el, { width: '100px' })
- expect(el.style.cssText).toBe('width: 100px;')
- setStyle(el, { width: undefined })
- expect(el.style.cssText).toBe('')
-
- setStyle(el, { width: '100px' })
- expect(el.style.cssText).toBe('width: 100px;')
- setStyle(el, null)
- expect(el.hasAttribute('style')).toBe(false)
- expect(el.style.cssText).toBe('')
- })
-
- test('should warn for trailing semicolons', () => {
- const el = document.createElement('div')
- setStyle(el, { color: 'red;' })
- expect(
- `Unexpected semicolon at the end of 'color' style value: 'red;'`,
- ).toHaveBeenWarned()
-
- setStyle(el, { '--custom': '100; ' })
- expect(
- `Unexpected semicolon at the end of '--custom' style value: '100; '`,
- ).toHaveBeenWarned()
- })
-
- test('should not warn for trailing semicolons', () => {
- const el = document.createElement('div')
- setStyle(el, { '--custom': '100\\;' })
- expect(el.style.getPropertyValue('--custom')).toBe('100\\;')
- })
-
- test('should work with shorthand properties', () => {
- const el = document.createElement('div')
- setStyle(el, {
- borderBottom: '1px solid red',
- border: '1px solid green',
- })
- expect(el.style.border).toBe('1px solid green')
- expect(el.style.borderBottom).toBe('1px solid green')
- })
-
- // JSDOM doesn't support custom properties on style object so we have to
- // mock it here.
- function mockElementWithStyle() {
- const store: any = {}
- return {
- style: {
- display: '',
- WebkitTransition: '',
- setProperty(key: string, val: string) {
- store[key] = val
- },
- getPropertyValue(key: string) {
- return store[key]
- },
- },
- }
- }
-
- test('should work with css custom properties', () => {
- const el = mockElementWithStyle()
- setStyle(el as any, { '--theme': 'red' })
- expect(el.style.getPropertyValue('--theme')).toBe('red')
- })
-
- test('should auto vendor prefixing', () => {
- const el = mockElementWithStyle()
- setStyle(el as any, { transition: 'all 1s' })
- expect(el.style.WebkitTransition).toBe('all 1s')
- })
-
- test('should work with multiple values', () => {
- const el = mockElementWithStyle()
- setStyle(el as any, {
- display: ['-webkit-box', '-ms-flexbox', 'flex'],
- })
- expect(el.style.display).toBe('flex')
- })
- })
-
- describe.todo('setClassIncremental', () => {})
-
- describe.todo('setStyleIncremental', () => {})
-
- describe('setAttr', () => {
- test('should set attribute', () => {
- const el = document.createElement('div')
- setAttr(el, 'id', 'foo')
- expect(el.getAttribute('id')).toBe('foo')
- setAttr(el, 'name', 'bar')
- expect(el.getAttribute('name')).toBe('bar')
- })
-
- test('should remove attribute', () => {
- const el = document.createElement('div')
- setAttr(el, 'id', 'foo')
- setAttr(el, 'data', 'bar')
- expect(el.getAttribute('id')).toBe('foo')
- expect(el.getAttribute('data')).toBe('bar')
- setAttr(el, 'id', null)
- expect(el.getAttribute('id')).toBeNull()
- setAttr(el, 'data', undefined)
- expect(el.getAttribute('data')).toBeNull()
- })
-
- test('should set boolean attribute to string', () => {
- const el = document.createElement('div')
- setAttr(el, 'disabled', true)
- expect(el.getAttribute('disabled')).toBe('true')
- setAttr(el, 'disabled', false)
- expect(el.getAttribute('disabled')).toBe('false')
- })
- })
-
- describe('setValue', () => {
- test('should set value prop', () => {
- const el = document.createElement('input')
- setValue(el, 'foo')
- expect(el.value).toBe('foo')
- setValue(el, null)
- expect(el.value).toBe('')
- expect(el.getAttribute('value')).toBe(null)
- const obj = {}
- setValue(el, obj)
- expect(el.value).toBe(obj.toString())
- expect((el as any)._value).toBe(obj)
-
- const option = document.createElement('option')
- setElementText(option, 'foo')
- expect(option.value).toBe('foo')
- expect(option.getAttribute('value')).toBe(null)
-
- setValue(option, 'bar')
- expect(option.textContent).toBe('foo')
- expect(option.value).toBe('bar')
- expect(option.getAttribute('value')).toBe('bar')
- })
- })
-
- describe('setDOMProp', () => {
- test('should be boolean prop', () => {
- const el = document.createElement('select')
- // In vapor static attrs are part of the template and this never happens
- // setDOMProp(el, 'multiple', '')
- // expect(el.multiple).toBe(true)
- setProp(el, 'multiple', null)
- expect(el.multiple).toBe(false)
- setProp(el, 'multiple', true)
- expect(el.multiple).toBe(true)
- setProp(el, 'multiple', 0)
- expect(el.multiple).toBe(false)
- setProp(el, 'multiple', '0')
- expect(el.multiple).toBe(true)
- setProp(el, 'multiple', false)
- expect(el.multiple).toBe(false)
- setProp(el, 'multiple', 1)
- expect(el.multiple).toBe(true)
- setProp(el, 'multiple', undefined)
- expect(el.multiple).toBe(false)
- })
-
- test('should remove attribute when value is falsy', () => {
- const el = document.createElement('div')
- el.setAttribute('id', '')
- setProp(el, 'id', null)
- expect(el.hasAttribute('id')).toBe(false)
-
- el.setAttribute('id', '')
- setProp(el, 'id', undefined)
- expect(el.hasAttribute('id')).toBe(false)
-
- setProp(el, 'id', '')
- expect(el.hasAttribute('id')).toBe(false)
-
- const img = document.createElement('img')
- setProp(img, 'width', 0)
- expect(img.hasAttribute('width')).toBe(false) // skipped
-
- setProp(img, 'width', null)
- expect(img.hasAttribute('width')).toBe(false)
- setProp(img, 'width', 1)
- expect(img.hasAttribute('width')).toBe(true)
-
- setProp(img, 'width', undefined)
- expect(img.hasAttribute('width')).toBe(false)
- setProp(img, 'width', 1)
- expect(img.hasAttribute('width')).toBe(true)
- })
-
- test('should warn when set prop error', () => {
- const el = document.createElement('div')
- Object.defineProperty(el, 'someProp', {
- set() {
- throw new TypeError('Invalid type')
- },
- })
- setProp(el, 'someProp', 'foo')
-
- expect(
- `Failed setting prop "someProp" on <div>: value foo is invalid.`,
- ).toHaveBeenWarnedLast()
- })
- })
-
- describe('setDynamicProp', () => {
- const element = document.createElement('div')
- function setDynamicProp(
- key: string,
- value: any,
- el = element.cloneNode(true) as HTMLElement,
- ) {
- _setDynamicProp(el, key, value)
- return el
- }
-
- test('should be able to set id', () => {
- let res = setDynamicProp('id', 'bar')
- expect(res.id).toBe('bar')
- })
-
- test('should be able to set class', () => {
- let res = setDynamicProp('class', 'foo')
- expect(res.className).toBe('foo')
- })
-
- test('should be able to set style', () => {
- let res = setDynamicProp('style', 'color: red')
- expect(res.style.cssText).toBe('color: red;')
- })
-
- test('should be able to set .prop', () => {
- let res = setDynamicProp('.foo', 'bar')
- expect((res as any)['foo']).toBe('bar')
- expect(res.getAttribute('foo')).toBeNull()
- })
-
- test('should be able to set ^attr', () => {
- let res = setDynamicProp('^foo', 'bar')
- expect(res.getAttribute('foo')).toBe('bar')
- expect((res as any)['foo']).toBeUndefined()
- })
-
- test('should be able to set boolean prop', () => {
- let res = setDynamicProp(
- 'disabled',
- true,
- document.createElement('button'),
- )
- expect(res.getAttribute('disabled')).toBe('')
- setDynamicProp('disabled', false, res)
- expect(res.getAttribute('disabled')).toBeNull()
- })
-
- // The function shouldSetAsProp has complete tests elsewhere,
- // so here we only do a simple test.
- test('should be able to set innerHTML and textContent', () => {
- let res = setDynamicProp('innerHTML', '<p>bar</p>')
- expect(res.innerHTML).toBe('<p>bar</p>')
- res = setDynamicProp('textContent', 'foo')
- expect(res.textContent).toBe('foo')
- })
-
- test.todo('should be able to set something on SVG')
- })
-
- describe('setDynamicProps', () => {
- test('basic set dynamic props', () => {
- const el = document.createElement('div')
- setDynamicProps(el, [{ foo: 'val' }, { bar: 'val' }])
- expect(el.getAttribute('foo')).toBe('val')
- expect(el.getAttribute('bar')).toBe('val')
- })
-
- test('should merge props', () => {
- const el = document.createElement('div')
- setDynamicProps(el, [{ foo: 'val' }, { foo: 'newVal' }])
- expect(el.getAttribute('foo')).toBe('newVal')
- })
-
- test('should reset old props', () => {
- const el = document.createElement('div')
- setDynamicProps(el, [{ foo: 'val' }])
- expect(el.attributes.length).toBe(1)
- expect(el.getAttribute('foo')).toBe('val')
-
- setDynamicProps(el, [{ bar: 'val' }])
- expect(el.attributes.length).toBe(1)
- expect(el.getAttribute('bar')).toBe('val')
- expect(el.getAttribute('foo')).toBeNull()
- })
-
- test('should reset old modifier props', () => {
- const el = document.createElement('div')
-
- setDynamicProps(el, [{ ['.foo']: 'val' }])
- expect((el as any).foo).toBe('val')
-
- setDynamicProps(el, [{ ['.bar']: 'val' }])
- expect((el as any).bar).toBe('val')
- expect((el as any).foo).toBe('')
-
- setDynamicProps(el, [{ ['^foo']: 'val' }])
- expect(el.attributes.length).toBe(1)
- expect(el.getAttribute('foo')).toBe('val')
-
- setDynamicProps(el, [{ ['^bar']: 'val' }])
- expect(el.attributes.length).toBe(1)
- expect(el.getAttribute('bar')).toBe('val')
- expect(el.getAttribute('foo')).toBeNull()
- })
- })
-
- describe('setText', () => {
- test('should set nodeValue', () => {
- const el = document.createTextNode('foo')
- setText(el, '')
- expect(el.textContent).toBe('')
- setText(el, 'foo')
- expect(el.textContent).toBe('foo')
- setText(el, 'bar')
- expect(el.textContent).toBe('bar')
- })
- })
-
- describe('setElementText', () => {
- test('should set textContent w/ toDisplayString', () => {
- const el = document.createElement('div')
- setElementText(el, null)
- expect(el.textContent).toBe('')
- setElementText(el, { a: 1 })
- expect(el.textContent).toBe(JSON.stringify({ a: 1 }, null, 2))
- setElementText(el, ref('bar'))
- expect(el.textContent).toBe('bar')
- })
- })
-
- describe('setHtml', () => {
- test('should set innerHTML', () => {
- const el = document.createElement('div')
- setHtml(el, null)
- expect(el.innerHTML).toBe('')
- setHtml(el, '<p>foo</p>')
- expect(el.innerHTML).toBe('<p>foo</p>')
- setHtml(el, '<p>bar</p>')
- expect(el.innerHTML).toBe('<p>bar</p>')
- })
- })
-})
+++ /dev/null
-import { template } from '../../src/dom/template'
-import { child, next, nthChild } from '../../src/dom/node'
-
-describe('api: template', () => {
- test('create element', () => {
- const t = template('<div>')
- const root = t()
- expect(root).toBeInstanceOf(HTMLDivElement)
-
- const root2 = t()
- expect(root2).toBeInstanceOf(HTMLDivElement)
- expect(root2).not.toBe(root)
- })
-
- test('create root element', () => {
- const t = template('<div>', true)
- const root = t()
- expect(root.$root).toBe(true)
- })
-
- test('nthChild', () => {
- const t = template('<div><span><b>nested</b></span><p></p></div>')
- const root = t()
- const span = nthChild(root, 0)
- const b = nthChild(span, 0)
- const p = nthChild(root, 1)
- expect(span).toBe(root.firstChild)
- expect(b).toBe(root.firstChild!.firstChild)
- expect(p).toBe(root.firstChild!.nextSibling)
- })
-
- test('next', () => {
- const t = template('<div><span></span><b></b><p></p></div>')
- const root = t()
- const span = child(root as ParentNode)
- const b = next(span)
-
- expect(span).toBe(root.childNodes[0])
- expect(b).toBe(root.childNodes[1])
- expect(nthChild(root, 2)).toBe(root.childNodes[2])
- expect(next(b)).toBe(root.childNodes[2])
- })
-})
+++ /dev/null
-import type { NodeRef } from '../../src/apiTemplateRef'
-import {
- child,
- createComponent,
- createDynamicComponent,
- createFor,
- createIf,
- createSlot,
- createTemplateRefSetter,
- defineVaporComponent,
- insert,
- renderEffect,
- template,
-} from '../../src'
-import { makeRender } from '../_utils'
-import {
- type ShallowRef,
- currentInstance,
- nextTick,
- reactive,
- ref,
- useTemplateRef,
- watchEffect,
-} from '@vue/runtime-dom'
-import { setElementText, setText } from '../../src/dom/prop'
-import type { VaporComponent } from '../../src/component'
-
-const define = makeRender()
-
-describe('api: template ref', () => {
- test('string ref mount', () => {
- const t0 = template('<div ref="refKey"></div>')
- const el = ref(null)
- const { render } = define({
- setup() {
- return {
- refKey: el,
- }
- },
- render() {
- const n0 = t0()
- createTemplateRefSetter()(n0 as Element, 'refKey')
- return n0
- },
- })
-
- const { host } = render()
- expect(el.value).toBe(host.children[0])
- })
-
- it('string ref update', async () => {
- const t0 = template('<div></div>')
- const fooEl = ref(null)
- const barEl = ref(null)
- const refKey = ref('foo')
-
- const { render } = define({
- setup() {
- return {
- foo: fooEl,
- bar: barEl,
- }
- },
- render() {
- const n0 = t0()
- let r0: NodeRef | undefined
- renderEffect(() => {
- r0 = createTemplateRefSetter()(n0 as Element, refKey.value, r0)
- })
- return n0
- },
- })
- const { host } = render()
- expect(fooEl.value).toBe(host.children[0])
- expect(barEl.value).toBe(null)
-
- refKey.value = 'bar'
- await nextTick()
- expect(barEl.value).toBe(host.children[0])
- expect(fooEl.value).toBe(null)
- })
-
- it('string ref unmount', async () => {
- const t0 = template('<div></div>')
- const el = ref(null)
- const toggle = ref(true)
-
- const { render } = define({
- setup() {
- return {
- refKey: el,
- }
- },
- render() {
- const setRef = createTemplateRefSetter()
- const n0 = createIf(
- () => toggle.value,
- () => {
- const n1 = t0()
- setRef(n1 as Element, 'refKey')
- return n1
- },
- )
- return n0
- },
- })
- const { host } = render()
- expect(el.value).toBe(host.children[0])
-
- toggle.value = false
- await nextTick()
- expect(el.value).toBe(null)
- })
-
- it('function ref mount', () => {
- const fn = vi.fn()
- const t0 = template('<div></div>')
- const { render } = define({
- render() {
- const n0 = t0()
- createTemplateRefSetter()(n0 as Element, fn)
- return n0
- },
- })
-
- const { host } = render()
- expect(fn.mock.calls[0][0]).toBe(host.children[0])
- })
-
- it('function ref update', async () => {
- const fn1 = vi.fn()
- const fn2 = vi.fn()
- const fn = ref(fn1)
-
- const t0 = template('<div></div>')
- const { render } = define({
- render() {
- const n0 = t0()
- let r0: NodeRef | undefined
- renderEffect(() => {
- r0 = createTemplateRefSetter()(n0 as Element, fn.value, r0)
- })
- return n0
- },
- })
-
- const { host } = render()
-
- expect(fn1.mock.calls).toHaveLength(1)
- expect(fn1.mock.calls[0][0]).toBe(host.children[0])
- expect(fn2.mock.calls).toHaveLength(0)
-
- fn.value = fn2
- await nextTick()
- expect(fn1.mock.calls).toHaveLength(1)
- expect(fn2.mock.calls).toHaveLength(1)
- expect(fn2.mock.calls[0][0]).toBe(host.children[0])
- })
-
- it('function ref unmount', async () => {
- const fn = vi.fn()
- const toggle = ref(true)
-
- const t0 = template('<div></div>')
- const { render } = define({
- render() {
- const n0 = createIf(
- () => toggle.value,
- () => {
- const n1 = t0()
- createTemplateRefSetter()(n1 as Element, fn)
- return n1
- },
- )
- return n0
- },
- })
- const { host } = render()
- expect(fn.mock.calls[0][0]).toBe(host.children[0])
- toggle.value = false
- await nextTick()
- expect(fn.mock.calls[1][0]).toBe(undefined)
- })
-
- test('useTemplateRef mount', () => {
- const t0 = template('<div ref="refKey"></div>')
- let r
- let n
- const { render } = define({
- setup() {
- r = useTemplateRef('foo')
- n = t0()
- createTemplateRefSetter()(n as Element, 'foo')
- return n
- },
- })
-
- const { host } = render()
- expect(r!.value).toBe(host.children[0])
- })
-
- test('useTemplateRef update', async () => {
- const t0 = template('<div></div>')
- let fooEl: ShallowRef
- let barEl: ShallowRef
- const refKey = ref('foo')
-
- const { render } = define({
- setup() {
- return {
- foo: fooEl,
- bar: barEl,
- }
- },
- render() {
- fooEl = useTemplateRef('foo')
- barEl = useTemplateRef('bar')
- const n0 = t0()
- let r0: NodeRef | undefined
- renderEffect(() => {
- r0 = createTemplateRefSetter()(n0 as Element, refKey.value, r0)
- })
- return n0
- },
- })
- const { host } = render()
- expect(fooEl!.value).toBe(host.children[0])
- expect(barEl!.value).toBe(null)
-
- refKey.value = 'bar'
- await nextTick()
- expect(barEl!.value).toBe(host.children[0])
- expect(fooEl!.value).toBe(null)
- })
-
- it('should work with direct reactive property', () => {
- const state = reactive({
- refKey: null,
- })
-
- const t0 = template('<div></div>')
- const { render } = define({
- setup() {
- return state
- },
- render() {
- const n0 = t0()
- createTemplateRefSetter()(n0 as Element, 'refKey')
- return n0
- },
- })
- const { host } = render()
- expect(state.refKey).toBe(host.children[0])
- })
-
- test('multiple root refs', () => {
- const refKey1 = ref(null)
- const refKey2 = ref(null)
- const refKey3 = ref(null)
-
- const t0 = template('<div></div>')
- const t1 = template('<div></div>')
- const t2 = template('<div></div>')
- const { render } = define({
- setup() {
- return {
- refKey1,
- refKey2,
- refKey3,
- }
- },
- render() {
- const n0 = t0()
- const n1 = t1()
- const n2 = t2()
- createTemplateRefSetter()(n0 as Element, 'refKey1')
- createTemplateRefSetter()(n1 as Element, 'refKey2')
- createTemplateRefSetter()(n2 as Element, 'refKey3')
- return [n0, n1, n2]
- },
- })
- const { host } = render()
- // Note: toBe Condition is different from core test case
- // Core test case is expecting refKey1.value to be host.children[1]
- expect(refKey1.value).toBe(host.children[0])
- expect(refKey2.value).toBe(host.children[1])
- expect(refKey3.value).toBe(host.children[2])
- })
-
- // #1505
- test('reactive template ref in the same template', async () => {
- const t0 = template('<div id="foo"></div>')
- const el = ref<HTMLElement>()
- const { render } = define({
- render() {
- const n0 = t0()
- createTemplateRefSetter()(n0 as Element, el)
- renderEffect(() => {
- setElementText(n0, el.value && el.value.getAttribute('id'))
- })
- return n0
- },
- })
-
- const { host } = render()
- // ref not ready on first render, but should queue an update immediately
- expect(host.innerHTML).toBe(`<div id="foo"></div>`)
- await nextTick()
- // ref should be updated
- expect(host.innerHTML).toBe(`<div id="foo">foo</div>`)
- })
-
- // #1834
- test('exchange refs', async () => {
- const refToggle = ref(false)
- const spy = vi.fn()
-
- const t0 = template('<p></p>')
- const t1 = template('<i></i>')
- const { render } = define({
- render() {
- const instance = currentInstance!
- const n0 = t0()
- const n1 = t1()
- let r0: NodeRef | undefined
- let r1: NodeRef | undefined
- renderEffect(() => {
- r0 = createTemplateRefSetter()(
- n0 as Element,
- refToggle.value ? 'foo' : 'bar',
- r0,
- )
- })
- renderEffect(() => {
- r1 = createTemplateRefSetter()(
- n1 as Element,
- refToggle.value ? 'bar' : 'foo',
- r1,
- )
- })
- watchEffect(
- () => {
- refToggle.value
- spy(
- (instance.refs.foo as HTMLElement).tagName,
- (instance.refs.bar as HTMLElement).tagName,
- )
- },
- {
- flush: 'post',
- },
- )
- return [n0, n1]
- },
- })
-
- render()
-
- expect(spy.mock.calls[0][0]).toBe('I')
- expect(spy.mock.calls[0][1]).toBe('P')
- refToggle.value = true
- await nextTick()
- expect(spy.mock.calls[1][0]).toBe('P')
- expect(spy.mock.calls[1][1]).toBe('I')
- })
-
- // #1789
- test('toggle the same ref to different elements', async () => {
- const refToggle = ref(false)
- const spy = vi.fn()
-
- const t0 = template('<p></p>')
- const t1 = template('<i></i>')
- const { render } = define({
- render() {
- const instance = currentInstance!
- const setRef = createTemplateRefSetter()
- const n0 = createIf(
- () => refToggle.value,
- () => {
- const n1 = t0()
- setRef(n1 as Element, 'foo')
- return n1
- },
- () => {
- const n1 = t1()
- setRef(n1 as Element, 'foo')
- return n1
- },
- )
- watchEffect(
- () => {
- refToggle.value
- spy((instance.refs.foo as HTMLElement).tagName)
- },
- {
- flush: 'post',
- },
- )
- return [n0]
- },
- })
-
- render()
-
- expect(spy.mock.calls[0][0]).toBe('I')
- refToggle.value = true
- await nextTick()
- expect(spy.mock.calls[1][0]).toBe('P')
- })
-
- // compiled output of v-for + template ref
- test('ref in v-for', async () => {
- const show = ref(true)
- const list = reactive([1, 2, 3])
- const listRefs = ref([])
- const mapRefs = () => listRefs.value.map((n: HTMLElement) => n.innerHTML)
-
- const t0 = template('<ul></ul>')
- const t1 = template('<li></li>')
- const { render } = define({
- render() {
- const n0 = createIf(
- () => show.value,
- () => {
- const n1 = t0()
- const n2 = createFor(
- () => list,
- item => {
- const n1 = t1()
- createTemplateRefSetter()(
- n1 as Element,
- listRefs,
- undefined,
- true,
- )
- renderEffect(() => {
- setElementText(n1, item)
- })
- return n1
- },
- )
- insert(n2, n1 as ParentNode)
- return n1
- },
- )
- return n0
- },
- })
- render()
-
- expect(mapRefs()).toMatchObject(['1', '2', '3'])
-
- list.push(4)
- await nextTick()
- expect(mapRefs()).toMatchObject(['1', '2', '3', '4'])
-
- list.shift()
- await nextTick()
- expect(mapRefs()).toMatchObject(['2', '3', '4'])
-
- show.value = !show.value
- await nextTick()
-
- expect(mapRefs()).toMatchObject([])
-
- show.value = !show.value
- await nextTick()
- expect(mapRefs()).toMatchObject(['2', '3', '4'])
- })
-
- test('named ref in v-for', async () => {
- const show = ref(true)
- const list = reactive([1, 2, 3])
- const listRefs = ref([])
- const mapRefs = () => listRefs.value.map((n: HTMLElement) => n.innerHTML)
-
- const t0 = template('<ul></ul>')
- const t1 = template('<li></li>')
- const { render } = define({
- setup() {
- return { listRefs }
- },
- render() {
- const n0 = createIf(
- () => show.value,
- () => {
- const n1 = t0()
- const n2 = createFor(
- () => list,
- item => {
- const n1 = t1()
- createTemplateRefSetter()(
- n1 as Element,
- 'listRefs',
- undefined,
- true,
- )
- renderEffect(() => {
- setElementText(n1, item)
- })
- return n1
- },
- )
- insert(n2, n1 as ParentNode)
- return n1
- },
- )
- return n0
- },
- })
- render()
-
- expect(mapRefs()).toMatchObject(['1', '2', '3'])
-
- list.push(4)
- await nextTick()
- expect(mapRefs()).toMatchObject(['1', '2', '3', '4'])
-
- list.shift()
- await nextTick()
- expect(mapRefs()).toMatchObject(['2', '3', '4'])
-
- show.value = !show.value
- await nextTick()
-
- expect(mapRefs()).toMatchObject([])
-
- show.value = !show.value
- await nextTick()
- expect(mapRefs()).toMatchObject(['2', '3', '4'])
- })
-
- // #6697 v-for ref behaves differently under production and development
- test('named ref in v-for , should be responsive when rendering', async () => {
- const list = ref([1, 2, 3])
- const listRefs = ref([])
-
- const t0 = template('<div><div></div><ul></ul></div>')
- const t1 = template('<li></li>')
- const { render } = define({
- setup() {
- return { listRefs }
- },
- render() {
- const n0 = t0()
- const n1 = n0.firstChild
- const n2 = n1!.nextSibling!
- const n3 = createFor(
- () => list.value,
- item => {
- const n4 = t1()
- createTemplateRefSetter()(
- n4 as Element,
- 'listRefs',
- undefined,
- true,
- )
- renderEffect(() => {
- setElementText(n4, item)
- })
- return n4
- },
- )
- insert(n3, n2 as unknown as ParentNode)
- renderEffect(() => {
- setElementText(n1!, String(listRefs.value))
- })
- return n0
- },
- })
-
- const { host } = render()
-
- await nextTick()
- expect(String(listRefs.value)).toBe(
- '[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement]',
- )
- expect(host.innerHTML).toBe(
- '<div><div>[object HTMLLIElement],[object HTMLLIElement],[object HTMLLIElement]</div><ul><li>1</li><li>2</li><li>3</li><!--for--></ul></div>',
- )
-
- list.value.splice(0, 1)
- await nextTick()
- expect(String(listRefs.value)).toBe(
- '[object HTMLLIElement],[object HTMLLIElement]',
- )
- expect(host.innerHTML).toBe(
- '<div><div>[object HTMLLIElement],[object HTMLLIElement]</div><ul><li>2</li><li>3</li><!--for--></ul></div>',
- )
- })
-
- test('string ref inside slots', () => {
- const { component: Child } = define({
- setup() {
- return createSlot('default')
- },
- })
-
- const r = ref()
- let n
-
- const { render } = define({
- setup() {
- return {
- foo: r,
- }
- },
- render() {
- const setRef = createTemplateRefSetter()
- const n0 = createComponent(Child, null, {
- default: () => {
- n = document.createElement('div')
- setRef(n, 'foo')
- return n
- },
- })
- return n0
- },
- })
-
- render()
- expect(r.value).toBe(n)
- })
-
- test('inline ref inside slots', () => {
- const { component: Child } = define({
- setup() {
- return createSlot('default')
- },
- })
-
- const r = ref()
- let n
-
- const { render } = define({
- setup() {
- const setRef = createTemplateRefSetter()
- const n0 = createComponent(Child, null, {
- default: () => {
- n = document.createElement('div')
- setRef(n, r)
- return n
- },
- })
- return n0
- },
- })
-
- render()
- expect(r.value).toBe(n)
- })
-
- test('useTemplateRef ref inside slots', () => {
- const { component: Child } = define({
- setup() {
- return createSlot('default')
- },
- })
-
- let r: ShallowRef
- let n
-
- const { render } = define({
- setup() {
- r = useTemplateRef('foo')
- const setRef = createTemplateRefSetter()
- const n0 = createComponent(Child, null, {
- default: () => {
- n = document.createElement('div')
- setRef(n, 'foo')
- return n
- },
- })
- return n0
- },
- })
-
- render()
- expect(r!.value).toBe(n)
- })
-
- test('work with dynamic component', async () => {
- const Child = defineVaporComponent({
- setup(_, { expose }) {
- const msg = ref('one')
- expose({ setMsg: (m: string) => (msg.value = m) })
- const n0 = template(`<div> </div>`)() as any
- const x0 = child(n0) as any
- renderEffect(() => setText(x0, msg.value))
- return n0
- },
- })
-
- const views: Record<string, VaporComponent> = { child: Child }
- const view = ref('child')
- const refKey = ref<any>(null)
-
- const { html } = define({
- setup() {
- const setRef = createTemplateRefSetter()
- const n0 = createDynamicComponent(() => views[view.value]) as any
- setRef(n0, refKey)
- return n0
- },
- }).render()
-
- expect(html()).toBe('<div>one</div><!--dynamic-component-->')
- expect(refKey.value).toBeDefined()
-
- refKey.value.setMsg('changed')
- await nextTick()
- expect(html()).toBe('<div>changed</div><!--dynamic-component-->')
- })
-
- // TODO: can not reproduce in Vapor
- // // #2078
- // test('handling multiple merged refs', async () => {
- // const Foo = {
- // render: () => h('div', 'foo'),
- // }
- // const Bar = {
- // render: () => h('div', 'bar'),
- // }
-
- // const viewRef = shallowRef<any>(Foo)
- // const elRef1 = ref()
- // const elRef2 = ref()
-
- // const App = {
- // render() {
- // if (!viewRef.value) {
- // return null
- // }
- // const view = h(viewRef.value, { ref: elRef1 })
- // return h(view, { ref: elRef2 })
- // },
- // }
- // const root = nodeOps.createElement('div')
- // render(h(App), root)
-
- // expect(serializeInner(elRef1.value.$el)).toBe('foo')
- // expect(elRef1.value).toBe(elRef2.value)
-
- // viewRef.value = Bar
- // await nextTick()
- // expect(serializeInner(elRef1.value.$el)).toBe('bar')
- // expect(elRef1.value).toBe(elRef2.value)
-
- // viewRef.value = null
- // await nextTick()
- // expect(elRef1.value).toBeNull()
- // expect(elRef1.value).toBe(elRef2.value)
- // })
-})
+++ /dev/null
-import {
- nextTick,
- onErrorCaptured,
- onMounted,
- ref,
- watch,
- watchEffect,
-} from '@vue/runtime-dom'
-import { createComponent, createTemplateRefSetter, template } from '../src'
-import { makeRender } from './_utils'
-import type { VaporComponent } from '../src/component'
-import type { RefEl } from '../src/apiTemplateRef'
-
-const define = makeRender()
-
-describe('error handling', () => {
- test('propagation', () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp: VaporComponent = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info, 'root')
- return false
- })
-
- return createComponent(Child)
- },
- }
-
- const Child: VaporComponent = {
- name: 'Child',
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info, 'child')
- })
- return createComponent(GrandChild)
- },
- }
-
- const GrandChild: VaporComponent = {
- setup() {
- onMounted(() => {
- throw err
- })
- return []
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledTimes(2)
- expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'root')
- expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child')
- })
-
- test('propagation stoppage', () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp: VaporComponent = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info, 'root')
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child: VaporComponent = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info, 'child')
- return false
- })
- return createComponent(GrandChild)
- },
- }
-
- const GrandChild: VaporComponent = {
- setup() {
- onMounted(() => {
- throw err
- })
- return []
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledTimes(1)
- expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child')
- })
-
- test('async error handling', async () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp: VaporComponent = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child: VaporComponent = {
- setup() {
- onMounted(async () => {
- throw err
- })
- return []
- },
- }
-
- define(Comp).render()
- expect(fn).not.toHaveBeenCalled()
- await new Promise(r => setTimeout(r))
- expect(fn).toHaveBeenCalledWith(err, 'mounted hook')
- })
-
- test('error thrown in onErrorCaptured', () => {
- const err = new Error('foo')
- const err2 = new Error('bar')
- const fn = vi.fn()
-
- const Comp: VaporComponent = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child: VaporComponent = {
- setup() {
- onErrorCaptured(() => {
- throw err2
- })
- return createComponent(GrandChild)
- },
- }
-
- const GrandChild: VaporComponent = {
- setup() {
- onMounted(() => {
- throw err
- })
- return []
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledTimes(2)
- expect(fn).toHaveBeenCalledWith(err, 'mounted hook')
- expect(fn).toHaveBeenCalledWith(err2, 'errorCaptured hook')
- })
-
- test('setup function', () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child = {
- setup() {
- throw err
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledWith(err, 'setup function')
- expect(`returned non-block value`).toHaveBeenWarned()
- })
-
- test('in render function', () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child = {
- render() {
- throw err
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledWith(err, 'render function')
- })
-
- test('in function ref', () => {
- const err = new Error('foo')
- const ref = () => {
- throw err
- }
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child = {
- render() {
- const el = template('<div>')()
- const setRef = createTemplateRefSetter()
- setRef(el as RefEl, ref)
- return el
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledWith(err, 'ref function')
- })
-
- test('in effect', () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp: VaporComponent = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child: VaporComponent = {
- setup() {
- watchEffect(() => {
- throw err
- })
- return []
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledWith(err, 'watcher callback')
- })
-
- test('in watch getter', () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child: VaporComponent = {
- setup() {
- watch(
- () => {
- throw err
- },
- () => {},
- )
- return []
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledWith(err, 'watcher getter')
- })
-
- test('in watch callback', async () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const count = ref(0)
- const Child: VaporComponent = {
- setup() {
- watch(
- () => count.value,
- () => {
- throw err
- },
- )
- return []
- },
- }
-
- define(Comp).render()
-
- count.value++
- await nextTick()
- expect(fn).toHaveBeenCalledWith(err, 'watcher callback')
- })
-
- test('in effect cleanup', async () => {
- const err = new Error('foo')
- const count = ref(0)
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child)
- },
- }
-
- const Child: VaporComponent = {
- setup() {
- watchEffect(onCleanup => {
- count.value
- onCleanup(() => {
- throw err
- })
- })
- return []
- },
- }
-
- define(Comp).render()
-
- count.value++
- await nextTick()
- expect(fn).toHaveBeenCalledWith(err, 'watcher cleanup function')
- })
-
- test('in component event handler via emit', () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child, {
- onFoo: () => () => {
- throw err
- },
- })
- },
- }
-
- const Child: VaporComponent = {
- setup(props: any, { emit }: any) {
- emit('foo')
- return []
- },
- }
-
- define(Comp).render()
- expect(fn).toHaveBeenCalledWith(err, 'component event handler')
- })
-
- test('in component event handler via emit (async)', async () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child, {
- onFoo: () => async () => {
- throw err
- },
- })
- },
- }
-
- const Child: VaporComponent = {
- props: ['onFoo'],
- setup(props: any, { emit }: any) {
- emit('foo')
- return []
- },
- }
-
- define(Comp).render()
- await nextTick()
- expect(fn).toHaveBeenCalledWith(err, 'component event handler')
- })
-
- test('in component event handler via emit (async + array)', async () => {
- const err = new Error('foo')
- const fn = vi.fn()
-
- const res: Promise<any>[] = []
- const createAsyncHandler = (p: Promise<any>) => () => {
- res.push(p)
- return p
- }
-
- const handlers = [
- createAsyncHandler(Promise.reject(err)),
- createAsyncHandler(Promise.resolve(1)),
- ]
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- return false
- })
- return createComponent(Child, {
- onFoo: () => handlers,
- })
- },
- }
-
- const Child: VaporComponent = {
- setup(props: any, { emit }: any) {
- emit('foo')
- return []
- },
- }
-
- define(Comp).render()
-
- await expect(() => Promise.all(res)).rejects.toThrowError()
- expect(fn).toHaveBeenCalledWith(err, 'component event handler')
- })
-
- it('should warn unhandled', () => {
- const groupCollapsed = vi.spyOn(console, 'groupCollapsed')
- groupCollapsed.mockImplementation(() => {})
- const log = vi.spyOn(console, 'log')
- log.mockImplementation(() => {})
-
- const err = new Error('foo')
- const fn = vi.fn()
-
- const Comp = {
- setup() {
- onErrorCaptured((err, instance, info) => {
- fn(err, info)
- })
- return createComponent(Child)
- },
- }
-
- const Child = {
- setup() {
- throw err
- },
- }
-
- let caughtError
- try {
- define(Comp).render()
- } catch (caught) {
- caughtError = caught
- }
- expect(fn).toHaveBeenCalledWith(err, 'setup function')
- expect(
- `Unhandled error during execution of setup function`,
- ).toHaveBeenWarned()
- expect(caughtError).toBe(err)
-
- groupCollapsed.mockRestore()
- log.mockRestore()
- })
-
- //# 3127
- test.fails('handle error in watch & watchEffect', async () => {
- const error1 = new Error('error1')
- const error2 = new Error('error2')
- const error3 = new Error('error3')
- const error4 = new Error('error4')
- const handler = vi.fn()
-
- const app = define({
- setup() {
- const count = ref(1)
- watch(
- count,
- () => {
- throw error1
- },
- { immediate: true },
- )
- watch(
- count,
- async () => {
- throw error2
- },
- { immediate: true },
- )
- watchEffect(() => {
- throw error3
- })
- watchEffect(async () => {
- throw error4
- })
- return []
- },
- }).create()
-
- app.app.config.errorHandler = handler
- app.mount()
-
- await nextTick()
- expect(handler).toHaveBeenCalledWith(error1, {}, 'watcher callback')
- expect(handler).toHaveBeenCalledWith(error2, {}, 'watcher callback')
- expect(handler).toHaveBeenCalledWith(error3, {}, 'watcher callback')
- expect(handler).toHaveBeenCalledWith(error4, {}, 'watcher callback')
- expect(handler).toHaveBeenCalledTimes(4)
- })
-
- // #9574
- test.fails('should pause tracking in error handler', async () => {
- const error = new Error('error')
- const x = ref(Math.random())
-
- const handler = vi.fn(() => {
- x.value
- x.value = Math.random()
- })
-
- const app = define({
- setup() {
- throw error
- },
- }).create()
-
- app.app.config.errorHandler = handler
- app.mount()
-
- await nextTick()
- expect(handler).toHaveBeenCalledWith(error, {}, 'render function')
- expect(handler).toHaveBeenCalledTimes(1)
- })
-
- // native event handler handling should be tested in respective renderers
-})
+++ /dev/null
-import {
- createFor,
- getDefaultValue,
- getRestElement,
- renderEffect,
-} from '../src'
-import {
- nextTick,
- reactive,
- readonly,
- ref,
- shallowRef,
- triggerRef,
-} from '@vue/runtime-dom'
-import { makeRender } from './_utils'
-
-const define = makeRender()
-
-describe('createFor', () => {
- test('array source', async () => {
- const list = ref([{ name: '1' }, { name: '2' }, { name: '3' }])
- function reverse() {
- list.value = list.value.reverse()
- }
-
- const { host } = define(() => {
- const n1 = createFor(
- () => list.value,
- (item, key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- span.innerHTML = `${key.value}. ${item.value.name}`
-
- // index should be undefined if source is not an object
- expect(index.value).toBe(undefined)
- })
- return span
- },
- item => item.name,
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><!--for-->',
- )
-
- // add
- list.value.push({ name: '4' })
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // move
- reverse()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 4</li><li>1. 3</li><li>2. 2</li><li>3. 1</li><!--for-->',
- )
-
- reverse()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // change
- list.value[0].name = 'a'
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. a</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // remove
- list.value.splice(1, 1)
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. a</li><li>1. 3</li><li>2. 4</li><!--for-->',
- )
-
- // clear
- list.value = []
- await nextTick()
- expect(host.innerHTML).toBe('<!--for-->')
- })
-
- test('number source', async () => {
- const count = ref(3)
-
- const { host } = define(() => {
- const n1 = createFor(
- () => count.value,
- (item, key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- span.innerHTML = `${key.value}. ${item.value}`
-
- // index should be undefined if source is not an object
- expect(index.value).toBe(undefined)
- })
- return span
- },
- item => item.name,
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><!--for-->',
- )
-
- // add
- count.value = 4
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // remove
- count.value = 2
- await nextTick()
- expect(host.innerHTML).toBe('<li>0. 1</li><li>1. 2</li><!--for-->')
-
- // clear
- count.value = 0
- await nextTick()
- expect(host.innerHTML).toBe('<!--for-->')
- })
-
- test('object source', async () => {
- const initial = () => ({ a: 1, b: 2, c: 3 })
- const data = ref<Record<string, number>>(initial())
-
- const { host } = define(() => {
- const n1 = createFor(
- () => data.value,
- (item, key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- span.innerHTML = `${key.value}${index.value}. ${item.value}`
- expect(index.value).not.toBe(undefined)
- })
- return span
- },
- item => {
- return item
- },
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>a0. 1</li><li>b1. 2</li><li>c2. 3</li><!--for-->',
- )
-
- // move
- data.value = {
- c: 3,
- b: 2,
- a: 1,
- }
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>c0. 3</li><li>b1. 2</li><li>a2. 1</li><!--for-->',
- )
-
- // add
- data.value.d = 4
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>c0. 3</li><li>b1. 2</li><li>a2. 1</li><li>d3. 4</li><!--for-->',
- )
-
- // change
- data.value.b = 100
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>c0. 3</li><li>b1. 100</li><li>a2. 1</li><li>d3. 4</li><!--for-->',
- )
-
- // remove
- delete data.value.c
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>b0. 100</li><li>a1. 1</li><li>d2. 4</li><!--for-->',
- )
-
- // clear
- data.value = {}
- await nextTick()
- expect(host.innerHTML).toBe('<!--for-->')
- })
-
- test('de-structured value', async () => {
- const list = ref([{ name: '1' }, { name: '2' }, { name: '3' }])
- function reverse() {
- list.value = list.value.reverse()
- }
-
- const { host } = define(() => {
- const n1 = createFor(
- () => list.value,
- (item, key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- // compiler rewrites { name } destructure to inline access
- span.innerHTML = `${key.value}. ${item.value.name}`
- // index should be undefined if source is not an object
- expect(index.value).toBe(undefined)
- })
- return span
- },
- item => item.name,
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><!--for-->',
- )
-
- // add
- list.value.push({ name: '4' })
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // move
- reverse()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 4</li><li>1. 3</li><li>2. 2</li><li>3. 1</li><!--for-->',
- )
-
- reverse()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // change
- list.value[0].name = 'a'
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. a</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // remove
- list.value.splice(1, 1)
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. a</li><li>1. 3</li><li>2. 4</li><!--for-->',
- )
-
- // clear
- list.value = []
- await nextTick()
- expect(host.innerHTML).toBe('<!--for-->')
- })
-
- test('de-structured value (rest element)', async () => {
- const list = ref([
- { name: '1', a: 1 },
- { name: '2', a: 2 },
- { name: '3', a: 3 },
- ])
- function reverse() {
- list.value = list.value.reverse()
- }
-
- const { host } = define(() => {
- const n1 = createFor(
- () => list.value,
- (item, _key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- span.innerHTML = JSON.stringify(
- getRestElement(item.value, ['name']),
- )
- // index should be undefined if source is not an object
- expect(index.value).toBe(undefined)
- })
- return span
- },
- item => item.name,
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>{"a":1}</li><li>{"a":2}</li><li>{"a":3}</li><!--for-->',
- )
-
- // add
- list.value.push({ name: '4', a: 4 })
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>{"a":1}</li><li>{"a":2}</li><li>{"a":3}</li><li>{"a":4}</li><!--for-->',
- )
-
- // move
- reverse()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>{"a":4}</li><li>{"a":3}</li><li>{"a":2}</li><li>{"a":1}</li><!--for-->',
- )
-
- reverse()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>{"a":1}</li><li>{"a":2}</li><li>{"a":3}</li><li>{"a":4}</li><!--for-->',
- )
-
- // change
- list.value[0].a = 5
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>{"a":5}</li><li>{"a":2}</li><li>{"a":3}</li><li>{"a":4}</li><!--for-->',
- )
-
- // remove
- list.value.splice(1, 1)
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>{"a":5}</li><li>{"a":3}</li><li>{"a":4}</li><!--for-->',
- )
-
- // clear
- list.value = []
- await nextTick()
- expect(host.innerHTML).toBe('<!--for-->')
- })
-
- test('de-structured value (default value)', async () => {
- const list = ref<any[]>([{ name: '1' }, { name: '2' }, { name: '3' }])
-
- const { host } = define(() => {
- const n1 = createFor(
- () => list.value,
- (item, _key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- span.innerHTML = getDefaultValue(item.value.x, '0')
- // index should be undefined if source is not an object
- expect(index.value).toBe(undefined)
- })
- return span
- },
- item => item.name,
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe('<li>0</li><li>0</li><li>0</li><!--for-->')
-
- // change
- list.value[0].x = 5
- await nextTick()
- expect(host.innerHTML).toBe('<li>5</li><li>0</li><li>0</li><!--for-->')
-
- // clear
- list.value = []
- await nextTick()
- expect(host.innerHTML).toBe('<!--for-->')
- })
-
- test('shallowRef source', async () => {
- const list = shallowRef([{ name: '1' }, { name: '2' }, { name: '3' }])
- const setList = (update = list.value.slice()) => (list.value = update)
- function reverse() {
- list.value = list.value.reverse()
- }
-
- const { host } = define(() => {
- const n1 = createFor(
- () => list.value,
- (item, key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- span.innerHTML = `${key.value}. ${item.value.name}`
-
- // index should be undefined if source is not an object
- expect(index.value).toBe(undefined)
- })
- return span
- },
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><!--for-->',
- )
-
- // add
- list.value.push({ name: '4' })
- setList()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // move
- reverse()
- setList()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 4</li><li>1. 3</li><li>2. 2</li><li>3. 1</li><!--for-->',
- )
-
- reverse()
- setList()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // change deep value should not update
- list.value[0].name = 'a'
- setList()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 2</li><li>2. 3</li><li>3. 4</li><!--for-->',
- )
-
- // remove
- list.value.splice(1, 1)
- setList()
- await nextTick()
- expect(host.innerHTML).toBe(
- '<li>0. 1</li><li>1. 3</li><li>2. 4</li><!--for-->',
- )
-
- // clear
- setList([])
- await nextTick()
- expect(host.innerHTML).toBe('<!--for-->')
- })
-
- test('should optimize call frequency during list operations', async () => {
- let sourceCalledTimes = 0
- let renderCalledTimes = 0
- let effectLabelCalledTimes = 0
- let effectIndexCalledTimes = 0
-
- const resetCounter = () => {
- sourceCalledTimes = 0
- renderCalledTimes = 0
- effectLabelCalledTimes = 0
- effectIndexCalledTimes = 0
- }
- const expectCalledTimesToBe = (
- message: string,
- source: number,
- render: number,
- label: number,
- index: number,
- ) => {
- expect(
- {
- source: sourceCalledTimes,
- render: renderCalledTimes,
- label: effectLabelCalledTimes,
- index: effectIndexCalledTimes,
- },
- message,
- ).toEqual({ source, render, label, index })
- resetCounter()
- }
-
- const createItem = (
- (id = 0) =>
- (label = id) => ({ id: id++, label })
- )()
- const createItems = (length: number) =>
- Array.from({ length }, (_, i) => createItem(i))
- const list = ref(createItems(100))
- const length = () => list.value.length
-
- define(() => {
- const n1 = createFor(
- () => (++sourceCalledTimes, list.value),
- (item, index) => {
- ++renderCalledTimes
- const span = document.createElement('li')
- renderEffect(() => {
- ++effectLabelCalledTimes
- item.value.label
- })
- renderEffect(() => {
- ++effectIndexCalledTimes
- index.value
- })
- return span
- },
- item => item.id,
- )
- return n1
- }).render()
-
- // Create rows
- expectCalledTimesToBe('Create rows', 1, length(), length(), length())
-
- // Update every 10th row
- for (let i = 0; i < length(); i += 10) {
- list.value[i].label += 10000
- }
- await nextTick()
- expectCalledTimesToBe('Update every 10th row', 0, 0, length() / 10, 0)
-
- // Append rows
- list.value.push(...createItems(100))
- await nextTick()
- expectCalledTimesToBe('Append rows', 1, 100, 100, 100)
-
- // Inserts rows at the beginning
- const tempLen = length()
- list.value.unshift(...createItems(100))
- await nextTick()
- expectCalledTimesToBe(
- 'Inserts rows at the beginning',
- 1,
- 100,
- 100,
- 100 + tempLen,
- )
-
- // Inserts rows in the middle
- const middleIdx = length() / 2
- list.value.splice(middleIdx, 0, ...createItems(100))
- await nextTick()
- expectCalledTimesToBe(
- 'Inserts rows in the middle',
- 1,
- 100,
- 100,
- 100 + middleIdx,
- )
-
- // Swap rows
- const temp = list.value[1]
- list.value[1] = list.value[length() - 2]
- list.value[length() - 2] = temp
- await nextTick()
- expectCalledTimesToBe('Swap rows', 1, 0, 0, 2)
-
- // Remove rows
- list.value.splice(1, 1)
- list.value.splice(length() - 2, 1)
- await nextTick()
- expectCalledTimesToBe('Remove rows', 1, 0, 0, length() - 1)
-
- // Clear rows
- list.value = []
- await nextTick()
- expectCalledTimesToBe('Clear rows', 1, 0, 0, 0)
- })
-
- test('should optimize call frequency during list operations with shallowRef', async () => {
- let sourceCalledTimes = 0
- let renderCalledTimes = 0
- let effectLabelCalledTimes = 0
- let effectIndexCalledTimes = 0
-
- const resetCounter = () => {
- sourceCalledTimes = 0
- renderCalledTimes = 0
- effectLabelCalledTimes = 0
- effectIndexCalledTimes = 0
- }
- const expectCalledTimesToBe = (
- message: string,
- source: number,
- render: number,
- label: number,
- index: number,
- ) => {
- expect(
- {
- source: sourceCalledTimes,
- render: renderCalledTimes,
- label: effectLabelCalledTimes,
- index: effectIndexCalledTimes,
- },
- message,
- ).toEqual({ source, render, label, index })
- resetCounter()
- }
-
- const createItem = (
- (id = 0) =>
- (label = id) => ({ id: id++, label: shallowRef(label) })
- )()
- const createItems = (length: number) =>
- Array.from({ length }, (_, i) => createItem(i))
- const list = shallowRef(createItems(100))
- const length = () => list.value.length
-
- define(() => {
- const n1 = createFor(
- () => (++sourceCalledTimes, list.value),
- (item, index) => {
- ++renderCalledTimes
- const span = document.createElement('li')
- renderEffect(() => {
- ++effectLabelCalledTimes
- item.value.label.value
- })
- renderEffect(() => {
- ++effectIndexCalledTimes
- index.value
- })
- return span
- },
- item => item.id,
- )
- return n1
- }).render()
-
- // Create rows
- expectCalledTimesToBe('Create rows', 1, length(), length(), length())
-
- // Update every 10th row
- for (let i = 0; i < length(); i += 10) {
- list.value[i].label.value += 10000
- }
- await nextTick()
- expectCalledTimesToBe('Update every 10th row', 0, 0, length() / 10, 0)
-
- // Append rows
- list.value.push(...createItems(100))
- triggerRef(list)
- await nextTick()
- expectCalledTimesToBe('Append rows', 1, 100, 100, 100)
-
- // Inserts rows at the beginning
- const tempLen = length()
- list.value.unshift(...createItems(100))
- triggerRef(list)
- await nextTick()
- expectCalledTimesToBe(
- 'Inserts rows at the beginning',
- 1,
- 100,
- 100,
- 100 + tempLen,
- )
-
- // Inserts rows in the middle
- const middleIdx = length() / 2
- list.value.splice(middleIdx, 0, ...createItems(100))
- triggerRef(list)
- await nextTick()
- expectCalledTimesToBe(
- 'Inserts rows in the middle',
- 1,
- 100,
- 100,
- 100 + middleIdx,
- )
-
- // Swap rows
- const temp = list.value[1]
- list.value[1] = list.value[length() - 2]
- list.value[length() - 2] = temp
- triggerRef(list)
- await nextTick()
- expectCalledTimesToBe('Swap rows', 1, 0, 0, 2)
-
- // Remove rows
- list.value.splice(1, 1)
- list.value.splice(length() - 2, 1)
- triggerRef(list)
- await nextTick()
- expectCalledTimesToBe('Remove rows', 1, 0, 0, length() - 1)
-
- // Clear rows
- list.value = []
- await nextTick()
- expectCalledTimesToBe('Clear rows', 1, 0, 0, 0)
- })
-
- describe('readonly source', () => {
- test('should not allow mutation', () => {
- const arr = readonly(reactive([{ foo: 1 }]))
-
- const { host } = define(() => {
- const n1 = createFor(
- () => arr,
- (item, key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- item.value.foo = 0
- span.innerHTML = `${item.value.foo}`
- })
- return span
- },
- idx => idx,
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe('<li>1</li><!--for-->')
- expect(
- `Set operation on key "foo" failed: target is readonly.`,
- ).toHaveBeenWarned()
- })
-
- test('should trigger effect for deep mutations', async () => {
- const arr = reactive([{ foo: 1 }])
- const readonlyArr = readonly(arr)
-
- const { host } = define(() => {
- const n1 = createFor(
- () => readonlyArr,
- (item, key, index) => {
- const span = document.createElement('li')
- renderEffect(() => {
- span.innerHTML = `${item.value.foo}`
- })
- return span
- },
- idx => idx,
- )
- return n1
- }).render()
-
- expect(host.innerHTML).toBe('<li>1</li><!--for-->')
-
- arr[0].foo = 2
- await nextTick()
- expect(host.innerHTML).toBe('<li>2</li><!--for-->')
- })
- })
-})
+++ /dev/null
-import { createVaporSSRApp, delegateEvents } from '../src'
-import { nextTick, ref } from '@vue/runtime-dom'
-import { compileScript, parse } from '@vue/compiler-sfc'
-import * as runtimeVapor from '../src'
-import * as runtimeDom from '@vue/runtime-dom'
-import * as VueServerRenderer from '@vue/server-renderer'
-
-const Vue = { ...runtimeDom, ...runtimeVapor }
-
-function compile(
- sfc: string,
- data: runtimeDom.Ref<any>,
- components: Record<string, any> = {},
- ssr = false,
-) {
- if (!sfc.includes(`<script`)) {
- sfc =
- `<script vapor>const data = _data; const components = _components;</script>` +
- sfc
- }
- const descriptor = parse(sfc).descriptor
-
- const script = compileScript(descriptor, {
- id: 'x',
- isProd: true,
- inlineTemplate: true,
- genDefaultAs: '__sfc__',
- vapor: true,
- templateOptions: {
- ssr,
- },
- })
-
- const code =
- script.content
- .replace(/\bimport {/g, 'const {')
- .replace(/ as _/g, ': _')
- .replace(/} from ['"]vue['"]/g, `} = Vue`)
- .replace(/} from "vue\/server-renderer"/g, '} = VueServerRenderer') +
- '\nreturn __sfc__'
-
- return new Function('Vue', 'VueServerRenderer', '_data', '_components', code)(
- Vue,
- VueServerRenderer,
- data,
- components,
- )
-}
-
-async function testHydration(
- code: string,
- components: Record<string, string> = {},
-) {
- const data = ref('foo')
- const ssrComponents: any = {}
- const clientComponents: any = {}
- for (const key in components) {
- clientComponents[key] = compile(components[key], data, clientComponents)
- ssrComponents[key] = compile(components[key], data, ssrComponents, true)
- }
-
- const serverComp = compile(code, data, ssrComponents, true)
- const html = await VueServerRenderer.renderToString(
- runtimeDom.createSSRApp(serverComp),
- )
- const container = document.createElement('div')
- document.body.appendChild(container)
- container.innerHTML = html
-
- const clientComp = compile(code, data, clientComponents)
- const app = createVaporSSRApp(clientComp)
- app.mount(container)
- return { data, container }
-}
-
-const triggerEvent = (type: string, el: Element) => {
- const event = new Event(type, { bubbles: true })
- el.dispatchEvent(event)
-}
-
-describe('Vapor Mode hydration', () => {
- delegateEvents('click')
-
- beforeEach(() => {
- document.body.innerHTML = ''
- })
-
- test('root text', async () => {
- const { data, container } = await testHydration(`
- <template>{{ data }}</template>
- `)
- expect(container.innerHTML).toMatchInlineSnapshot(`"foo"`)
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(`"bar"`)
- })
-
- test('root comment', async () => {
- const { container } = await testHydration(`
- <template><!----></template>
- `)
- expect(container.innerHTML).toBe('<!---->')
- expect(`Hydration children mismatch in <div>`).not.toHaveBeenWarned()
- })
-
- test('root with mixed element and text', async () => {
- const { container, data } = await testHydration(`
- <template> A<span>{{ data }}</span>{{ data }}</template>
- `)
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<!--[--> A<span>foo</span>foo<!--]-->"`,
- )
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<!--[--> A<span>bar</span>bar<!--]-->"`,
- )
- })
-
- test('empty element', async () => {
- const { container } = await testHydration(`
- <template><div/></template>
- `)
- expect(container.innerHTML).toBe('<div></div>')
- expect(`Hydration children mismatch in <div>`).not.toHaveBeenWarned()
- })
-
- test('element with binding and text children', async () => {
- const { container, data } = await testHydration(`
- <template><div :class="data">{{ data }}</div></template>
- `)
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div class="foo">foo</div>"`,
- )
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div class="bar">bar</div>"`,
- )
- })
-
- test('element with elements children', async () => {
- const { container } = await testHydration(`
- <template>
- <div>
- <span>{{ data }}</span>
- <span :class="data" @click="data = 'bar'"/>
- </div>
- </template>
- `)
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><span>foo</span><span class="foo"></span></div>"`,
- )
-
- // event handler
- triggerEvent('click', container.querySelector('.foo')!)
-
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><span>bar</span><span class="bar"></span></div>"`,
- )
- })
-
- test('basic component', async () => {
- const { container, data } = await testHydration(
- `
- <template><div><span></span><components.Child/></div></template>
- `,
- { Child: `<template>{{ data }}</template>` },
- )
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><span></span>foo</div>"`,
- )
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><span></span>bar</div>"`,
- )
- })
-
- test('fragment component', async () => {
- const { container, data } = await testHydration(
- `
- <template><div><span></span><components.Child/></div></template>
- `,
- { Child: `<template><div>{{ data }}</div>-{{ data }}-</template>` },
- )
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><span></span><!--[--><div>foo</div>-foo-<!--]--></div>"`,
- )
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><span></span><!--[--><div>bar</div>-bar-<!--]--></div>"`,
- )
- })
-
- test('fragment component with prepend', async () => {
- const { container, data } = await testHydration(
- `
- <template><div><components.Child/><span></span></div></template>
- `,
- { Child: `<template><div>{{ data }}</div>-{{ data }}-</template>` },
- )
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><!--[--><div>foo</div>-foo-<!--]--><span></span></div>"`,
- )
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><!--[--><div>bar</div>-bar-<!--]--><span></span></div>"`,
- )
- })
-
- test('nested fragment components', async () => {
- const { container, data } = await testHydration(
- `
- <template><div><components.Parent/><span></span></div></template>
- `,
- {
- Parent: `<template><div/><components.Child/><div/></template>`,
- Child: `<template><div>{{ data }}</div>-{{ data }}-</template>`,
- },
- )
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><!--[--><div></div><!--[--><div>foo</div>-foo-<!--]--><div></div><!--]--><span></span></div>"`,
- )
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot(
- `"<div><!--[--><div></div><!--[--><div>bar</div>-bar-<!--]--><div></div><!--]--><span></span></div>"`,
- )
- })
-
- // problem is the <!> placeholder does not exist in SSR output
- test.todo('component with anchor insertion', async () => {
- const { container, data } = await testHydration(
- `
- <template>
- <div>
- <span/>
- <components.Child/>
- <span/>
- </div>
- </template>
- `,
- {
- Child: `<template>{{ data }}</template>`,
- },
- )
- expect(container.innerHTML).toMatchInlineSnapshot()
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot()
- })
-
- test.todo('consecutive component with anchor insertion', async () => {
- const { container, data } = await testHydration(
- `<template>
- <div>
- <span/>
- <components.Child/>
- <components.Child/>
- <span/>
- </div>
- </template>
- `,
- {
- Child: `<template>{{ data }}</template>`,
- },
- )
- expect(container.innerHTML).toMatchInlineSnapshot()
-
- data.value = 'bar'
- await nextTick()
- expect(container.innerHTML).toMatchInlineSnapshot()
- })
-
- test.todo('if')
-
- test.todo('for')
-
- test.todo('slots')
-
- // test('element with ref', () => {
- // const el = ref()
- // const { vnode, container } = mountWithHydration('<div></div>', () =>
- // h('div', { ref: el }),
- // )
- // expect(vnode.el).toBe(container.firstChild)
- // expect(el.value).toBe(vnode.el)
- // })
-
- // test('with data-allow-mismatch component when using onServerPrefetch', async () => {
- // const Comp = {
- // template: `
- // <div>Comp2</div>
- // `,
- // }
- // let foo: any
- // const App = {
- // setup() {
- // const flag = ref(true)
- // foo = () => {
- // flag.value = false
- // }
- // onServerPrefetch(() => (flag.value = false))
- // return { flag }
- // },
- // components: {
- // Comp,
- // },
- // template: `
- // <span data-allow-mismatch>
- // <Comp v-if="flag"></Comp>
- // </span>
- // `,
- // }
- // // hydrate
- // const container = document.createElement('div')
- // container.innerHTML = await renderToString(h(App))
- // createSSRApp(App).mount(container)
- // expect(container.innerHTML).toBe(
- // '<span data-allow-mismatch=""><div>Comp2</div></span>',
- // )
- // foo()
- // await nextTick()
- // expect(container.innerHTML).toBe(
- // '<span data-allow-mismatch=""><!--v-if--></span>',
- // )
- // })
-
- // // compile SSR + client render fn from the same template & hydrate
- // test('full compiler integration', async () => {
- // const mounted: string[] = []
- // const log = vi.fn()
- // const toggle = ref(true)
-
- // const Child = {
- // data() {
- // return {
- // count: 0,
- // text: 'hello',
- // style: {
- // color: 'red',
- // },
- // }
- // },
- // mounted() {
- // mounted.push('child')
- // },
- // template: `
- // <div>
- // <span class="count" :style="style">{{ count }}</span>
- // <button class="inc" @click="count++">inc</button>
- // <button class="change" @click="style.color = 'green'" >change color</button>
- // <button class="emit" @click="$emit('foo')">emit</button>
- // <span class="text">{{ text }}</span>
- // <input v-model="text">
- // </div>
- // `,
- // }
-
- // const App = {
- // setup() {
- // return { toggle }
- // },
- // mounted() {
- // mounted.push('parent')
- // },
- // template: `
- // <div>
- // <span>hello</span>
- // <template v-if="toggle">
- // <Child @foo="log('child')"/>
- // <template v-if="true">
- // <button class="parent-click" @click="log('click')">click me</button>
- // </template>
- // </template>
- // <span>hello</span>
- // </div>`,
- // components: {
- // Child,
- // },
- // methods: {
- // log,
- // },
- // }
-
- // const container = document.createElement('div')
- // // server render
- // container.innerHTML = await renderToString(h(App))
- // // hydrate
- // createSSRApp(App).mount(container)
-
- // // assert interactions
- // // 1. parent button click
- // triggerEvent('click', container.querySelector('.parent-click')!)
- // expect(log).toHaveBeenCalledWith('click')
-
- // // 2. child inc click + text interpolation
- // const count = container.querySelector('.count') as HTMLElement
- // expect(count.textContent).toBe(`0`)
- // triggerEvent('click', container.querySelector('.inc')!)
- // await nextTick()
- // expect(count.textContent).toBe(`1`)
-
- // // 3. child color click + style binding
- // expect(count.style.color).toBe('red')
- // triggerEvent('click', container.querySelector('.change')!)
- // await nextTick()
- // expect(count.style.color).toBe('green')
-
- // // 4. child event emit
- // triggerEvent('click', container.querySelector('.emit')!)
- // expect(log).toHaveBeenCalledWith('child')
-
- // // 5. child v-model
- // const text = container.querySelector('.text')!
- // const input = container.querySelector('input')!
- // expect(text.textContent).toBe('hello')
- // input.value = 'bye'
- // triggerEvent('input', input)
- // await nextTick()
- // expect(text.textContent).toBe('bye')
- // })
-
- // test('handle click error in ssr mode', async () => {
- // const App = {
- // setup() {
- // const throwError = () => {
- // throw new Error('Sentry Error')
- // }
- // return { throwError }
- // },
- // template: `
- // <div>
- // <button class="parent-click" @click="throwError">click me</button>
- // </div>`,
- // }
-
- // const container = document.createElement('div')
- // // server render
- // container.innerHTML = await renderToString(h(App))
- // // hydrate
- // const app = createSSRApp(App)
- // const handler = (app.config.errorHandler = vi.fn())
- // app.mount(container)
- // // assert interactions
- // // parent button click
- // triggerEvent('click', container.querySelector('.parent-click')!)
- // expect(handler).toHaveBeenCalled()
- // })
-
- // test('handle blur error in ssr mode', async () => {
- // const App = {
- // setup() {
- // const throwError = () => {
- // throw new Error('Sentry Error')
- // }
- // return { throwError }
- // },
- // template: `
- // <div>
- // <input class="parent-click" @blur="throwError"/>
- // </div>`,
- // }
-
- // const container = document.createElement('div')
- // // server render
- // container.innerHTML = await renderToString(h(App))
- // // hydrate
- // const app = createSSRApp(App)
- // const handler = (app.config.errorHandler = vi.fn())
- // app.mount(container)
- // // assert interactions
- // // parent blur event
- // triggerEvent('blur', container.querySelector('.parent-click')!)
- // expect(handler).toHaveBeenCalled()
- // })
-
- // test('async component', async () => {
- // const spy = vi.fn()
- // const Comp = () =>
- // h(
- // 'button',
- // {
- // onClick: spy,
- // },
- // 'hello!',
- // )
-
- // let serverResolve: any
- // let AsyncComp = defineAsyncComponent(
- // () =>
- // new Promise(r => {
- // serverResolve = r
- // }),
- // )
-
- // const App = {
- // render() {
- // return ['hello', h(AsyncComp), 'world']
- // },
- // }
-
- // // server render
- // const htmlPromise = renderToString(h(App))
- // serverResolve(Comp)
- // const html = await htmlPromise
- // expect(html).toMatchInlineSnapshot(
- // `"<!--[-->hello<button>hello!</button>world<!--]-->"`,
- // )
-
- // // hydration
- // let clientResolve: any
- // AsyncComp = defineAsyncComponent(
- // () =>
- // new Promise(r => {
- // clientResolve = r
- // }),
- // )
-
- // const container = document.createElement('div')
- // container.innerHTML = html
- // createSSRApp(App).mount(container)
-
- // // hydration not complete yet
- // triggerEvent('click', container.querySelector('button')!)
- // expect(spy).not.toHaveBeenCalled()
-
- // // resolve
- // clientResolve(Comp)
- // await new Promise(r => setTimeout(r))
-
- // // should be hydrated now
- // triggerEvent('click', container.querySelector('button')!)
- // expect(spy).toHaveBeenCalled()
- // })
-
- // test('update async wrapper before resolve', async () => {
- // const Comp = {
- // render() {
- // return h('h1', 'Async component')
- // },
- // }
- // let serverResolve: any
- // let AsyncComp = defineAsyncComponent(
- // () =>
- // new Promise(r => {
- // serverResolve = r
- // }),
- // )
-
- // const toggle = ref(true)
- // const App = {
- // setup() {
- // onMounted(() => {
- // // change state, this makes updateComponent(AsyncComp) execute before
- // // the async component is resolved
- // toggle.value = false
- // })
-
- // return () => {
- // return [toggle.value ? 'hello' : 'world', h(AsyncComp)]
- // }
- // },
- // }
-
- // // server render
- // const htmlPromise = renderToString(h(App))
- // serverResolve(Comp)
- // const html = await htmlPromise
- // expect(html).toMatchInlineSnapshot(
- // `"<!--[-->hello<h1>Async component</h1><!--]-->"`,
- // )
-
- // // hydration
- // let clientResolve: any
- // AsyncComp = defineAsyncComponent(
- // () =>
- // new Promise(r => {
- // clientResolve = r
- // }),
- // )
-
- // const container = document.createElement('div')
- // container.innerHTML = html
- // createSSRApp(App).mount(container)
-
- // // resolve
- // clientResolve(Comp)
- // await new Promise(r => setTimeout(r))
-
- // // should be hydrated now
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
- // expect(container.innerHTML).toMatchInlineSnapshot(
- // `"<!--[-->world<h1>Async component</h1><!--]-->"`,
- // )
- // })
-
- // test('hydrate safely when property used by async setup changed before render', async () => {
- // const toggle = ref(true)
-
- // const AsyncComp = {
- // async setup() {
- // await new Promise<void>(r => setTimeout(r, 10))
- // return () => h('h1', 'Async component')
- // },
- // }
-
- // const AsyncWrapper = {
- // render() {
- // return h(AsyncComp)
- // },
- // }
-
- // const SiblingComp = {
- // setup() {
- // toggle.value = false
- // return () => h('span')
- // },
- // }
-
- // const App = {
- // setup() {
- // return () =>
- // h(
- // Suspense,
- // {},
- // {
- // default: () => [
- // h('main', {}, [
- // h(AsyncWrapper, {
- // prop: toggle.value ? 'hello' : 'world',
- // }),
- // h(SiblingComp),
- // ]),
- // ],
- // },
- // )
- // },
- // }
-
- // // server render
- // const html = await renderToString(h(App))
-
- // expect(html).toMatchInlineSnapshot(
- // `"<main><h1 prop="hello">Async component</h1><span></span></main>"`,
- // )
-
- // expect(toggle.value).toBe(false)
-
- // // hydration
-
- // // reset the value
- // toggle.value = true
- // expect(toggle.value).toBe(true)
-
- // const container = document.createElement('div')
- // container.innerHTML = html
- // createSSRApp(App).mount(container)
-
- // await new Promise(r => setTimeout(r, 10))
-
- // expect(toggle.value).toBe(false)
-
- // // should be hydrated now
- // expect(container.innerHTML).toMatchInlineSnapshot(
- // `"<main><h1 prop="world">Async component</h1><span></span></main>"`,
- // )
- // })
-
- // test('hydrate safely when property used by deep nested async setup changed before render', async () => {
- // const toggle = ref(true)
-
- // const AsyncComp = {
- // async setup() {
- // await new Promise<void>(r => setTimeout(r, 10))
- // return () => h('h1', 'Async component')
- // },
- // }
-
- // const AsyncWrapper = { render: () => h(AsyncComp) }
- // const AsyncWrapperWrapper = { render: () => h(AsyncWrapper) }
-
- // const SiblingComp = {
- // setup() {
- // toggle.value = false
- // return () => h('span')
- // },
- // }
-
- // const App = {
- // setup() {
- // return () =>
- // h(
- // Suspense,
- // {},
- // {
- // default: () => [
- // h('main', {}, [
- // h(AsyncWrapperWrapper, {
- // prop: toggle.value ? 'hello' : 'world',
- // }),
- // h(SiblingComp),
- // ]),
- // ],
- // },
- // )
- // },
- // }
-
- // // server render
- // const html = await renderToString(h(App))
-
- // expect(html).toMatchInlineSnapshot(
- // `"<main><h1 prop="hello">Async component</h1><span></span></main>"`,
- // )
-
- // expect(toggle.value).toBe(false)
-
- // // hydration
-
- // // reset the value
- // toggle.value = true
- // expect(toggle.value).toBe(true)
-
- // const container = document.createElement('div')
- // container.innerHTML = html
- // createSSRApp(App).mount(container)
-
- // await new Promise(r => setTimeout(r, 10))
-
- // expect(toggle.value).toBe(false)
-
- // // should be hydrated now
- // expect(container.innerHTML).toMatchInlineSnapshot(
- // `"<main><h1 prop="world">Async component</h1><span></span></main>"`,
- // )
- // })
-
- // // #3787
- // test('unmount async wrapper before load', async () => {
- // let resolve: any
- // const AsyncComp = defineAsyncComponent(
- // () =>
- // new Promise(r => {
- // resolve = r
- // }),
- // )
-
- // const show = ref(true)
- // const root = document.createElement('div')
- // root.innerHTML = '<div><div>async</div></div>'
-
- // createSSRApp({
- // render() {
- // return h('div', [show.value ? h(AsyncComp) : h('div', 'hi')])
- // },
- // }).mount(root)
-
- // show.value = false
- // await nextTick()
- // expect(root.innerHTML).toBe('<div><div>hi</div></div>')
- // resolve({})
- // })
-
- // //#12362
- // test('nested async wrapper', async () => {
- // const Toggle = defineAsyncComponent(
- // () =>
- // new Promise(r => {
- // r(
- // defineComponent({
- // setup(_, { slots }) {
- // const show = ref(false)
- // onMounted(() => {
- // nextTick(() => {
- // show.value = true
- // })
- // })
- // return () =>
- // withDirectives(
- // h('div', null, [renderSlot(slots, 'default')]),
- // [[vShow, show.value]],
- // )
- // },
- // }) as any,
- // )
- // }),
- // )
-
- // const Wrapper = defineAsyncComponent(() => {
- // return new Promise(r => {
- // r(
- // defineComponent({
- // render(this: any) {
- // return renderSlot(this.$slots, 'default')
- // },
- // }) as any,
- // )
- // })
- // })
-
- // const count = ref(0)
- // const fn = vi.fn()
- // const Child = {
- // setup() {
- // onMounted(() => {
- // fn()
- // count.value++
- // })
- // return () => h('div', count.value)
- // },
- // }
-
- // const App = {
- // render() {
- // return h(Toggle, null, {
- // default: () =>
- // h(Wrapper, null, {
- // default: () =>
- // h(Wrapper, null, {
- // default: () => h(Child),
- // }),
- // }),
- // })
- // },
- // }
-
- // const root = document.createElement('div')
- // root.innerHTML = await renderToString(h(App))
- // expect(root.innerHTML).toMatchInlineSnapshot(
- // `"<div style="display:none;"><!--[--><!--[--><!--[--><div>0</div><!--]--><!--]--><!--]--></div>"`,
- // )
-
- // createSSRApp(App).mount(root)
- // await nextTick()
- // await nextTick()
- // expect(root.innerHTML).toMatchInlineSnapshot(
- // `"<div style=""><!--[--><!--[--><!--[--><div>1</div><!--]--><!--]--><!--]--></div>"`,
- // )
- // expect(fn).toBeCalledTimes(1)
- // })
-
- // test('unmount async wrapper before load (fragment)', async () => {
- // let resolve: any
- // const AsyncComp = defineAsyncComponent(
- // () =>
- // new Promise(r => {
- // resolve = r
- // }),
- // )
-
- // const show = ref(true)
- // const root = document.createElement('div')
- // root.innerHTML = '<div><!--[-->async<!--]--></div>'
-
- // createSSRApp({
- // render() {
- // return h('div', [show.value ? h(AsyncComp) : h('div', 'hi')])
- // },
- // }).mount(root)
-
- // show.value = false
- // await nextTick()
- // expect(root.innerHTML).toBe('<div><div>hi</div></div>')
- // resolve({})
- // })
-
- // test('elements with camel-case in svg ', () => {
- // const { vnode, container } = mountWithHydration(
- // '<animateTransform></animateTransform>',
- // () => h('animateTransform'),
- // )
- // expect(vnode.el).toBe(container.firstChild)
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('SVG as a mount container', () => {
- // const svgContainer = document.createElement('svg')
- // svgContainer.innerHTML = '<g></g>'
- // const app = createSSRApp({
- // render: () => h('g'),
- // })
-
- // expect(
- // (
- // app.mount(svgContainer).$.subTree as VNode<Node, Element> & {
- // el: Element
- // }
- // ).el instanceof SVGElement,
- // )
- // })
-
- // test('force hydrate prop with `.prop` modifier', () => {
- // const { container } = mountWithHydration('<input type="checkbox">', () =>
- // h('input', {
- // type: 'checkbox',
- // '.indeterminate': true,
- // }),
- // )
- // expect((container.firstChild! as any).indeterminate).toBe(true)
- // })
-
- // test('force hydrate input v-model with non-string value bindings', () => {
- // const { container } = mountWithHydration(
- // '<input type="checkbox" value="true">',
- // () =>
- // withDirectives(
- // createVNode(
- // 'input',
- // { type: 'checkbox', 'true-value': true },
- // null,
- // PatchFlags.PROPS,
- // ['true-value'],
- // ),
- // [[vModelCheckbox, true]],
- // ),
- // )
- // expect((container.firstChild as any)._trueValue).toBe(true)
- // })
-
- // test('force hydrate checkbox with indeterminate', () => {
- // const { container } = mountWithHydration(
- // '<input type="checkbox" indeterminate>',
- // () =>
- // createVNode(
- // 'input',
- // { type: 'checkbox', indeterminate: '' },
- // null,
- // PatchFlags.CACHED,
- // ),
- // )
- // expect((container.firstChild as any).indeterminate).toBe(true)
- // })
-
- // test('force hydrate select option with non-string value bindings', () => {
- // const { container } = mountWithHydration(
- // '<select><option value="true">ok</option></select>',
- // () =>
- // h('select', [
- // // hoisted because bound value is a constant...
- // createVNode('option', { value: true }, null, -1 /* HOISTED */),
- // ]),
- // )
- // expect((container.firstChild!.firstChild as any)._value).toBe(true)
- // })
-
- // // #7203
- // test('force hydrate custom element with dynamic props', () => {
- // class MyElement extends HTMLElement {
- // foo = ''
- // constructor() {
- // super()
- // }
- // }
- // customElements.define('my-element-7203', MyElement)
-
- // const msg = ref('bar')
- // const container = document.createElement('div')
- // container.innerHTML = '<my-element-7203></my-element-7203>'
- // const app = createSSRApp({
- // render: () => h('my-element-7203', { foo: msg.value }),
- // })
- // app.mount(container)
- // expect((container.firstChild as any).foo).toBe(msg.value)
- // })
-
- // // #5728
- // test('empty text node in slot', () => {
- // const Comp = {
- // render(this: any) {
- // return renderSlot(this.$slots, 'default', {}, () => [
- // createTextVNode(''),
- // ])
- // },
- // }
- // const { container, vnode } = mountWithHydration('<!--[--><!--]-->', () =>
- // h(Comp),
- // )
- // expect(container.childNodes.length).toBe(3)
- // const text = container.childNodes[1]
- // expect(text.nodeType).toBe(3)
- // expect(vnode.el).toBe(container.childNodes[0])
- // // component => slot fragment => text node
- // expect((vnode as any).component?.subTree.children[0].el).toBe(text)
- // })
-
- // // #7215
- // test('empty text node', () => {
- // const Comp = {
- // render(this: any) {
- // return h('p', [''])
- // },
- // }
- // const { container } = mountWithHydration('<p></p>', () => h(Comp))
- // expect(container.childNodes.length).toBe(1)
- // const p = container.childNodes[0]
- // expect(p.childNodes.length).toBe(1)
- // const text = p.childNodes[0]
- // expect(text.nodeType).toBe(3)
- // })
-
- // // #11372
- // test('object style value tracking in prod', async () => {
- // __DEV__ = false
- // try {
- // const style = reactive({ color: 'red' })
- // const Comp = {
- // render(this: any) {
- // return (
- // openBlock(),
- // createElementBlock(
- // 'div',
- // {
- // style: normalizeStyle(style),
- // },
- // null,
- // 4 /* STYLE */,
- // )
- // )
- // },
- // }
- // const { container } = mountWithHydration(
- // `<div style="color: red;"></div>`,
- // () => h(Comp),
- // )
- // style.color = 'green'
- // await nextTick()
- // expect(container.innerHTML).toBe(`<div style="color: green;"></div>`)
- // } finally {
- // __DEV__ = true
- // }
- // })
-
- // test('app.unmount()', async () => {
- // const container = document.createElement('DIV')
- // container.innerHTML = '<button></button>'
- // const App = defineComponent({
- // setup(_, { expose }) {
- // const count = ref(0)
-
- // expose({ count })
-
- // return () =>
- // h('button', {
- // onClick: () => count.value++,
- // })
- // },
- // })
-
- // const app = createSSRApp(App)
- // const vm = app.mount(container)
- // await nextTick()
- // expect((container as any)._vnode).toBeDefined()
- // // @ts-expect-error - expose()'d properties are not available on vm type
- // expect(vm.count).toBe(0)
-
- // app.unmount()
- // expect((container as any)._vnode).toBe(null)
- // })
-
- // // #6637
- // test('stringified root fragment', () => {
- // mountWithHydration(`<!--[--><div></div><!--]-->`, () =>
- // createStaticVNode(`<div></div>`, 1),
- // )
- // expect(`mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('transition appear', () => {
- // const { vnode, container } = mountWithHydration(
- // `<template><div>foo</div></template>`,
- // () =>
- // h(
- // Transition,
- // { appear: true },
- // {
- // default: () => h('div', 'foo'),
- // },
- // ),
- // )
- // expect(container.firstChild).toMatchInlineSnapshot(`
- // <div
- // class="v-enter-from v-enter-active"
- // >
- // foo
- // </div>
- // `)
- // expect(vnode.el).toBe(container.firstChild)
- // expect(`mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('transition appear with v-if', () => {
- // const show = false
- // const { vnode, container } = mountWithHydration(
- // `<template><!----></template>`,
- // () =>
- // h(
- // Transition,
- // { appear: true },
- // {
- // default: () => (show ? h('div', 'foo') : createCommentVNode('')),
- // },
- // ),
- // )
- // expect(container.firstChild).toMatchInlineSnapshot('<!---->')
- // expect(vnode.el).toBe(container.firstChild)
- // expect(`mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('transition appear with v-show', () => {
- // const show = false
- // const { vnode, container } = mountWithHydration(
- // `<template><div style="display: none;">foo</div></template>`,
- // () =>
- // h(
- // Transition,
- // { appear: true },
- // {
- // default: () =>
- // withDirectives(createVNode('div', null, 'foo'), [[vShow, show]]),
- // },
- // ),
- // )
- // expect(container.firstChild).toMatchInlineSnapshot(`
- // <div
- // class="v-enter-from v-enter-active"
- // style="display: none;"
- // >
- // foo
- // </div>
- // `)
- // expect((container.firstChild as any)[vShowOriginalDisplay]).toBe('')
- // expect(vnode.el).toBe(container.firstChild)
- // expect(`mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('transition appear w/ event listener', async () => {
- // const container = document.createElement('div')
- // container.innerHTML = `<template><button>0</button></template>`
- // createSSRApp({
- // data() {
- // return {
- // count: 0,
- // }
- // },
- // template: `
- // <Transition appear>
- // <button @click="count++">{{count}}</button>
- // </Transition>
- // `,
- // }).mount(container)
-
- // expect(container.firstChild).toMatchInlineSnapshot(`
- // <button
- // class="v-enter-from v-enter-active"
- // >
- // 0
- // </button>
- // `)
-
- // triggerEvent('click', container.querySelector('button')!)
- // await nextTick()
- // expect(container.firstChild).toMatchInlineSnapshot(`
- // <button
- // class="v-enter-from v-enter-active"
- // >
- // 1
- // </button>
- // `)
- // })
-
- // test('Suspense + transition appear', async () => {
- // const { vnode, container } = mountWithHydration(
- // `<template><div>foo</div></template>`,
- // () =>
- // h(Suspense, {}, () =>
- // h(
- // Transition,
- // { appear: true },
- // {
- // default: () => h('div', 'foo'),
- // },
- // ),
- // ),
- // )
-
- // expect(vnode.el).toBe(container.firstChild)
- // // wait for hydration to finish
- // await new Promise(r => setTimeout(r))
-
- // expect(container.firstChild).toMatchInlineSnapshot(`
- // <div
- // class="v-enter-from v-enter-active"
- // >
- // foo
- // </div>
- // `)
- // await nextTick()
- // expect(vnode.el).toBe(container.firstChild)
- // })
-
- // // #10607
- // test('update component stable slot (prod + optimized mode)', async () => {
- // __DEV__ = false
- // try {
- // const container = document.createElement('div')
- // container.innerHTML = `<template><div show="false"><!--[--><div><div><!----></div></div><div>0</div><!--]--></div></template>`
- // const Comp = {
- // render(this: any) {
- // return (
- // openBlock(),
- // createElementBlock('div', null, [
- // renderSlot(this.$slots, 'default'),
- // ])
- // )
- // },
- // }
- // const show = ref(false)
- // const clicked = ref(false)
-
- // const Wrapper = {
- // setup() {
- // const items = ref<number[]>([])
- // onMounted(() => {
- // items.value = [1]
- // })
- // return () => {
- // return (
- // openBlock(),
- // createBlock(Comp, null, {
- // default: withCtx(() => [
- // createElementVNode('div', null, [
- // createElementVNode('div', null, [
- // clicked.value
- // ? (openBlock(),
- // createElementBlock('div', { key: 0 }, 'foo'))
- // : createCommentVNode('v-if', true),
- // ]),
- // ]),
- // createElementVNode(
- // 'div',
- // null,
- // items.value.length,
- // 1 /* TEXT */,
- // ),
- // ]),
- // _: 1 /* STABLE */,
- // })
- // )
- // }
- // },
- // }
- // createSSRApp({
- // components: { Wrapper },
- // data() {
- // return { show }
- // },
- // template: `<Wrapper :show="show"/>`,
- // }).mount(container)
-
- // await nextTick()
- // expect(container.innerHTML).toBe(
- // `<div show="false"><!--[--><div><div><!----></div></div><div>1</div><!--]--></div>`,
- // )
-
- // show.value = true
- // await nextTick()
- // expect(async () => {
- // clicked.value = true
- // await nextTick()
- // }).not.toThrow("Cannot read properties of null (reading 'insertBefore')")
-
- // await nextTick()
- // expect(container.innerHTML).toBe(
- // `<div show="true"><!--[--><div><div><div>foo</div></div></div><div>1</div><!--]--></div>`,
- // )
- // } catch (e) {
- // throw e
- // } finally {
- // __DEV__ = true
- // }
- // })
-
- // describe('mismatch handling', () => {
- // test('text node', () => {
- // const { container } = mountWithHydration(`foo`, () => 'bar')
- // expect(container.textContent).toBe('bar')
- // expect(`Hydration text mismatch`).toHaveBeenWarned()
- // })
-
- // test('element text content', () => {
- // const { container } = mountWithHydration(`<div>foo</div>`, () =>
- // h('div', 'bar'),
- // )
- // expect(container.innerHTML).toBe('<div>bar</div>')
- // expect(`Hydration text content mismatch`).toHaveBeenWarned()
- // })
-
- // test('not enough children', () => {
- // const { container } = mountWithHydration(`<div></div>`, () =>
- // h('div', [h('span', 'foo'), h('span', 'bar')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div><span>foo</span><span>bar</span></div>',
- // )
- // expect(`Hydration children mismatch`).toHaveBeenWarned()
- // })
-
- // test('too many children', () => {
- // const { container } = mountWithHydration(
- // `<div><span>foo</span><span>bar</span></div>`,
- // () => h('div', [h('span', 'foo')]),
- // )
- // expect(container.innerHTML).toBe('<div><span>foo</span></div>')
- // expect(`Hydration children mismatch`).toHaveBeenWarned()
- // })
-
- // test('complete mismatch', () => {
- // const { container } = mountWithHydration(
- // `<div><span>foo</span><span>bar</span></div>`,
- // () => h('div', [h('div', 'foo'), h('p', 'bar')]),
- // )
- // expect(container.innerHTML).toBe('<div><div>foo</div><p>bar</p></div>')
- // expect(`Hydration node mismatch`).toHaveBeenWarnedTimes(2)
- // })
-
- // test('fragment mismatch removal', () => {
- // const { container } = mountWithHydration(
- // `<div><!--[--><div>foo</div><div>bar</div><!--]--></div>`,
- // () => h('div', [h('span', 'replaced')]),
- // )
- // expect(container.innerHTML).toBe('<div><span>replaced</span></div>')
- // expect(`Hydration node mismatch`).toHaveBeenWarned()
- // })
-
- // test('fragment not enough children', () => {
- // const { container } = mountWithHydration(
- // `<div><!--[--><div>foo</div><!--]--><div>baz</div></div>`,
- // () => h('div', [[h('div', 'foo'), h('div', 'bar')], h('div', 'baz')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div><!--[--><div>foo</div><div>bar</div><!--]--><div>baz</div></div>',
- // )
- // expect(`Hydration node mismatch`).toHaveBeenWarned()
- // })
-
- // test('fragment too many children', () => {
- // const { container } = mountWithHydration(
- // `<div><!--[--><div>foo</div><div>bar</div><!--]--><div>baz</div></div>`,
- // () => h('div', [[h('div', 'foo')], h('div', 'baz')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div><!--[--><div>foo</div><!--]--><div>baz</div></div>',
- // )
- // // fragment ends early and attempts to hydrate the extra <div>bar</div>
- // // as 2nd fragment child.
- // expect(`Hydration text content mismatch`).toHaveBeenWarned()
- // // excessive children removal
- // expect(`Hydration children mismatch`).toHaveBeenWarned()
- // })
-
- // test('Teleport target has empty children', () => {
- // const teleportContainer = document.createElement('div')
- // teleportContainer.id = 'teleport'
- // document.body.appendChild(teleportContainer)
-
- // mountWithHydration('<!--teleport start--><!--teleport end-->', () =>
- // h(Teleport, { to: '#teleport' }, [h('span', 'value')]),
- // )
- // expect(teleportContainer.innerHTML).toBe(`<span>value</span>`)
- // expect(`Hydration children mismatch`).toHaveBeenWarned()
- // })
-
- // test('comment mismatch (element)', () => {
- // const { container } = mountWithHydration(`<div><span></span></div>`, () =>
- // h('div', [createCommentVNode('hi')]),
- // )
- // expect(container.innerHTML).toBe('<div><!--hi--></div>')
- // expect(`Hydration node mismatch`).toHaveBeenWarned()
- // })
-
- // test('comment mismatch (text)', () => {
- // const { container } = mountWithHydration(`<div>foobar</div>`, () =>
- // h('div', [createCommentVNode('hi')]),
- // )
- // expect(container.innerHTML).toBe('<div><!--hi--></div>')
- // expect(`Hydration node mismatch`).toHaveBeenWarned()
- // })
-
- // test('class mismatch', () => {
- // mountWithHydration(`<div class="foo bar"></div>`, () =>
- // h('div', { class: ['foo', 'bar'] }),
- // )
- // mountWithHydration(`<div class="foo bar"></div>`, () =>
- // h('div', { class: { foo: true, bar: true } }),
- // )
- // mountWithHydration(`<div class="foo bar"></div>`, () =>
- // h('div', { class: 'foo bar' }),
- // )
- // // SVG classes
- // mountWithHydration(`<svg class="foo bar"></svg>`, () =>
- // h('svg', { class: 'foo bar' }),
- // )
- // // class with different order
- // mountWithHydration(`<div class="foo bar"></div>`, () =>
- // h('div', { class: 'bar foo' }),
- // )
- // expect(`Hydration class mismatch`).not.toHaveBeenWarned()
- // mountWithHydration(`<div class="foo bar"></div>`, () =>
- // h('div', { class: 'foo' }),
- // )
- // expect(`Hydration class mismatch`).toHaveBeenWarned()
- // })
-
- // test('style mismatch', () => {
- // mountWithHydration(`<div style="color:red;"></div>`, () =>
- // h('div', { style: { color: 'red' } }),
- // )
- // mountWithHydration(`<div style="color:red;"></div>`, () =>
- // h('div', { style: `color:red;` }),
- // )
- // mountWithHydration(
- // `<div style="color:red; font-size: 12px;"></div>`,
- // () => h('div', { style: `font-size: 12px; color:red;` }),
- // )
- // mountWithHydration(`<div style="color:red;display:none;"></div>`, () =>
- // withDirectives(createVNode('div', { style: 'color: red' }, ''), [
- // [vShow, false],
- // ]),
- // )
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // mountWithHydration(`<div style="color:red;"></div>`, () =>
- // h('div', { style: { color: 'green' } }),
- // )
- // expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1)
- // })
-
- // test('style mismatch when no style attribute is present', () => {
- // mountWithHydration(`<div></div>`, () =>
- // h('div', { style: { color: 'red' } }),
- // )
- // expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1)
- // })
-
- // test('style mismatch w/ v-show', () => {
- // mountWithHydration(`<div style="color:red;display:none"></div>`, () =>
- // withDirectives(createVNode('div', { style: 'color: red' }, ''), [
- // [vShow, false],
- // ]),
- // )
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // mountWithHydration(`<div style="color:red;"></div>`, () =>
- // withDirectives(createVNode('div', { style: 'color: red' }, ''), [
- // [vShow, false],
- // ]),
- // )
- // expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1)
- // })
-
- // test('attr mismatch', () => {
- // mountWithHydration(`<div id="foo"></div>`, () => h('div', { id: 'foo' }))
- // mountWithHydration(`<div spellcheck></div>`, () =>
- // h('div', { spellcheck: '' }),
- // )
- // mountWithHydration(`<div></div>`, () => h('div', { id: undefined }))
- // // boolean
- // mountWithHydration(`<select multiple></div>`, () =>
- // h('select', { multiple: true }),
- // )
- // mountWithHydration(`<select multiple></div>`, () =>
- // h('select', { multiple: 'multiple' }),
- // )
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
-
- // mountWithHydration(`<div></div>`, () => h('div', { id: 'foo' }))
- // expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(1)
-
- // mountWithHydration(`<div id="bar"></div>`, () => h('div', { id: 'foo' }))
- // expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(2)
- // })
-
- // test('attr special case: textarea value', () => {
- // mountWithHydration(`<textarea>foo</textarea>`, () =>
- // h('textarea', { value: 'foo' }),
- // )
- // mountWithHydration(`<textarea></textarea>`, () =>
- // h('textarea', { value: '' }),
- // )
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
-
- // mountWithHydration(`<textarea>foo</textarea>`, () =>
- // h('textarea', { value: 'bar' }),
- // )
- // expect(`Hydration attribute mismatch`).toHaveBeenWarned()
- // })
-
- // // #11873
- // test('<textarea> with newlines at the beginning', async () => {
- // const render = () => h('textarea', null, '\nhello')
- // const html = await renderToString(createSSRApp({ render }))
- // mountWithHydration(html, render)
- // expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('<pre> with newlines at the beginning', async () => {
- // const render = () => h('pre', null, '\n')
- // const html = await renderToString(createSSRApp({ render }))
- // mountWithHydration(html, render)
- // expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('boolean attr handling', () => {
- // mountWithHydration(`<input />`, () => h('input', { readonly: false }))
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
-
- // mountWithHydration(`<input readonly />`, () =>
- // h('input', { readonly: true }),
- // )
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
-
- // mountWithHydration(`<input readonly="readonly" />`, () =>
- // h('input', { readonly: true }),
- // )
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('client value is null or undefined', () => {
- // mountWithHydration(`<div></div>`, () =>
- // h('div', { draggable: undefined }),
- // )
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
-
- // mountWithHydration(`<input />`, () => h('input', { type: null }))
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('should not warn against object values', () => {
- // mountWithHydration(`<input />`, () => h('input', { from: {} }))
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('should not warn on falsy bindings of non-property keys', () => {
- // mountWithHydration(`<button />`, () => h('button', { href: undefined }))
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('should not warn on non-renderable option values', () => {
- // mountWithHydration(`<select><option>hello</option></select>`, () =>
- // h('select', [h('option', { value: ['foo'] }, 'hello')]),
- // )
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('should not warn css v-bind', () => {
- // const container = document.createElement('div')
- // container.innerHTML = `<div style="--foo:red;color:var(--foo);" />`
- // const app = createSSRApp({
- // setup() {
- // useCssVars(() => ({
- // foo: 'red',
- // }))
- // return () => h('div', { style: { color: 'var(--foo)' } })
- // },
- // })
- // app.mount(container)
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // })
-
- // // #10317 - test case from #10325
- // test('css vars should only be added to expected on component root dom', () => {
- // const container = document.createElement('div')
- // container.innerHTML = `<div style="--foo:red;"><div style="color:var(--foo);" /></div>`
- // const app = createSSRApp({
- // setup() {
- // useCssVars(() => ({
- // foo: 'red',
- // }))
- // return () =>
- // h('div', null, [h('div', { style: { color: 'var(--foo)' } })])
- // },
- // })
- // app.mount(container)
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // })
-
- // // #11188
- // test('css vars support fallthrough', () => {
- // const container = document.createElement('div')
- // container.innerHTML = `<div style="padding: 4px;--foo:red;"></div>`
- // const app = createSSRApp({
- // setup() {
- // useCssVars(() => ({
- // foo: 'red',
- // }))
- // return () => h(Child)
- // },
- // })
- // const Child = {
- // setup() {
- // return () => h('div', { style: 'padding: 4px' })
- // },
- // }
- // app.mount(container)
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // })
-
- // // #11189
- // test('should not warn for directives that mutate DOM in created', () => {
- // const container = document.createElement('div')
- // container.innerHTML = `<div class="test red"></div>`
- // const vColor: ObjectDirective = {
- // created(el, binding) {
- // el.classList.add(binding.value)
- // },
- // }
- // const app = createSSRApp({
- // setup() {
- // return () =>
- // withDirectives(h('div', { class: 'test' }), [[vColor, 'red']])
- // },
- // })
- // app.mount(container)
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('escape css var name', () => {
- // const container = document.createElement('div')
- // container.innerHTML = `<div style="padding: 4px;--foo\\.bar:red;"></div>`
- // const app = createSSRApp({
- // setup() {
- // useCssVars(() => ({
- // 'foo.bar': 'red',
- // }))
- // return () => h(Child)
- // },
- // })
- // const Child = {
- // setup() {
- // return () => h('div', { style: 'padding: 4px' })
- // },
- // }
- // app.mount(container)
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // })
- // })
-
- // describe('data-allow-mismatch', () => {
- // test('element text content', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="text">foo</div>`,
- // () => h('div', 'bar'),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="text">bar</div>',
- // )
- // expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('not enough children', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children"></div>`,
- // () => h('div', [h('span', 'foo'), h('span', 'bar')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><span>foo</span><span>bar</span></div>',
- // )
- // expect(`Hydration children mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('too many children', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children"><span>foo</span><span>bar</span></div>`,
- // () => h('div', [h('span', 'foo')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><span>foo</span></div>',
- // )
- // expect(`Hydration children mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('complete mismatch', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children"><span>foo</span><span>bar</span></div>`,
- // () => h('div', [h('div', 'foo'), h('p', 'bar')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><div>foo</div><p>bar</p></div>',
- // )
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('fragment mismatch removal', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children"><!--[--><div>foo</div><div>bar</div><!--]--></div>`,
- // () => h('div', [h('span', 'replaced')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><span>replaced</span></div>',
- // )
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('fragment not enough children', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children"><!--[--><div>foo</div><!--]--><div>baz</div></div>`,
- // () => h('div', [[h('div', 'foo'), h('div', 'bar')], h('div', 'baz')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><!--[--><div>foo</div><div>bar</div><!--]--><div>baz</div></div>',
- // )
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('fragment too many children', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children"><!--[--><div>foo</div><div>bar</div><!--]--><div>baz</div></div>`,
- // () => h('div', [[h('div', 'foo')], h('div', 'baz')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><!--[--><div>foo</div><!--]--><div>baz</div></div>',
- // )
- // // fragment ends early and attempts to hydrate the extra <div>bar</div>
- // // as 2nd fragment child.
- // expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
- // // excessive children removal
- // expect(`Hydration children mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('comment mismatch (element)', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children"><span></span></div>`,
- // () => h('div', [createCommentVNode('hi')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><!--hi--></div>',
- // )
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('comment mismatch (text)', () => {
- // const { container } = mountWithHydration(
- // `<div data-allow-mismatch="children">foobar</div>`,
- // () => h('div', [createCommentVNode('hi')]),
- // )
- // expect(container.innerHTML).toBe(
- // '<div data-allow-mismatch="children"><!--hi--></div>',
- // )
- // expect(`Hydration node mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('class mismatch', () => {
- // mountWithHydration(
- // `<div class="foo bar" data-allow-mismatch="class"></div>`,
- // () => h('div', { class: 'foo' }),
- // )
- // expect(`Hydration class mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('style mismatch', () => {
- // mountWithHydration(
- // `<div style="color:red;" data-allow-mismatch="style"></div>`,
- // () => h('div', { style: { color: 'green' } }),
- // )
- // expect(`Hydration style mismatch`).not.toHaveBeenWarned()
- // })
-
- // test('attr mismatch', () => {
- // mountWithHydration(`<div data-allow-mismatch="attribute"></div>`, () =>
- // h('div', { id: 'foo' }),
- // )
- // mountWithHydration(
- // `<div id="bar" data-allow-mismatch="attribute"></div>`,
- // () => h('div', { id: 'foo' }),
- // )
- // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
- // })
- // })
-
- test.todo('Teleport')
- test.todo('Suspense')
-})
+++ /dev/null
-import {
- child,
- createIf,
- insert,
- renderEffect,
- template,
- // @ts-expect-error
- withDirectives,
-} from '../src'
-import { nextTick, ref } from '@vue/runtime-dom'
-import type { Mock } from 'vitest'
-import { makeRender } from './_utils'
-import { unmountComponent } from '../src/component'
-import { setElementText } from '../src/dom/prop'
-
-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(() => {
- setElementText(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.todo('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() as ParentNode
- withDirectives(child(n2), [[vDirective, () => (update.value, '1')]])
- return n2
- },
- () =>
- createIf(
- spyConditionFn2,
- () => {
- const n2 = t0() as ParentNode
- withDirectives(child(n2), [[vDirective, () => '2']])
- return n2
- },
- () => {
- const n2 = t0() as ParentNode
- withDirectives(child(n2), [[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)
- })
-})
+++ /dev/null
-import {
- EffectScope,
- type GenericComponentInstance,
- currentInstance,
- getCurrentScope,
- nextTick,
- onBeforeUpdate,
- onUpdated,
- ref,
- watchEffect,
- watchPostEffect,
- watchSyncEffect,
-} from '@vue/runtime-dom'
-import { renderEffect, template } from '../src'
-import { onEffectCleanup } from '@vue/reactivity'
-import { makeRender } from './_utils'
-
-const define = makeRender<any>()
-const createDemo = (setupFn: () => any, renderFn: (ctx: any) => any) =>
- define({
- setup: () => {
- const returned = setupFn()
- Object.defineProperty(returned, '__isScriptSetup', {
- enumerable: false,
- value: true,
- })
- return returned
- },
- render: (ctx: any) => {
- const t0 = template('<div></div>')
- renderFn(ctx)
- return t0()
- },
- })
-
-describe('renderEffect', () => {
- test('basic', async () => {
- let dummy: any
- const source = ref(0)
- renderEffect(() => {
- dummy = source.value
- })
- expect(dummy).toBe(0)
- await nextTick()
- expect(dummy).toBe(0)
-
- source.value++
- expect(dummy).toBe(0)
- await nextTick()
- expect(dummy).toBe(1)
-
- source.value++
- expect(dummy).toBe(1)
- await nextTick()
- expect(dummy).toBe(2)
-
- source.value++
- expect(dummy).toBe(2)
- await nextTick()
- expect(dummy).toBe(3)
- })
-
- test('should run with the scheduling order', async () => {
- const calls: string[] = []
-
- const { instance } = createDemo(
- () => {
- // setup
- const source = ref(0)
- const renderSource = ref(0)
- const change = () => source.value++
- const changeRender = () => renderSource.value++
-
- // Life Cycle Hooks
- onUpdated(() => {
- calls.push(`updated ${source.value}`)
- })
- onBeforeUpdate(() => {
- calls.push(`beforeUpdate ${source.value}`)
- })
-
- // Watch API
- watchPostEffect(() => {
- const current = source.value
- calls.push(`post ${current}`)
- onEffectCleanup(() => calls.push(`post cleanup ${current}`))
- })
- watchEffect(() => {
- const current = source.value
- calls.push(`pre ${current}`)
- onEffectCleanup(() => calls.push(`pre cleanup ${current}`))
- })
- watchSyncEffect(() => {
- const current = source.value
- calls.push(`sync ${current}`)
- onEffectCleanup(() => calls.push(`sync cleanup ${current}`))
- })
- return { source, change, renderSource, changeRender }
- },
- // render
- _ctx => {
- // Render Watch API
- renderEffect(() => {
- const current = _ctx.renderSource
- calls.push(`renderEffect ${current}`)
- onEffectCleanup(() => calls.push(`renderEffect cleanup ${current}`))
- })
- },
- ).render()
-
- const { change, changeRender } = instance?.setupState as any
-
- await nextTick()
- expect(calls).toEqual(['pre 0', 'sync 0', 'renderEffect 0', 'post 0'])
- calls.length = 0
-
- // Update
- changeRender()
- change()
-
- expect(calls).toEqual(['sync cleanup 0', 'sync 1'])
- calls.length = 0
-
- await nextTick()
- expect(calls).toEqual([
- 'pre cleanup 0',
- 'pre 1',
- 'renderEffect cleanup 0',
- 'beforeUpdate 1',
- 'renderEffect 1',
- 'post cleanup 0',
- 'post 1',
- 'updated 1',
- ])
- calls.length = 0
-
- // Update
- changeRender()
- change()
-
- expect(calls).toEqual(['sync cleanup 1', 'sync 2'])
- calls.length = 0
-
- await nextTick()
- expect(calls).toEqual([
- 'pre cleanup 1',
- 'pre 2',
- 'renderEffect cleanup 1',
- 'beforeUpdate 2',
- 'renderEffect 2',
- 'post cleanup 1',
- 'post 2',
- 'updated 2',
- ])
- })
-
- test('errors should include the execution location with beforeUpdate hook', async () => {
- const { instance } = createDemo(
- // setup
- () => {
- const source = ref()
- const update = () => source.value++
- onBeforeUpdate(() => {
- throw 'error in beforeUpdate'
- })
- return { source, update }
- },
- // render
- ctx => {
- renderEffect(() => {
- ctx.source
- })
- },
- ).render()
- const { update } = instance?.setupState as any
-
- await expect(async () => {
- update()
- await nextTick()
- }).rejects.toThrow('error in beforeUpdate')
-
- expect(
- '[Vue warn]: Unhandled error during execution of beforeUpdate hook',
- ).toHaveBeenWarned()
- expect(
- '[Vue warn]: Unhandled error during execution of component update',
- ).toHaveBeenWarned()
- })
-
- test('errors should include the execution location with updated hook', async () => {
- const { instance } = createDemo(
- // setup
- () => {
- const source = ref(0)
- const update = () => source.value++
- onUpdated(() => {
- throw 'error in updated'
- })
- return { source, update }
- },
- // render
- ctx => {
- renderEffect(() => {
- ctx.source
- })
- },
- ).render()
-
- const { update } = instance?.setupState as any
-
- await expect(async () => {
- update()
- await nextTick()
- }).rejects.toThrow('error in updated')
-
- expect(
- '[Vue warn]: Unhandled error during execution of updated',
- ).toHaveBeenWarned()
- })
-
- test('should be called with the current instance and current scope', async () => {
- const source = ref(0)
- const scope = new EffectScope()
- let instanceSnap: GenericComponentInstance | null = null
- let scopeSnap: EffectScope | undefined = undefined
- const { instance } = define(() => {
- scope.run(() => {
- renderEffect(() => {
- source.value
- instanceSnap = currentInstance
- scopeSnap = getCurrentScope()
- })
- })
- return []
- }).render()
-
- expect(instanceSnap).toBe(instance)
- expect(scopeSnap).toBe(scope)
-
- source.value++
- await nextTick()
- expect(instanceSnap).toBe(instance)
- expect(scopeSnap).toBe(scope)
- })
-})
+++ /dev/null
-import { defineComponent, h } from '@vue/runtime-dom'
-import { makeInteropRender } from './_utils'
-import { createComponent, defineVaporComponent } from '../src'
-
-const define = makeInteropRender()
-
-describe('vdomInterop', () => {
- describe.todo('props', () => {})
-
- describe.todo('emit', () => {})
-
- describe.todo('slots', () => {})
-
- describe.todo('provide', () => {})
-
- describe.todo('inject', () => {})
-
- describe.todo('template ref', () => {})
-
- describe.todo('dynamic component', () => {})
-
- describe('attribute fallthrough', () => {
- it('should not fallthrough emit handlers to vdom child', () => {
- const VDomChild = defineComponent({
- emits: ['click'],
- setup(_, { emit }) {
- return () => h('button', { onClick: () => emit('click') }, 'click me')
- },
- })
-
- const fn = vi.fn()
- const VaporChild = defineVaporComponent({
- emits: ['click'],
- setup() {
- return createComponent(
- VDomChild as any,
- { onClick: () => fn },
- null,
- true,
- )
- },
- })
-
- const { host, html } = define({
- setup() {
- return () => h(VaporChild as any)
- },
- }).render()
-
- expect(html()).toBe('<button>click me</button>')
- const button = host.querySelector('button')!
- button.dispatchEvent(new Event('click'))
-
- // fn should be called once
- expect(fn).toHaveBeenCalledTimes(1)
- })
- })
-})
+++ /dev/null
-{
- "name": "@vue/runtime-vapor",
- "version": "3.5.13",
- "description": "@vue/runtime-vapor",
- "main": "index.js",
- "module": "dist/runtime-vapor.esm-bundler.js",
- "types": "dist/runtime-vapor.d.ts",
- "files": [
- "index.js",
- "dist"
- ],
- "exports": {
- ".": {
- "types": "./dist/runtime-vapor.d.ts",
- "default": "./dist/runtime-vapor.esm-bundler.js"
- },
- "./*": "./*"
- },
- "sideEffects": false,
- "buildOptions": {
- "name": "VueRuntimeVapor",
- "formats": [
- "esm-bundler"
- ]
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/vuejs/core.git",
- "directory": "packages/runtime-vapor"
- },
- "keywords": [
- "vue"
- ],
- "author": "Evan You",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/vuejs/core/issues"
- },
- "homepage": "https://github.com/vuejs/core/tree/dev/packages/runtime-vapor#readme",
- "dependencies": {
- "@vue/shared": "workspace:*",
- "@vue/reactivity": "workspace:*"
- },
- "peerDependencies": {
- "@vue/runtime-dom": "workspace:*"
- }
-}
+++ /dev/null
-import {
- type VaporComponent,
- type VaporComponentInstance,
- createComponent,
- getExposed,
- mountComponent,
- unmountComponent,
-} from './component'
-import {
- type App,
- type AppMountFn,
- type AppUnmountFn,
- type CreateAppFunction,
- createAppAPI,
- flushOnAppMount,
- initFeatureFlags,
- normalizeContainer,
- setDevtoolsHook,
- warn,
-} from '@vue/runtime-dom'
-import type { RawProps } from './componentProps'
-import { getGlobalThis } from '@vue/shared'
-import { optimizePropertyLookup } from './dom/prop'
-import { withHydration } from './dom/hydration'
-
-let _createApp: CreateAppFunction<ParentNode, VaporComponent>
-
-const mountApp: AppMountFn<ParentNode> = (app, container) => {
- optimizePropertyLookup()
-
- // clear content before mounting
- if (container.nodeType === 1 /* Node.ELEMENT_NODE */) {
- if (__DEV__ && container.childNodes.length) {
- warn('mount target container is not empty and will be cleared.')
- }
- container.textContent = ''
- }
-
- const instance = createComponent(
- app._component,
- app._props as RawProps,
- null,
- false,
- app._context,
- )
- mountComponent(instance, container)
- flushOnAppMount()
-
- return instance!
-}
-
-let _hydrateApp: CreateAppFunction<ParentNode, VaporComponent>
-
-const hydrateApp: AppMountFn<ParentNode> = (app, container) => {
- optimizePropertyLookup()
-
- let instance: VaporComponentInstance
- withHydration(container, () => {
- instance = createComponent(
- app._component,
- app._props as RawProps,
- null,
- false,
- app._context,
- )
- mountComponent(instance, container)
- flushOnAppMount()
- })
-
- return instance!
-}
-
-const unmountApp: AppUnmountFn = app => {
- unmountComponent(app._instance as VaporComponentInstance, app._container)
-}
-
-function prepareApp() {
- // compile-time feature flags check
- if (__ESM_BUNDLER__ && !__TEST__) {
- initFeatureFlags()
- }
-
- const target = getGlobalThis()
- target.__VUE__ = true
- if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
- setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__, target)
- }
-}
-
-function postPrepareApp(app: App) {
- if (__DEV__) {
- app.config.globalProperties = new Proxy(
- {},
- {
- set() {
- warn(`app.config.globalProperties is not supported in vapor mode.`)
- return false
- },
- },
- )
- }
-
- const mount = app.mount
- app.mount = (container, ...args: any[]) => {
- container = normalizeContainer(container) as ParentNode
- return mount(container, ...args)
- }
-}
-
-export const createVaporApp: CreateAppFunction<ParentNode, VaporComponent> = (
- comp,
- props,
-) => {
- prepareApp()
- if (!_createApp) _createApp = createAppAPI(mountApp, unmountApp, getExposed)
- const app = _createApp(comp, props)
- postPrepareApp(app)
- return app
-}
-
-export const createVaporSSRApp: CreateAppFunction<
- ParentNode,
- VaporComponent
-> = (comp, props) => {
- prepareApp()
- if (!_hydrateApp)
- _hydrateApp = createAppAPI(hydrateApp, unmountApp, getExposed)
- const app = _hydrateApp(comp, props)
- postPrepareApp(app)
- return app
-}
+++ /dev/null
-import { resolveDynamicComponent } from '@vue/runtime-dom'
-import { DynamicFragment, type VaporFragment, insert } from './block'
-import { createComponentWithFallback } from './component'
-import { renderEffect } from './renderEffect'
-import type { RawProps } from './componentProps'
-import type { RawSlots } from './componentSlots'
-import {
- insertionAnchor,
- insertionParent,
- resetInsertionState,
-} from './insertionState'
-import { isHydrating, locateHydrationNode } from './dom/hydration'
-
-export function createDynamicComponent(
- getter: () => any,
- rawProps?: RawProps | null,
- rawSlots?: RawSlots | null,
- isSingleRoot?: boolean,
-): VaporFragment {
- const _insertionParent = insertionParent
- const _insertionAnchor = insertionAnchor
- if (isHydrating) {
- locateHydrationNode()
- } else {
- resetInsertionState()
- }
-
- const frag = __DEV__
- ? new DynamicFragment('dynamic-component')
- : new DynamicFragment()
-
- renderEffect(() => {
- const value = getter()
- frag.update(
- () =>
- createComponentWithFallback(
- resolveDynamicComponent(value) as any,
- rawProps,
- rawSlots,
- isSingleRoot,
- ),
- value,
- )
- })
-
- if (!isHydrating && _insertionParent) {
- insert(frag, _insertionParent, _insertionAnchor)
- }
-
- return frag
-}
+++ /dev/null
-import {
- EffectScope,
- type ShallowRef,
- isReactive,
- isReadonly,
- isShallow,
- pauseTracking,
- resetTracking,
- shallowReadArray,
- shallowRef,
- toReactive,
- toReadonly,
-} from '@vue/reactivity'
-import { getSequence, isArray, isObject, isString } from '@vue/shared'
-import { createComment, createTextNode } from './dom/node'
-import {
- type Block,
- VaporFragment,
- insert,
- remove as removeBlock,
-} from './block'
-import { warn } from '@vue/runtime-dom'
-import { currentInstance, isVaporComponent } from './component'
-import type { DynamicSlot } from './componentSlots'
-import { renderEffect } from './renderEffect'
-import { VaporVForFlags } from '../../shared/src/vaporFlags'
-import { isHydrating, locateHydrationNode } from './dom/hydration'
-import {
- insertionAnchor,
- insertionParent,
- resetInsertionState,
-} from './insertionState'
-
-class ForBlock extends VaporFragment {
- scope: EffectScope | undefined
- key: any
-
- itemRef: ShallowRef<any>
- keyRef: ShallowRef<any> | undefined
- indexRef: ShallowRef<number | undefined> | undefined
-
- constructor(
- nodes: Block,
- scope: EffectScope | undefined,
- item: ShallowRef<any>,
- key: ShallowRef<any> | undefined,
- index: ShallowRef<number | undefined> | undefined,
- renderKey: any,
- ) {
- super(nodes)
- this.scope = scope
- this.itemRef = item
- this.keyRef = key
- this.indexRef = index
- this.key = renderKey
- }
-}
-
-type Source = any[] | Record<any, any> | number | Set<any> | Map<any, any>
-
-type ResolvedSource = {
- values: any[]
- needsWrap: boolean
- isReadonlySource: boolean
- keys?: string[]
-}
-
-export const createFor = (
- src: () => Source,
- renderItem: (
- item: ShallowRef<any>,
- key: ShallowRef<any>,
- index: ShallowRef<number | undefined>,
- ) => Block,
- getKey?: (item: any, key: any, index?: number) => any,
- flags = 0,
-): VaporFragment => {
- const _insertionParent = insertionParent
- const _insertionAnchor = insertionAnchor
- if (isHydrating) {
- locateHydrationNode()
- } else {
- resetInsertionState()
- }
-
- let isMounted = false
- let oldBlocks: ForBlock[] = []
- let newBlocks: ForBlock[]
- let parent: ParentNode | undefined | null
- // TODO handle this in hydration
- const parentAnchor = __DEV__ ? createComment('for') : createTextNode()
- const frag = new VaporFragment(oldBlocks)
- const instance = currentInstance!
- const canUseFastRemove = flags & VaporVForFlags.FAST_REMOVE
- const isComponent = flags & VaporVForFlags.IS_COMPONENT
-
- if (__DEV__ && !instance) {
- warn('createFor() can only be used inside setup()')
- }
-
- const renderList = () => {
- const source = normalizeSource(src())
- const newLength = source.values.length
- const oldLength = oldBlocks.length
- newBlocks = new Array(newLength)
-
- pauseTracking()
-
- if (!isMounted) {
- isMounted = true
- for (let i = 0; i < newLength; i++) {
- mount(source, i)
- }
- } else {
- parent = parent || parentAnchor!.parentNode
- if (!oldLength) {
- // fast path for all new
- for (let i = 0; i < newLength; i++) {
- mount(source, i)
- }
- } else if (!newLength) {
- // fast path for clearing all
- const doRemove = !canUseFastRemove
- for (let i = 0; i < oldLength; i++) {
- unmount(oldBlocks[i], doRemove)
- }
- if (canUseFastRemove) {
- parent!.textContent = ''
- parent!.appendChild(parentAnchor)
- }
- } else if (!getKey) {
- // unkeyed fast path
- const commonLength = Math.min(newLength, oldLength)
- for (let i = 0; i < commonLength; i++) {
- update((newBlocks[i] = oldBlocks[i]), getItem(source, i)[0])
- }
- for (let i = oldLength; i < newLength; i++) {
- mount(source, i)
- }
- for (let i = newLength; i < oldLength; i++) {
- unmount(oldBlocks[i])
- }
- } else {
- let i = 0
- let e1 = oldLength - 1 // prev ending index
- let e2 = newLength - 1 // next ending index
-
- // 1. sync from start
- // (a b) c
- // (a b) d e
- while (i <= e1 && i <= e2) {
- if (tryPatchIndex(source, i)) {
- i++
- } else {
- break
- }
- }
-
- // 2. sync from end
- // a (b c)
- // d e (b c)
- while (i <= e1 && i <= e2) {
- if (tryPatchIndex(source, i)) {
- e1--
- e2--
- } else {
- break
- }
- }
-
- // 3. common sequence + mount
- // (a b)
- // (a b) c
- // i = 2, e1 = 1, e2 = 2
- // (a b)
- // c (a b)
- // i = 0, e1 = -1, e2 = 0
- if (i > e1) {
- if (i <= e2) {
- const nextPos = e2 + 1
- const anchor =
- nextPos < newLength
- ? normalizeAnchor(newBlocks[nextPos].nodes)
- : parentAnchor
- while (i <= e2) {
- mount(source, i, anchor)
- i++
- }
- }
- }
-
- // 4. common sequence + unmount
- // (a b) c
- // (a b)
- // i = 2, e1 = 2, e2 = 1
- // a (b c)
- // (b c)
- // i = 0, e1 = 0, e2 = -1
- else if (i > e2) {
- while (i <= e1) {
- unmount(oldBlocks[i])
- i++
- }
- }
-
- // 5. unknown sequence
- // [i ... e1 + 1]: a b [c d e] f g
- // [i ... e2 + 1]: a b [e d c h] f g
- // i = 2, e1 = 4, e2 = 5
- else {
- const s1 = i // prev starting index
- const s2 = i // next starting index
-
- // 5.1 build key:index map for newChildren
- const keyToNewIndexMap = new Map()
- for (i = s2; i <= e2; i++) {
- keyToNewIndexMap.set(getKey(...getItem(source, i)), i)
- }
-
- // 5.2 loop through old children left to be patched and try to patch
- // matching nodes & remove nodes that are no longer present
- let j
- let patched = 0
- const toBePatched = e2 - s2 + 1
- let moved = false
- // used to track whether any node has moved
- let maxNewIndexSoFar = 0
- // works as Map<newIndex, oldIndex>
- // Note that oldIndex is offset by +1
- // and oldIndex = 0 is a special value indicating the new node has
- // no corresponding old node.
- // used for determining longest stable subsequence
- const newIndexToOldIndexMap = new Array(toBePatched).fill(0)
-
- for (i = s1; i <= e1; i++) {
- const prevBlock = oldBlocks[i]
- if (patched >= toBePatched) {
- // all new children have been patched so this can only be a removal
- unmount(prevBlock)
- } else {
- const newIndex = keyToNewIndexMap.get(prevBlock.key)
- if (newIndex == null) {
- unmount(prevBlock)
- } else {
- newIndexToOldIndexMap[newIndex - s2] = i + 1
- if (newIndex >= maxNewIndexSoFar) {
- maxNewIndexSoFar = newIndex
- } else {
- moved = true
- }
- update(
- (newBlocks[newIndex] = prevBlock),
- ...getItem(source, newIndex),
- )
- patched++
- }
- }
- }
-
- // 5.3 move and mount
- // generate longest stable subsequence only when nodes have moved
- const increasingNewIndexSequence = moved
- ? getSequence(newIndexToOldIndexMap)
- : []
- j = increasingNewIndexSequence.length - 1
- // looping backwards so that we can use last patched node as anchor
- for (i = toBePatched - 1; i >= 0; i--) {
- const nextIndex = s2 + i
- const anchor =
- nextIndex + 1 < newLength
- ? normalizeAnchor(newBlocks[nextIndex + 1].nodes)
- : parentAnchor
- if (newIndexToOldIndexMap[i] === 0) {
- // mount new
- mount(source, nextIndex, anchor)
- } else if (moved) {
- // move if:
- // There is no stable subsequence (e.g. a reverse)
- // OR current node is not among the stable sequence
- if (j < 0 || i !== increasingNewIndexSequence[j]) {
- insert(newBlocks[nextIndex].nodes, parent!, anchor)
- } else {
- j--
- }
- }
- }
- }
- }
- }
-
- frag.nodes = [(oldBlocks = newBlocks)]
- if (parentAnchor) {
- frag.nodes.push(parentAnchor)
- }
-
- resetTracking()
- }
-
- const needKey = renderItem.length > 1
- const needIndex = renderItem.length > 2
-
- const mount = (
- source: ResolvedSource,
- idx: number,
- anchor: Node | undefined = parentAnchor,
- ): ForBlock => {
- const [item, key, index] = getItem(source, idx)
- const itemRef = shallowRef(item)
- // avoid creating refs if the render fn doesn't need it
- const keyRef = needKey ? shallowRef(key) : undefined
- const indexRef = needIndex ? shallowRef(index) : undefined
-
- let nodes: Block
- let scope: EffectScope | undefined
- if (isComponent) {
- // component already has its own scope so no outer scope needed
- nodes = renderItem(itemRef, keyRef as any, indexRef as any)
- } else {
- scope = new EffectScope()
- nodes = scope.run(() =>
- renderItem(itemRef, keyRef as any, indexRef as any),
- )!
- }
-
- const block = (newBlocks[idx] = new ForBlock(
- nodes,
- scope,
- itemRef,
- keyRef,
- indexRef,
- getKey && getKey(item, key, index),
- ))
-
- if (parent) insert(block.nodes, parent, anchor)
-
- return block
- }
-
- const tryPatchIndex = (source: any, idx: number) => {
- const block = oldBlocks[idx]
- const [item, key, index] = getItem(source, idx)
- if (block.key === getKey!(item, key, index)) {
- update((newBlocks[idx] = block), item)
- return true
- }
- }
-
- const update = (
- { itemRef, keyRef, indexRef }: ForBlock,
- newItem: any,
- newKey?: any,
- newIndex?: any,
- ) => {
- if (newItem !== itemRef.value) {
- itemRef.value = newItem
- }
- if (keyRef && newKey !== undefined && newKey !== keyRef.value) {
- keyRef.value = newKey
- }
- if (indexRef && newIndex !== undefined && newIndex !== indexRef.value) {
- indexRef.value = newIndex
- }
- }
-
- const unmount = ({ nodes, scope }: ForBlock, doRemove = true) => {
- scope && scope.stop()
- doRemove && removeBlock(nodes, parent!)
- }
-
- if (flags & VaporVForFlags.ONCE) {
- renderList()
- } else {
- renderEffect(renderList)
- }
-
- if (!isHydrating && _insertionParent) {
- insert(frag, _insertionParent, _insertionAnchor)
- }
-
- return frag
-}
-
-export function createForSlots(
- rawSource: Source,
- getSlot: (item: any, key: any, index?: number) => DynamicSlot,
-): DynamicSlot[] {
- const source = normalizeSource(rawSource)
- const sourceLength = source.values.length
- const slots = new Array<DynamicSlot>(sourceLength)
- for (let i = 0; i < sourceLength; i++) {
- slots[i] = getSlot(...getItem(source, i))
- }
- return slots
-}
-
-function normalizeSource(source: any): ResolvedSource {
- let values = source
- let needsWrap = false
- let isReadonlySource = false
- let keys
- if (isArray(source)) {
- if (isReactive(source)) {
- needsWrap = !isShallow(source)
- values = shallowReadArray(source)
- isReadonlySource = isReadonly(source)
- }
- } else if (isString(source)) {
- values = source.split('')
- } else if (typeof source === 'number') {
- if (__DEV__ && !Number.isInteger(source)) {
- warn(`The v-for range expect an integer value but got ${source}.`)
- }
- values = new Array(source)
- for (let i = 0; i < source; i++) values[i] = i + 1
- } else if (isObject(source)) {
- if (source[Symbol.iterator as any]) {
- values = Array.from(source as Iterable<any>)
- } else {
- keys = Object.keys(source)
- values = new Array(keys.length)
- for (let i = 0, l = keys.length; i < l; i++) {
- values[i] = source[keys[i]]
- }
- }
- }
- return {
- values,
- needsWrap,
- isReadonlySource,
- keys,
- }
-}
-
-function getItem(
- { keys, values, needsWrap, isReadonlySource }: ResolvedSource,
- idx: number,
-): [item: any, key: any, index?: number] {
- const value = needsWrap
- ? isReadonlySource
- ? toReadonly(toReactive(values[idx]))
- : toReactive(values[idx])
- : values[idx]
- if (keys) {
- return [value, keys[idx], idx]
- } else {
- return [value, idx, undefined]
- }
-}
-
-function normalizeAnchor(node: Block): Node {
- if (node instanceof Node) {
- return node
- } else if (isArray(node)) {
- return normalizeAnchor(node[0])
- } else if (isVaporComponent(node)) {
- return normalizeAnchor(node.block!)
- } else {
- return normalizeAnchor(node.nodes!)
- }
-}
-
-// runtime helper for rest element destructure
-export function getRestElement(val: any, keys: string[]): any {
- const res: any = {}
- for (const key in val) {
- if (!keys.includes(key)) res[key] = val[key]
- }
- return res
-}
-
-export function getDefaultValue(val: any, defaultVal: any): any {
- return val === undefined ? defaultVal : val
-}
+++ /dev/null
-import { type Block, type BlockFn, DynamicFragment, insert } from './block'
-import { isHydrating, locateHydrationNode } from './dom/hydration'
-import {
- insertionAnchor,
- insertionParent,
- resetInsertionState,
-} from './insertionState'
-import { renderEffect } from './renderEffect'
-
-export function createIf(
- condition: () => any,
- b1: BlockFn,
- b2?: BlockFn,
- once?: boolean,
-): Block {
- const _insertionParent = insertionParent
- const _insertionAnchor = insertionAnchor
- if (isHydrating) {
- locateHydrationNode()
- } else {
- resetInsertionState()
- }
-
- let frag: Block
- if (once) {
- frag = condition() ? b1() : b2 ? b2() : []
- } else {
- frag = __DEV__ ? new DynamicFragment('if') : new DynamicFragment()
- renderEffect(() => (frag as DynamicFragment).update(condition() ? b1 : b2))
- }
-
- if (!isHydrating && _insertionParent) {
- insert(frag, _insertionParent, _insertionAnchor)
- }
-
- return frag
-}
+++ /dev/null
-import type { ObjectVaporComponent, VaporComponent } from './component'
-import { extend, isFunction } from '@vue/shared'
-
-/*! #__NO_SIDE_EFFECTS__ */
-export function defineVaporComponent(
- comp: VaporComponent,
- extraOptions?: Omit<ObjectVaporComponent, 'setup'>,
-): VaporComponent {
- if (isFunction(comp)) {
- // #8236: extend call and options.name access are considered side-effects
- // by Rollup, so we have to wrap it in a pure-annotated IIFE.
- return /*@__PURE__*/ (() =>
- extend({ name: comp.name }, extraOptions, {
- setup: comp,
- __vapor: true,
- }))()
- }
- // TODO type inference
- comp.__vapor = true
- return comp
-}
+++ /dev/null
-import { type Ref, isRef, onScopeDispose } from '@vue/reactivity'
-import {
- type VaporComponentInstance,
- currentInstance,
- getExposed,
- isVaporComponent,
-} from './component'
-import {
- ErrorCodes,
- type SchedulerJob,
- callWithErrorHandling,
- queuePostFlushCb,
- warn,
-} from '@vue/runtime-dom'
-import {
- EMPTY_OBJ,
- hasOwn,
- isArray,
- isFunction,
- isString,
- remove,
-} from '@vue/shared'
-import { DynamicFragment } from './block'
-
-export type NodeRef = string | Ref | ((ref: Element) => void)
-export type RefEl = Element | VaporComponentInstance
-
-export type setRefFn = (
- el: RefEl,
- ref: NodeRef,
- oldRef?: NodeRef,
- refFor?: boolean,
-) => NodeRef | undefined
-
-export function createTemplateRefSetter(): setRefFn {
- const instance = currentInstance as VaporComponentInstance
- return (...args) => setRef(instance, ...args)
-}
-
-/**
- * Function for handling a template ref
- */
-export function setRef(
- instance: VaporComponentInstance,
- el: RefEl,
- ref: NodeRef,
- oldRef?: NodeRef,
- refFor = false,
-): NodeRef | undefined {
- if (!instance || instance.isUnmounted) return
-
- const setupState: any = __DEV__ ? instance.setupState || {} : null
- const refValue = getRefValue(el)
-
- const refs =
- instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs
-
- // dynamic ref changed. unset old ref
- if (oldRef != null && oldRef !== ref) {
- if (isString(oldRef)) {
- refs[oldRef] = null
- if (__DEV__ && 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, ErrorCodes.FUNCTION_REF, [
- value,
- refs,
- ])
- }
-
- invokeRefSetter(refValue)
- // TODO this gets called repeatedly in renderEffect when it's dynamic ref?
- onScopeDispose(() => invokeRefSetter())
- } else {
- const _isString = isString(ref)
- const _isRef = isRef(ref)
- let existing: unknown
-
- if (_isString || _isRef) {
- const doSet: SchedulerJob = () => {
- if (refFor) {
- existing = _isString
- ? __DEV__ && hasOwn(setupState, ref)
- ? setupState[ref]
- : refs[ref]
- : ref.value
-
- if (!isArray(existing)) {
- existing = [refValue]
- if (_isString) {
- refs[ref] = existing
- if (__DEV__ && 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 (__DEV__ && 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)
-
- // TODO this gets called repeatedly in renderEffect when it's dynamic ref?
- onScopeDispose(() => {
- queuePostFlushCb(() => {
- if (isArray(existing)) {
- remove(existing, refValue)
- } else if (_isString) {
- refs[ref] = null
- if (__DEV__ && 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
-}
-
-const getRefValue = (el: RefEl) => {
- if (isVaporComponent(el)) {
- return getExposed(el) || el
- } else if (el instanceof DynamicFragment) {
- return getRefValue(el.nodes as RefEl)
- }
- return el
-}
+++ /dev/null
-import { isArray } from '@vue/shared'
-import {
- type VaporComponentInstance,
- isVaporComponent,
- mountComponent,
- unmountComponent,
-} from './component'
-import { createComment, createTextNode } from './dom/node'
-import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
-import { isHydrating } from './dom/hydration'
-
-export type Block =
- | Node
- | VaporFragment
- | DynamicFragment
- | VaporComponentInstance
- | Block[]
-
-export type BlockFn = (...args: any[]) => Block
-
-export class VaporFragment {
- nodes: Block
- anchor?: Node
- insert?: (parent: ParentNode, anchor: Node | null) => void
- remove?: (parent?: ParentNode) => void
-
- constructor(nodes: Block) {
- this.nodes = nodes
- }
-}
-
-export class DynamicFragment extends VaporFragment {
- anchor: Node
- scope: EffectScope | undefined
- current?: BlockFn
- fallback?: BlockFn
-
- constructor(anchorLabel?: string) {
- super([])
- this.anchor =
- __DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode()
- }
-
- update(render?: BlockFn, key: any = render): void {
- if (key === this.current) {
- return
- }
- this.current = key
-
- pauseTracking()
- const parent = this.anchor.parentNode
-
- // teardown previous branch
- if (this.scope) {
- this.scope.stop()
- parent && remove(this.nodes, parent)
- }
-
- if (render) {
- this.scope = new EffectScope()
- this.nodes = this.scope.run(render) || []
- if (parent) insert(this.nodes, parent, this.anchor)
- } else {
- this.scope = undefined
- this.nodes = []
- }
-
- if (this.fallback && !isValidBlock(this.nodes)) {
- parent && remove(this.nodes, parent)
- this.nodes =
- (this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
- []
- parent && insert(this.nodes, parent, this.anchor)
- }
-
- resetTracking()
- }
-}
-
-export function isFragment(val: NonNullable<unknown>): val is VaporFragment {
- return val instanceof VaporFragment
-}
-
-export function isBlock(val: NonNullable<unknown>): val is Block {
- return (
- val instanceof Node ||
- isArray(val) ||
- isVaporComponent(val) ||
- isFragment(val)
- )
-}
-
-export function isValidBlock(block: Block): boolean {
- if (block instanceof Node) {
- return !(block instanceof Comment)
- } else if (isVaporComponent(block)) {
- return isValidBlock(block.block)
- } else if (isArray(block)) {
- return block.length > 0 && block.every(isValidBlock)
- } else {
- // fragment
- return isValidBlock(block.nodes)
- }
-}
-
-export function insert(
- block: Block,
- parent: ParentNode,
- anchor: Node | null | 0 = null, // 0 means prepend
-): void {
- anchor = anchor === 0 ? parent.firstChild : anchor
- if (block instanceof Node) {
- if (!isHydrating) {
- parent.insertBefore(block, anchor)
- }
- } else if (isVaporComponent(block)) {
- if (block.isMounted) {
- insert(block.block!, parent, anchor)
- } else {
- mountComponent(block, parent, anchor)
- }
- } else if (isArray(block)) {
- for (const b of block) {
- insert(b, parent, anchor)
- }
- } else {
- // fragment
- if (block.insert) {
- // TODO handle hydration for vdom interop
- block.insert(parent, anchor)
- } else {
- insert(block.nodes, parent, anchor)
- }
- if (block.anchor) insert(block.anchor, parent, anchor)
- }
-}
-
-export type InsertFn = typeof insert
-
-export function prepend(parent: ParentNode, ...blocks: Block[]): void {
- let i = blocks.length
- while (i--) insert(blocks[i], parent, 0)
-}
-
-export function remove(block: Block, parent?: ParentNode): void {
- if (block instanceof Node) {
- parent && parent.removeChild(block)
- } else if (isVaporComponent(block)) {
- unmountComponent(block, parent)
- } else if (isArray(block)) {
- for (let i = 0; i < block.length; i++) {
- remove(block[i], parent)
- }
- } else {
- // fragment
- if (block.remove) {
- block.remove(parent)
- } else {
- remove(block.nodes, parent)
- }
- if (block.anchor) remove(block.anchor, parent)
- if ((block as DynamicFragment).scope) {
- ;(block as DynamicFragment).scope!.stop()
- }
- }
-}
-
-/**
- * dev / test only
- */
-export function normalizeBlock(block: Block): Node[] {
- if (!__DEV__ && !__TEST__) {
- throw new Error(
- 'normalizeBlock should not be used in production code paths',
- )
- }
- const nodes: Node[] = []
- if (block instanceof Node) {
- nodes.push(block)
- } else if (isArray(block)) {
- block.forEach(child => nodes.push(...normalizeBlock(child)))
- } else if (isVaporComponent(block)) {
- nodes.push(...normalizeBlock(block.block!))
- } else {
- nodes.push(...normalizeBlock(block.nodes))
- block.anchor && nodes.push(block.anchor)
- }
- return nodes
-}
+++ /dev/null
-import {
- type ComponentInternalOptions,
- type ComponentPropsOptions,
- EffectScope,
- type EmitFn,
- type EmitsOptions,
- ErrorCodes,
- type GenericAppContext,
- type GenericComponentInstance,
- type LifecycleHook,
- type NormalizedPropsOptions,
- type ObjectEmitsOptions,
- type SuspenseBoundary,
- callWithErrorHandling,
- currentInstance,
- endMeasure,
- expose,
- nextUid,
- popWarningContext,
- pushWarningContext,
- queuePostFlushCb,
- registerHMR,
- simpleSetCurrentInstance,
- startMeasure,
- unregisterHMR,
- warn,
-} from '@vue/runtime-dom'
-import { type Block, DynamicFragment, insert, isBlock, remove } from './block'
-import {
- type ShallowRef,
- markRaw,
- onScopeDispose,
- pauseTracking,
- proxyRefs,
- resetTracking,
- unref,
-} from '@vue/reactivity'
-import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared'
-import {
- type DynamicPropsSource,
- type RawProps,
- getKeysFromRawProps,
- getPropsProxyHandlers,
- hasFallthroughAttrs,
- normalizePropsOptions,
- resolveDynamicProps,
- setupPropsValidation,
-} from './componentProps'
-import { renderEffect } from './renderEffect'
-import { emit, normalizeEmitsOptions } from './componentEmits'
-import { setDynamicProps } from './dom/prop'
-import {
- type DynamicSlotSource,
- type RawSlots,
- type StaticSlots,
- type VaporSlot,
- dynamicSlotsProxyHandlers,
- getSlot,
-} from './componentSlots'
-import { hmrReload, hmrRerender } from './hmr'
-import { isHydrating, locateHydrationNode } from './dom/hydration'
-import {
- insertionAnchor,
- insertionParent,
- resetInsertionState,
-} from './insertionState'
-
-export { currentInstance } from '@vue/runtime-dom'
-
-export type VaporComponent = FunctionalVaporComponent | ObjectVaporComponent
-
-export type VaporSetupFn = (
- props: any,
- ctx: Pick<VaporComponentInstance, 'slots' | 'attrs' | 'emit' | 'expose'>,
-) => Block | Record<string, any> | undefined
-
-export type FunctionalVaporComponent = VaporSetupFn &
- Omit<ObjectVaporComponent, 'setup'> & {
- displayName?: string
- } & SharedInternalOptions
-
-export interface ObjectVaporComponent
- extends ComponentInternalOptions,
- SharedInternalOptions {
- setup?: VaporSetupFn
- inheritAttrs?: boolean
- props?: ComponentPropsOptions
- emits?: EmitsOptions
- render?(
- ctx: any,
- props?: any,
- emit?: EmitFn,
- attrs?: any,
- slots?: Record<string, VaporSlot>,
- ): Block
-
- name?: string
- vapor?: boolean
-}
-
-interface SharedInternalOptions {
- /**
- * Cached normalized props options.
- * In vapor mode there are no mixins so normalized options can be cached
- * directly on the component
- */
- __propsOptions?: NormalizedPropsOptions
- /**
- * Cached normalized props proxy handlers.
- */
- __propsHandlers?: [ProxyHandler<any> | null, ProxyHandler<any>]
- /**
- * Cached normalized emits options.
- */
- __emitsOptions?: ObjectEmitsOptions
-}
-
-// In TypeScript, it is actually impossible to have a record type with only
-// specific properties that have a different type from the indexed type.
-// This makes our rawProps / rawSlots shape difficult to satisfy when calling
-// `createComponent` - luckily this is not user-facing, so we don't need to be
-// 100% strict. Here we use intentionally wider types to make `createComponent`
-// more ergonomic in tests and internal call sites, where we immediately cast
-// them into the stricter types.
-export type LooseRawProps = Record<
- string,
- (() => unknown) | DynamicPropsSource[]
-> & {
- $?: DynamicPropsSource[]
-}
-
-export type LooseRawSlots = Record<string, VaporSlot | DynamicSlotSource[]> & {
- $?: DynamicSlotSource[]
-}
-
-export function createComponent(
- component: VaporComponent,
- rawProps?: LooseRawProps | null,
- rawSlots?: LooseRawSlots | null,
- isSingleRoot?: boolean,
- appContext: GenericAppContext = (currentInstance &&
- currentInstance.appContext) ||
- emptyContext,
-): VaporComponentInstance {
- const _insertionParent = insertionParent
- const _insertionAnchor = insertionAnchor
- if (isHydrating) {
- locateHydrationNode()
- } else {
- resetInsertionState()
- }
-
- // vdom interop enabled and component is not an explicit vapor component
- if (appContext.vapor && !component.__vapor) {
- const frag = appContext.vapor.vdomMount(
- component as any,
- rawProps,
- rawSlots,
- )
- if (!isHydrating && _insertionParent) {
- insert(frag, _insertionParent, _insertionAnchor)
- }
- return frag
- }
-
- if (
- isSingleRoot &&
- component.inheritAttrs !== false &&
- isVaporComponent(currentInstance) &&
- currentInstance.hasFallthrough
- ) {
- // check if we are the single root of the parent
- // if yes, inject parent attrs as dynamic props source
- const attrs = currentInstance.attrs
- if (rawProps) {
- ;((rawProps as RawProps).$ || ((rawProps as RawProps).$ = [])).push(
- () => attrs,
- )
- } else {
- rawProps = { $: [() => attrs] } as RawProps
- }
- }
-
- const instance = new VaporComponentInstance(
- component,
- rawProps as RawProps,
- rawSlots as RawSlots,
- appContext,
- )
-
- if (__DEV__) {
- pushWarningContext(instance)
- startMeasure(instance, `init`)
-
- // cache normalized options for dev only emit check
- instance.propsOptions = normalizePropsOptions(component)
- instance.emitsOptions = normalizeEmitsOptions(component)
- }
-
- const prev = currentInstance
- simpleSetCurrentInstance(instance)
- pauseTracking()
-
- if (__DEV__) {
- setupPropsValidation(instance)
- }
-
- const setupFn = isFunction(component) ? component : component.setup
- const setupResult = setupFn
- ? callWithErrorHandling(setupFn, instance, ErrorCodes.SETUP_FUNCTION, [
- instance.props,
- instance,
- ]) || EMPTY_OBJ
- : EMPTY_OBJ
-
- if (__DEV__ && !isBlock(setupResult)) {
- if (isFunction(component)) {
- warn(`Functional vapor component must return a block directly.`)
- instance.block = []
- } else if (!component.render) {
- warn(
- `Vapor component setup() returned non-block value, and has no render function.`,
- )
- instance.block = []
- } else {
- instance.devtoolsRawSetupState = setupResult
- // TODO make the proxy warn non-existent property access during dev
- instance.setupState = proxyRefs(setupResult)
- devRender(instance)
-
- // HMR
- if (component.__hmrId) {
- registerHMR(instance)
- instance.isSingleRoot = isSingleRoot
- instance.hmrRerender = hmrRerender.bind(null, instance)
- instance.hmrReload = hmrReload.bind(null, instance)
- }
- }
- } else {
- // component has a render function but no setup function
- // (typically components with only a template and no state)
- if (!setupFn && component.render) {
- instance.block = callWithErrorHandling(
- component.render,
- instance,
- ErrorCodes.RENDER_FUNCTION,
- )
- } else {
- // in prod result can only be block
- instance.block = setupResult as Block
- }
- }
-
- // single root, inherit attrs
- if (
- instance.hasFallthrough &&
- component.inheritAttrs !== false &&
- Object.keys(instance.attrs).length
- ) {
- const el = getRootElement(instance)
- if (el) {
- renderEffect(() => {
- isApplyingFallthroughProps = true
- setDynamicProps(el, [instance.attrs])
- isApplyingFallthroughProps = false
- })
- }
- }
-
- resetTracking()
- simpleSetCurrentInstance(prev, instance)
-
- if (__DEV__) {
- popWarningContext()
- endMeasure(instance, 'init')
- }
-
- onScopeDispose(() => unmountComponent(instance), true)
-
- if (!isHydrating && _insertionParent) {
- mountComponent(instance, _insertionParent, _insertionAnchor)
- }
-
- return instance
-}
-
-export let isApplyingFallthroughProps = false
-
-/**
- * dev only
- */
-export function devRender(instance: VaporComponentInstance): void {
- instance.block =
- callWithErrorHandling(
- instance.type.render!,
- instance,
- ErrorCodes.RENDER_FUNCTION,
- [
- instance.setupState,
- instance.props,
- instance.emit,
- instance.attrs,
- instance.slots,
- ],
- ) || []
-}
-
-const emptyContext: GenericAppContext = {
- app: null as any,
- config: {},
- provides: /*@__PURE__*/ Object.create(null),
-}
-
-export class VaporComponentInstance implements GenericComponentInstance {
- vapor: true
- uid: number
- type: VaporComponent
- root: GenericComponentInstance | null
- parent: GenericComponentInstance | null
- appContext: GenericAppContext
-
- block: Block
- scope: EffectScope
-
- rawProps: RawProps
- rawSlots: RawSlots
-
- props: Record<string, any>
- attrs: Record<string, any>
- propsDefaults: Record<string, any> | null
-
- slots: StaticSlots
-
- // to hold vnode props / slots in vdom interop mode
- rawPropsRef?: ShallowRef<any>
- rawSlotsRef?: ShallowRef<any>
-
- emit: EmitFn
- emitted: Record<string, boolean> | null
-
- expose: (exposed: Record<string, any>) => void
- exposed: Record<string, any> | null
- exposeProxy: Record<string, any> | null
-
- // for useTemplateRef()
- refs: Record<string, any>
- // for provide / inject
- provides: Record<string, any>
- // for useId
- ids: [string, number, number]
- // for suspense
- suspense: SuspenseBoundary | null
-
- hasFallthrough: boolean
-
- // lifecycle hooks
- isMounted: boolean
- isUnmounted: boolean
- isDeactivated: boolean
- isUpdating: boolean
-
- bc?: LifecycleHook // LifecycleHooks.BEFORE_CREATE
- c?: LifecycleHook // LifecycleHooks.CREATED
- bm?: LifecycleHook // LifecycleHooks.BEFORE_MOUNT
- m?: LifecycleHook // LifecycleHooks.MOUNTED
- bu?: LifecycleHook // LifecycleHooks.BEFORE_UPDATE
- u?: LifecycleHook // LifecycleHooks.UPDATED
- um?: LifecycleHook // LifecycleHooks.BEFORE_UNMOUNT
- bum?: LifecycleHook // LifecycleHooks.UNMOUNTED
- da?: LifecycleHook // LifecycleHooks.DEACTIVATED
- a?: LifecycleHook // LifecycleHooks.ACTIVATED
- rtg?: LifecycleHook // LifecycleHooks.RENDER_TRACKED
- rtc?: LifecycleHook // LifecycleHooks.RENDER_TRIGGERED
- ec?: LifecycleHook // LifecycleHooks.ERROR_CAPTURED
- sp?: LifecycleHook<() => Promise<unknown>> // LifecycleHooks.SERVER_PREFETCH
-
- // dev only
- setupState?: Record<string, any>
- devtoolsRawSetupState?: any
- hmrRerender?: () => void
- hmrReload?: (newComp: VaporComponent) => void
- propsOptions?: NormalizedPropsOptions
- emitsOptions?: ObjectEmitsOptions | null
- isSingleRoot?: boolean
-
- constructor(
- comp: VaporComponent,
- rawProps?: RawProps | null,
- rawSlots?: RawSlots | null,
- appContext?: GenericAppContext,
- ) {
- this.vapor = true
- this.uid = nextUid()
- this.type = comp
- this.parent = currentInstance
- this.root = currentInstance ? currentInstance.root : this
-
- if (currentInstance) {
- this.appContext = currentInstance.appContext
- this.provides = currentInstance.provides
- this.ids = currentInstance.ids
- } else {
- this.appContext = appContext || emptyContext
- this.provides = Object.create(this.appContext.provides)
- this.ids = ['', 0, 0]
- }
-
- this.block = null! // to be set
- this.scope = new EffectScope(true)
-
- this.emit = emit.bind(null, this)
- this.expose = expose.bind(null, this)
- this.refs = EMPTY_OBJ
- this.emitted =
- this.exposed =
- this.exposeProxy =
- this.propsDefaults =
- this.suspense =
- null
-
- this.isMounted =
- this.isUnmounted =
- this.isUpdating =
- this.isDeactivated =
- false
-
- // init props
- this.rawProps = rawProps || EMPTY_OBJ
- this.hasFallthrough = hasFallthroughAttrs(comp, rawProps)
- if (rawProps || comp.props) {
- const [propsHandlers, attrsHandlers] = getPropsProxyHandlers(comp)
- this.attrs = new Proxy(this, attrsHandlers)
- this.props = comp.props
- ? new Proxy(this, propsHandlers!)
- : isFunction(comp)
- ? this.attrs
- : EMPTY_OBJ
- } else {
- this.props = this.attrs = EMPTY_OBJ
- }
-
- // init slots
- this.rawSlots = rawSlots || EMPTY_OBJ
- this.slots = rawSlots
- ? rawSlots.$
- ? new Proxy(rawSlots, dynamicSlotsProxyHandlers)
- : rawSlots
- : EMPTY_OBJ
- }
-
- /**
- * Expose `getKeysFromRawProps` on the instance so it can be used in code
- * paths where it's needed, e.g. `useModel`
- */
- rawKeys(): string[] {
- return getKeysFromRawProps(this.rawProps)
- }
-}
-
-export function isVaporComponent(
- value: unknown,
-): value is VaporComponentInstance {
- return value instanceof VaporComponentInstance
-}
-
-/**
- * Used when a component cannot be resolved at compile time
- * and needs rely on runtime resolution - where it might fallback to a plain
- * element if the resolution fails.
- */
-export function createComponentWithFallback(
- comp: VaporComponent | string,
- rawProps?: LooseRawProps | null,
- rawSlots?: LooseRawSlots | null,
- isSingleRoot?: boolean,
-): HTMLElement | VaporComponentInstance {
- if (!isString(comp)) {
- return createComponent(comp, rawProps, rawSlots, isSingleRoot)
- }
-
- const _insertionParent = insertionParent
- const _insertionAnchor = insertionAnchor
- if (isHydrating) {
- locateHydrationNode()
- } else {
- resetInsertionState()
- }
-
- const el = document.createElement(comp)
- // mark single root
- ;(el as any).$root = isSingleRoot
-
- if (rawProps) {
- renderEffect(() => {
- setDynamicProps(el, [resolveDynamicProps(rawProps as RawProps)])
- })
- }
-
- if (rawSlots) {
- if (rawSlots.$) {
- // TODO dynamic slot fragment
- } else {
- insert(getSlot(rawSlots as RawSlots, 'default')!(), el)
- }
- }
-
- if (!isHydrating && _insertionParent) {
- insert(el, _insertionParent, _insertionAnchor)
- }
-
- return el
-}
-
-export function mountComponent(
- instance: VaporComponentInstance,
- parent: ParentNode,
- anchor?: Node | null | 0,
-): void {
- if (__DEV__) {
- startMeasure(instance, `mount`)
- }
- if (instance.bm) invokeArrayFns(instance.bm)
- insert(instance.block, parent, anchor)
- if (instance.m) queuePostFlushCb(() => invokeArrayFns(instance.m!))
- instance.isMounted = true
- if (__DEV__) {
- endMeasure(instance, `mount`)
- }
-}
-
-export function unmountComponent(
- instance: VaporComponentInstance,
- parentNode?: ParentNode,
-): void {
- if (instance.isMounted && !instance.isUnmounted) {
- if (__DEV__ && instance.type.__hmrId) {
- unregisterHMR(instance)
- }
- if (instance.bum) {
- invokeArrayFns(instance.bum)
- }
-
- instance.scope.stop()
-
- if (instance.um) {
- queuePostFlushCb(() => invokeArrayFns(instance.um!))
- }
- instance.isUnmounted = true
- }
-
- if (parentNode) {
- remove(instance.block, parentNode)
- }
-}
-
-export function getExposed(
- instance: GenericComponentInstance,
-): Record<string, any> | undefined {
- if (instance.exposed) {
- return (
- instance.exposeProxy ||
- (instance.exposeProxy = new Proxy(markRaw(instance.exposed), {
- get: (target, key) => unref(target[key as any]),
- }))
- )
- }
-}
-
-function getRootElement({
- block,
-}: VaporComponentInstance): Element | undefined {
- if (block instanceof Element) {
- return block
- }
-
- if (block instanceof DynamicFragment) {
- const { nodes } = block
- if (nodes instanceof Element && (nodes as any).$root) {
- return nodes
- }
- }
-}
+++ /dev/null
-import { type ObjectEmitsOptions, baseEmit } from '@vue/runtime-dom'
-import type { VaporComponent, VaporComponentInstance } from './component'
-import { EMPTY_OBJ, hasOwn, isArray } from '@vue/shared'
-import { resolveSource } from './componentProps'
-
-/**
- * The logic from core isn't too reusable so it's better to duplicate here
- */
-export function normalizeEmitsOptions(
- comp: VaporComponent,
-): ObjectEmitsOptions | null {
- const cached = comp.__emitsOptions
- if (cached) return cached
-
- const raw = comp.emits
- if (!raw) return null
-
- let normalized: ObjectEmitsOptions
- if (isArray(raw)) {
- normalized = {}
- for (const key of raw) normalized[key] = null
- } else {
- normalized = raw
- }
-
- return (comp.__emitsOptions = normalized)
-}
-
-export function emit(
- instance: VaporComponentInstance,
- event: string,
- ...rawArgs: any[]
-): void {
- baseEmit(
- instance,
- instance.rawProps || EMPTY_OBJ,
- propGetter,
- event,
- ...rawArgs,
- )
-}
-
-function propGetter(rawProps: Record<string, any>, key: string) {
- const dynamicSources = rawProps.$
- if (dynamicSources) {
- let i = dynamicSources.length
- while (i--) {
- const source = resolveSource(dynamicSources[i])
- if (hasOwn(source, key)) return resolveSource(source[key])
- }
- }
- return rawProps[key] && resolveSource(rawProps[key])
-}
+++ /dev/null
-import {
- EMPTY_ARR,
- NO,
- YES,
- camelize,
- hasOwn,
- isArray,
- isFunction,
- isString,
-} from '@vue/shared'
-import type { VaporComponent, VaporComponentInstance } from './component'
-import {
- type NormalizedPropsOptions,
- baseNormalizePropsOptions,
- currentInstance,
- isEmitListener,
- popWarningContext,
- pushWarningContext,
- resolvePropValue,
- simpleSetCurrentInstance,
- validateProps,
- warn,
-} from '@vue/runtime-dom'
-import { ReactiveFlags } from '@vue/reactivity'
-import { normalizeEmitsOptions } from './componentEmits'
-import { renderEffect } from './renderEffect'
-
-export type RawProps = Record<string, () => unknown> & {
- // generated by compiler for :[key]="x" or v-bind="x"
- $?: DynamicPropsSource[]
-}
-
-export type DynamicPropsSource =
- | (() => Record<string, unknown>)
- | Record<string, () => unknown>
-
-// TODO optimization: maybe convert functions into computeds
-export function resolveSource(
- source: Record<string, any> | (() => Record<string, any>),
-): Record<string, any> {
- return isFunction(source) ? source() : source
-}
-
-export function getPropsProxyHandlers(
- comp: VaporComponent,
-): [
- ProxyHandler<VaporComponentInstance> | null,
- ProxyHandler<VaporComponentInstance>,
-] {
- if (comp.__propsHandlers) {
- return comp.__propsHandlers
- }
- const propsOptions = normalizePropsOptions(comp)[0]
- const emitsOptions = normalizeEmitsOptions(comp)
- const isProp = (
- propsOptions
- ? (key: string | symbol) =>
- isString(key) && hasOwn(propsOptions, camelize(key))
- : NO
- ) as (key: string | symbol) => key is string
- const isAttr = propsOptions
- ? (key: string) =>
- key !== '$' && !isProp(key) && !isEmitListener(emitsOptions, key)
- : YES
-
- const getProp = (instance: VaporComponentInstance, key: string | symbol) => {
- // this enables direct watching of props and prevents `Invalid watch source` DEV warnings.
- if (key === ReactiveFlags.IS_REACTIVE) return true
-
- if (!isProp(key)) return
- const rawProps = instance.rawProps
- const dynamicSources = rawProps.$
- if (dynamicSources) {
- let i = dynamicSources.length
- let source, isDynamic, rawKey
- while (i--) {
- source = dynamicSources[i]
- isDynamic = isFunction(source)
- source = isDynamic ? (source as Function)() : source
- for (rawKey in source) {
- if (camelize(rawKey) === key) {
- return resolvePropValue(
- propsOptions!,
- key,
- isDynamic ? source[rawKey] : source[rawKey](),
- instance,
- resolveDefault,
- )
- }
- }
- }
- }
- for (const rawKey in rawProps) {
- if (camelize(rawKey) === key) {
- return resolvePropValue(
- propsOptions!,
- key,
- rawProps[rawKey](),
- instance,
- resolveDefault,
- )
- }
- }
- return resolvePropValue(
- propsOptions!,
- key,
- undefined,
- instance,
- resolveDefault,
- true,
- )
- }
-
- const propsHandlers = propsOptions
- ? ({
- get: (target, key) => getProp(target, key),
- has: (_, key) => isProp(key),
- ownKeys: () => Object.keys(propsOptions),
- getOwnPropertyDescriptor(target, key) {
- if (isProp(key)) {
- return {
- configurable: true,
- enumerable: true,
- get: () => getProp(target, key),
- }
- }
- },
- } satisfies ProxyHandler<VaporComponentInstance>)
- : null
-
- if (__DEV__ && propsOptions) {
- Object.assign(propsHandlers!, {
- set: propsSetDevTrap,
- deleteProperty: propsDeleteDevTrap,
- })
- }
-
- const getAttr = (target: RawProps, key: string) => {
- if (!isProp(key) && !isEmitListener(emitsOptions, key)) {
- return getAttrFromRawProps(target, key)
- }
- }
-
- const hasAttr = (target: RawProps, key: string) => {
- if (isAttr(key)) {
- return hasAttrFromRawProps(target, key)
- } else {
- return false
- }
- }
-
- const attrsHandlers = {
- get: (target, key: string) => getAttr(target.rawProps, key),
- has: (target, key: string) => hasAttr(target.rawProps, key),
- ownKeys: target => getKeysFromRawProps(target.rawProps).filter(isAttr),
- getOwnPropertyDescriptor(target, key: string) {
- if (hasAttr(target.rawProps, key)) {
- return {
- configurable: true,
- enumerable: true,
- get: () => getAttr(target.rawProps, key),
- }
- }
- },
- } satisfies ProxyHandler<VaporComponentInstance>
-
- if (__DEV__) {
- Object.assign(attrsHandlers, {
- set: propsSetDevTrap,
- deleteProperty: propsDeleteDevTrap,
- })
- }
-
- return (comp.__propsHandlers = [propsHandlers, attrsHandlers])
-}
-
-export function getAttrFromRawProps(rawProps: RawProps, key: string): unknown {
- if (key === '$') return
- // need special merging behavior for class & style
- const merged = key === 'class' || key === 'style' ? ([] as any[]) : undefined
- const dynamicSources = rawProps.$
- if (dynamicSources) {
- let i = dynamicSources.length
- let source, isDynamic
- while (i--) {
- source = dynamicSources[i]
- isDynamic = isFunction(source)
- source = isDynamic ? (source as Function)() : source
- if (hasOwn(source, key)) {
- const value = isDynamic ? source[key] : source[key]()
- if (merged) {
- merged.push(value)
- } else {
- return value
- }
- }
- }
- }
- if (hasOwn(rawProps, key)) {
- if (merged) {
- merged.push(rawProps[key]())
- } else {
- return rawProps[key]()
- }
- }
- if (merged && merged.length) {
- return merged
- }
-}
-
-export function hasAttrFromRawProps(rawProps: RawProps, key: string): boolean {
- if (key === '$') return false
- const dynamicSources = rawProps.$
- if (dynamicSources) {
- let i = dynamicSources.length
- while (i--) {
- const source = resolveSource(dynamicSources[i])
- if (source && hasOwn(source, key)) {
- return true
- }
- }
- }
- return hasOwn(rawProps, key)
-}
-
-export function getKeysFromRawProps(rawProps: RawProps): string[] {
- const keys: string[] = []
- for (const key in rawProps) {
- if (key !== '$') keys.push(key)
- }
- const dynamicSources = rawProps.$
- if (dynamicSources) {
- let i = dynamicSources.length
- let source
- while (i--) {
- source = resolveSource(dynamicSources[i])
- for (const key in source) {
- keys.push(key)
- }
- }
- }
- return Array.from(new Set(keys))
-}
-
-export function normalizePropsOptions(
- comp: VaporComponent,
-): NormalizedPropsOptions {
- const cached = comp.__propsOptions
- if (cached) return cached
-
- const raw = comp.props
- if (!raw) return EMPTY_ARR as []
-
- const normalized: NormalizedPropsOptions[0] = {}
- const needCastKeys: NormalizedPropsOptions[1] = []
- baseNormalizePropsOptions(raw, normalized, needCastKeys)
-
- return (comp.__propsOptions = [normalized, needCastKeys])
-}
-
-function resolveDefault(
- factory: (props: Record<string, any>) => unknown,
- instance: VaporComponentInstance,
-) {
- const prev = currentInstance
- simpleSetCurrentInstance(instance)
- const res = factory.call(null, instance.props)
- simpleSetCurrentInstance(prev, instance)
- return res
-}
-
-export function hasFallthroughAttrs(
- comp: VaporComponent,
- rawProps: RawProps | null | undefined,
-): boolean {
- if (rawProps) {
- // determine fallthrough
- if (rawProps.$ || !comp.props) {
- return true
- } else {
- // check if rawProps contains any keys not declared
- const propsOptions = normalizePropsOptions(comp)[0]!
- for (const key in rawProps) {
- if (!hasOwn(propsOptions, camelize(key))) {
- return true
- }
- }
- }
- }
- return false
-}
-
-/**
- * dev only
- */
-export function setupPropsValidation(instance: VaporComponentInstance): void {
- const rawProps = instance.rawProps
- if (!rawProps) return
- renderEffect(() => {
- pushWarningContext(instance)
- validateProps(
- resolveDynamicProps(rawProps),
- instance.props,
- normalizePropsOptions(instance.type)[0]!,
- )
- popWarningContext()
- }, true /* noLifecycle */)
-}
-
-export function resolveDynamicProps(props: RawProps): Record<string, unknown> {
- const mergedRawProps: Record<string, any> = {}
- for (const key in props) {
- if (key !== '$') {
- mergedRawProps[key] = props[key]()
- }
- }
- if (props.$) {
- for (const source of props.$) {
- const isDynamic = isFunction(source)
- const resolved = isDynamic ? source() : source
- for (const key in resolved) {
- const value = isDynamic ? resolved[key] : (resolved[key] as Function)()
- if (key === 'class' || key === 'style') {
- const existing = mergedRawProps[key]
- if (isArray(existing)) {
- existing.push(value)
- } else {
- mergedRawProps[key] = [existing, value]
- }
- } else {
- mergedRawProps[key] = value
- }
- }
- }
- }
- return mergedRawProps
-}
-
-function propsSetDevTrap(_: any, key: string | symbol) {
- warn(
- `Attempt to mutate prop ${JSON.stringify(key)} failed. Props are readonly.`,
- )
- return true
-}
-
-function propsDeleteDevTrap(_: any, key: string | symbol) {
- warn(
- `Attempt to delete prop ${JSON.stringify(key)} failed. Props are readonly.`,
- )
- return true
-}
-
-export const rawPropsProxyHandlers: ProxyHandler<RawProps> = {
- get: getAttrFromRawProps,
- has: hasAttrFromRawProps,
- ownKeys: getKeysFromRawProps,
- getOwnPropertyDescriptor(target, key: string) {
- if (hasAttrFromRawProps(target, key)) {
- return {
- configurable: true,
- enumerable: true,
- get: () => getAttrFromRawProps(target, key),
- }
- }
- },
-}
+++ /dev/null
-import { EMPTY_OBJ, NO, hasOwn, isArray, isFunction } from '@vue/shared'
-import { type Block, type BlockFn, DynamicFragment, insert } from './block'
-import { rawPropsProxyHandlers } from './componentProps'
-import { currentInstance, isRef } from '@vue/runtime-dom'
-import type { LooseRawProps, VaporComponentInstance } from './component'
-import { renderEffect } from './renderEffect'
-import {
- insertionAnchor,
- insertionParent,
- resetInsertionState,
-} from './insertionState'
-import { isHydrating, locateHydrationNode } from './dom/hydration'
-
-export type RawSlots = Record<string, VaporSlot> & {
- $?: DynamicSlotSource[]
-}
-
-export type StaticSlots = Record<string, VaporSlot>
-
-export type VaporSlot = BlockFn
-export type DynamicSlot = { name: string; fn: VaporSlot }
-export type DynamicSlotFn = () => DynamicSlot | DynamicSlot[]
-export type DynamicSlotSource = StaticSlots | DynamicSlotFn
-
-export const dynamicSlotsProxyHandlers: ProxyHandler<RawSlots> = {
- get: getSlot,
- has: (target, key: string) => !!getSlot(target, key),
- getOwnPropertyDescriptor(target, key: string) {
- const slot = getSlot(target, key)
- if (slot) {
- return {
- configurable: true,
- enumerable: true,
- value: slot,
- }
- }
- },
- ownKeys(target) {
- let keys = Object.keys(target)
- const dynamicSources = target.$
- if (dynamicSources) {
- keys = keys.filter(k => k !== '$')
- for (const source of dynamicSources) {
- if (isFunction(source)) {
- const slot = source()
- if (isArray(slot)) {
- for (const s of slot) keys.push(String(s.name))
- } else {
- keys.push(String(slot.name))
- }
- } else {
- keys.push(...Object.keys(source))
- }
- }
- }
- return keys
- },
- set: NO,
- deleteProperty: NO,
-}
-
-export function getSlot(
- target: RawSlots,
- key: string,
-): (VaporSlot & { _bound?: VaporSlot }) | undefined {
- if (key === '$') return
- const dynamicSources = target.$
- if (dynamicSources) {
- let i = dynamicSources.length
- let source
- while (i--) {
- source = dynamicSources[i]
- if (isFunction(source)) {
- const slot = source()
- if (slot) {
- if (isArray(slot)) {
- for (const s of slot) {
- if (String(s.name) === key) return s.fn
- }
- } else if (String(slot.name) === key) {
- return slot.fn
- }
- }
- } else if (hasOwn(source, key)) {
- return source[key]
- }
- }
- }
- if (hasOwn(target, key)) {
- return target[key]
- }
-}
-
-export function createSlot(
- name: string | (() => string),
- rawProps?: LooseRawProps | null,
- fallback?: VaporSlot,
-): Block {
- const _insertionParent = insertionParent
- const _insertionAnchor = insertionAnchor
- if (isHydrating) {
- locateHydrationNode()
- } else {
- resetInsertionState()
- }
-
- const instance = currentInstance as VaporComponentInstance
- const rawSlots = instance.rawSlots
- const slotProps = rawProps
- ? new Proxy(rawProps, rawPropsProxyHandlers)
- : EMPTY_OBJ
-
- let fragment: DynamicFragment
-
- if (isRef(rawSlots._)) {
- fragment = instance.appContext.vapor!.vdomSlot(
- rawSlots._,
- name,
- slotProps,
- instance,
- fallback,
- )
- } else {
- fragment = __DEV__ ? new DynamicFragment('slot') : new DynamicFragment()
- const isDynamicName = isFunction(name)
- const renderSlot = () => {
- const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
- if (slot) {
- // create and cache bound version of the slot to make it stable
- // so that we avoid unnecessary updates if it resolves to the same slot
- fragment.update(
- slot._bound ||
- (slot._bound = () => {
- const slotContent = slot(slotProps)
- if (slotContent instanceof DynamicFragment) {
- slotContent.fallback = fallback
- }
- return slotContent
- }),
- )
- } else {
- fragment.update(fallback)
- }
- }
-
- // dynamic slot name or has dynamicSlots
- if (isDynamicName || rawSlots.$) {
- renderEffect(renderSlot)
- } else {
- renderSlot()
- }
- }
-
- if (!isHydrating && _insertionParent) {
- insert(fragment, _insertionParent, _insertionAnchor)
- }
-
- return fragment
-}
+++ /dev/null
-import { type DirectiveModifiers, onScopeDispose } from '@vue/runtime-dom'
-import type { VaporComponentInstance } from '../component'
-
-// !! vapor directive is different from vdom directives
-export type VaporDirective = (
- node: Element | VaporComponentInstance,
- value?: () => any,
- argument?: string,
- modifiers?: DirectiveModifiers,
-) => (() => void) | void
-
-type VaporDirectiveArguments = Array<
- | [VaporDirective | undefined]
- | [VaporDirective | undefined, () => any]
- | [VaporDirective | undefined, (() => any) | undefined, argument: string]
- | [
- VaporDirective | undefined,
- value: (() => any) | undefined,
- argument: string | undefined,
- modifiers: DirectiveModifiers,
- ]
->
-
-export function withVaporDirectives(
- node: Element | VaporComponentInstance,
- dirs: VaporDirectiveArguments,
-): void {
- // TODO handle custom directive on component
- for (const [dir, value, argument, modifiers] of dirs) {
- if (dir) {
- const ret = dir(node, value, argument, modifiers)
- if (ret) onScopeDispose(ret)
- }
- }
-}
+++ /dev/null
-import {
- currentInstance,
- onMounted,
- vModelCheckboxInit,
- vModelCheckboxUpdate,
- vModelGetValue,
- vModelSelectInit,
- vModelSetSelected,
- vModelTextInit,
- vModelTextUpdate,
-} from '@vue/runtime-dom'
-import { renderEffect } from '../renderEffect'
-import { looseEqual } from '@vue/shared'
-import { addEventListener } from '../dom/event'
-import { traverse } from '@vue/reactivity'
-
-type VaporModelDirective<
- T extends HTMLElement =
- | HTMLInputElement
- | HTMLTextAreaElement
- | HTMLSelectElement,
- Modifiers extends string = string,
-> = (
- el: T,
- get: () => any,
- set: (v: any) => void,
- modifiers?: { [key in Modifiers]?: true },
-) => void
-
-function ensureMounted(cb: () => void) {
- if (currentInstance!.isMounted) {
- cb()
- } else {
- onMounted(cb)
- }
-}
-
-export const applyTextModel: VaporModelDirective<
- HTMLInputElement | HTMLTextAreaElement,
- 'trim' | 'number' | 'lazy'
-> = (el, get, set, { trim, number, lazy } = {}) => {
- vModelTextInit(el, trim, number, lazy, set)
- ensureMounted(() => {
- let value: any
- renderEffect(() => {
- vModelTextUpdate(el, value, (value = get()), trim, number, lazy)
- })
- })
-}
-
-export const applyCheckboxModel: VaporModelDirective<HTMLInputElement> = (
- el,
- get,
- set,
-) => {
- vModelCheckboxInit(el, set)
- ensureMounted(() => {
- let value: any
- renderEffect(() => {
- vModelCheckboxUpdate(
- el,
- value,
- // #4096 array checkboxes need to be deep traversed
- traverse((value = get())),
- )
- })
- })
-}
-
-export const applyRadioModel: VaporModelDirective<HTMLInputElement> = (
- el,
- get,
- set,
-) => {
- addEventListener(el, 'change', () => set(vModelGetValue(el)))
- ensureMounted(() => {
- let value: any
- renderEffect(() => {
- if (value !== (value = get())) {
- el.checked = looseEqual(value, vModelGetValue(el))
- }
- })
- })
-}
-
-export const applySelectModel: VaporModelDirective<
- HTMLSelectElement,
- 'number'
-> = (el, get, set, modifiers) => {
- vModelSelectInit(el, get(), modifiers && modifiers.number, set)
- ensureMounted(() => {
- renderEffect(() => vModelSetSelected(el, traverse(get())))
- })
-}
-
-export const applyDynamicModel: VaporModelDirective = (
- el,
- get,
- set,
- modifiers,
-) => {
- let apply: VaporModelDirective<any> = applyTextModel
- if (el.tagName === 'SELECT') {
- apply = applySelectModel
- } else if (el.tagName === 'TEXTAREA') {
- apply = applyTextModel
- } else if ((el as HTMLInputElement).type === 'checkbox') {
- apply = applyCheckboxModel
- } else if ((el as HTMLInputElement).type === 'radio') {
- apply = applyRadioModel
- }
- apply(el, get, set, modifiers)
-}
+++ /dev/null
-import {
- type VShowElement,
- vShowHidden,
- vShowOriginalDisplay,
- warn,
-} from '@vue/runtime-dom'
-import { renderEffect } from '../renderEffect'
-import { isVaporComponent } from '../component'
-import { type Block, DynamicFragment } from '../block'
-import { isArray } from '@vue/shared'
-
-export function applyVShow(target: Block, source: () => any): void {
- if (isVaporComponent(target)) {
- return applyVShow(target.block, source)
- }
-
- if (isArray(target) && target.length === 1) {
- return applyVShow(target[0], source)
- }
-
- if (target instanceof DynamicFragment) {
- const update = target.update
- target.update = (render, key) => {
- update.call(target, render, key)
- setDisplay(target, source())
- }
- }
-
- renderEffect(() => setDisplay(target, source()))
-}
-
-function setDisplay(target: Block, value: unknown): void {
- if (isVaporComponent(target)) {
- return setDisplay(target, value)
- }
- if (isArray(target) && target.length === 1) {
- return setDisplay(target[0], value)
- }
- if (target instanceof DynamicFragment) {
- return setDisplay(target.nodes, value)
- }
- if (target instanceof Element) {
- const el = target as VShowElement
- if (!(vShowOriginalDisplay in el)) {
- el[vShowOriginalDisplay] =
- el.style.display === 'none' ? '' : el.style.display
- }
- el.style.display = value ? el[vShowOriginalDisplay]! : 'none'
- el[vShowHidden] = !value
- } else if (__DEV__) {
- warn(
- `v-show used on component with non-single-element root node ` +
- `and will be ignored.`,
- )
- }
-}
+++ /dev/null
-import { onEffectCleanup } from '@vue/reactivity'
-import { isArray } from '@vue/shared'
-
-export function addEventListener(
- el: Element,
- event: string,
- handler: (...args: any) => any,
- options?: AddEventListenerOptions,
-) {
- el.addEventListener(event, handler, options)
- return (): void => el.removeEventListener(event, handler, options)
-}
-
-export function on(
- el: Element,
- event: string,
- handler: (e: Event) => any,
- options: AddEventListenerOptions & { effect?: boolean } = {},
-): void {
- addEventListener(el, event, handler, options)
- if (options.effect) {
- onEffectCleanup(() => {
- el.removeEventListener(event, handler, options)
- })
- }
-}
-
-export function delegate(
- el: any,
- event: string,
- handler: (e: Event) => any,
-): void {
- const key = `$evt${event}`
- const existing = el[key]
- if (existing) {
- if (isArray(existing)) {
- existing.push(handler)
- } else {
- el[key] = [existing, handler]
- }
- } else {
- el[key] = handler
- }
-}
-
-type DelegatedHandler = {
- (...args: any[]): any
-}
-
-/**
- * Event delegation borrowed from solid
- */
-const delegatedEvents = Object.create(null)
-
-export const delegateEvents = (...names: string[]): void => {
- for (const name of names) {
- if (!delegatedEvents[name]) {
- delegatedEvents[name] = true
- document.addEventListener(name, delegatedEventHandler)
- }
- }
-}
-
-const delegatedEventHandler = (e: Event) => {
- let node = ((e.composedPath && e.composedPath()[0]) || e.target) as any
- if (e.target !== node) {
- Object.defineProperty(e, 'target', {
- configurable: true,
- value: node,
- })
- }
- Object.defineProperty(e, 'currentTarget', {
- configurable: true,
- get() {
- return node || document
- },
- })
- while (node !== null) {
- const handlers = node[`$evt${e.type}`] as
- | DelegatedHandler
- | DelegatedHandler[]
- if (handlers) {
- if (isArray(handlers)) {
- for (const handler of handlers) {
- if (!node.disabled) {
- handler(e)
- if (e.cancelBubble) return
- }
- }
- } else {
- handlers(e)
- if (e.cancelBubble) return
- }
- }
- node =
- node.host && node.host !== node && node.host instanceof Node
- ? node.host
- : node.parentNode
- }
-}
-
-export function setDynamicEvents(
- el: HTMLElement,
- events: Record<string, (...args: any[]) => any>,
-): void {
- for (const name in events) {
- on(el, name, events[name], { effect: true })
- }
-}
+++ /dev/null
-import { warn } from '@vue/runtime-dom'
-import {
- insertionAnchor,
- insertionParent,
- resetInsertionState,
- setInsertionState,
-} from '../insertionState'
-import { child, next } from './node'
-
-export let isHydrating = false
-export let currentHydrationNode: Node | null = null
-
-export function setCurrentHydrationNode(node: Node | null): void {
- currentHydrationNode = node
-}
-
-let isOptimized = false
-
-export function withHydration(container: ParentNode, fn: () => void): void {
- adoptTemplate = adoptTemplateImpl
- locateHydrationNode = locateHydrationNodeImpl
- if (!isOptimized) {
- // optimize anchor cache lookup
- ;(Comment.prototype as any).$fs = undefined
- isOptimized = true
- }
- isHydrating = true
- setInsertionState(container, 0)
- const res = fn()
- resetInsertionState()
- currentHydrationNode = null
- isHydrating = false
- return res
-}
-
-export let adoptTemplate: (node: Node, template: string) => Node | null
-export let locateHydrationNode: () => void
-
-type Anchor = Comment & {
- // cached matching fragment start to avoid repeated traversal
- // on nested fragments
- $fs?: Anchor
-}
-
-const isComment = (node: Node, data: string): node is Anchor =>
- node.nodeType === 8 && (node as Comment).data === data
-
-/**
- * Locate the first non-fragment-comment node and locate the next node
- * while handling potential fragments.
- */
-function adoptTemplateImpl(node: Node, template: string): Node | null {
- if (!(template[0] === '<' && template[1] === '!')) {
- while (node.nodeType === 8) node = next(node)
- }
-
- if (__DEV__) {
- const type = node.nodeType
- if (
- (type === 8 && !template.startsWith('<!')) ||
- (type === 1 &&
- !template.startsWith(`<` + (node as Element).tagName.toLowerCase())) ||
- (type === 3 &&
- template.trim() &&
- !template.startsWith((node as Text).data))
- ) {
- // TODO recover and provide more info
- warn(`adopted: `, node)
- warn(`template: ${template}`)
- warn('hydration mismatch!')
- }
- }
-
- currentHydrationNode = next(node)
- return node
-}
-
-function locateHydrationNodeImpl() {
- let node: Node | null
-
- // prepend / firstChild
- if (insertionAnchor === 0) {
- node = child(insertionParent!)
- } else {
- node = insertionAnchor
- ? insertionAnchor.previousSibling
- : insertionParent
- ? insertionParent.lastChild
- : currentHydrationNode
-
- if (node && isComment(node, ']')) {
- // fragment backward search
- if (node.$fs) {
- // already cached matching fragment start
- node = node.$fs
- } else {
- let cur: Node | null = node
- let curFragEnd = node
- let fragDepth = 0
- node = null
- while (cur) {
- cur = cur.previousSibling
- if (cur) {
- if (isComment(cur, '[')) {
- curFragEnd.$fs = cur
- if (!fragDepth) {
- node = cur
- break
- } else {
- fragDepth--
- }
- } else if (isComment(cur, ']')) {
- curFragEnd = cur
- fragDepth++
- }
- }
- }
- }
- }
- }
-
- if (__DEV__ && !node) {
- // TODO more info
- warn('Hydration mismatch in ', insertionParent)
- }
-
- resetInsertionState()
- currentHydrationNode = node
-}
+++ /dev/null
-/*! #__NO_SIDE_EFFECTS__ */
-export function createTextNode(value = ''): Text {
- return document.createTextNode(value)
-}
-
-/*! #__NO_SIDE_EFFECTS__ */
-export function createComment(data: string): Comment {
- return document.createComment(data)
-}
-
-/*! #__NO_SIDE_EFFECTS__ */
-export function querySelector(selectors: string): Element | null {
- return document.querySelector(selectors)
-}
-
-/*! #__NO_SIDE_EFFECTS__ */
-export function child(node: ParentNode): Node {
- return node.firstChild!
-}
-
-/*! #__NO_SIDE_EFFECTS__ */
-export function nthChild(node: Node, i: number): Node {
- return node.childNodes[i]
-}
-
-/*! #__NO_SIDE_EFFECTS__ */
-export function next(node: Node): Node {
- return node.nextSibling!
-}
+++ /dev/null
-import {
- type NormalizedStyle,
- canSetValueDirectly,
- isOn,
- isString,
- normalizeClass,
- normalizeStyle,
- parseStringStyle,
- toDisplayString,
-} from '@vue/shared'
-import { on } from './event'
-import {
- currentInstance,
- mergeProps,
- patchStyle,
- shouldSetAsProp,
- warn,
-} from '@vue/runtime-dom'
-import {
- type VaporComponentInstance,
- isApplyingFallthroughProps,
-} from '../component'
-
-type TargetElement = Element & {
- $root?: true
- $html?: string
- $cls?: string
- $sty?: NormalizedStyle | string | undefined
- value?: string
- _value?: any
-}
-
-const hasFallthroughKey = (key: string) =>
- (currentInstance as VaporComponentInstance).hasFallthrough &&
- key in currentInstance!.attrs
-
-export function setProp(el: any, key: string, value: any): void {
- if (key in el) {
- setDOMProp(el, key, value)
- } else {
- setAttr(el, key, value)
- }
-}
-
-export function setAttr(el: any, key: string, value: any): void {
- if (!isApplyingFallthroughProps && el.$root && hasFallthroughKey(key)) {
- return
- }
-
- // special case for <input v-model type="checkbox"> with
- // :true-value & :false-value
- // store value as dom properties since non-string values will be
- // stringified.
- if (key === 'true-value') {
- ;(el as any)._trueValue = value
- } else if (key === 'false-value') {
- ;(el as any)._falseValue = value
- }
-
- if (value !== el[`$${key}`]) {
- el[`$${key}`] = value
- if (value != null) {
- el.setAttribute(key, value)
- } else {
- el.removeAttribute(key)
- }
- }
-}
-
-export function setDOMProp(el: any, key: string, value: any): void {
- if (!isApplyingFallthroughProps && el.$root && hasFallthroughKey(key)) {
- return
- }
-
- const prev = el[key]
- if (value === prev) {
- return
- }
-
- let needRemove = false
- if (value === '' || value == null) {
- const type = typeof prev
- if (value == null && type === 'string') {
- // e.g. <div :id="null">
- value = ''
- needRemove = true
- } else if (type === 'number') {
- // e.g. <img :width="null">
- value = 0
- needRemove = true
- }
- }
-
- // some properties perform value validation and throw,
- // some properties has getter, no setter, will error in 'use strict'
- // eg. <select :type="null"></select> <select :willValidate="null"></select>
- try {
- el[key] = value
- } catch (e: any) {
- // do not warn if value is auto-coerced from nullish values
- if (__DEV__ && !needRemove) {
- warn(
- `Failed setting prop "${key}" on <${el.tagName.toLowerCase()}>: ` +
- `value ${value} is invalid.`,
- e,
- )
- }
- }
- needRemove && el.removeAttribute(key)
-}
-
-export function setClass(el: TargetElement, value: any): void {
- if (el.$root) {
- setClassIncremental(el, value)
- } else if ((value = normalizeClass(value)) !== el.$cls) {
- el.className = el.$cls = value
- }
-}
-
-function setClassIncremental(el: any, value: any): void {
- const cacheKey = `$clsi${isApplyingFallthroughProps ? '$' : ''}`
- const prev = el[cacheKey]
- if ((value = el[cacheKey] = normalizeClass(value)) !== prev) {
- const nextList = value.split(/\s+/)
- if (value) {
- el.classList.add(...nextList)
- }
- if (prev) {
- for (const cls of prev.split(/\s+/)) {
- if (!nextList.includes(cls)) el.classList.remove(cls)
- }
- }
- }
-}
-
-export function setStyle(el: TargetElement, value: any): void {
- if (el.$root) {
- setStyleIncremental(el, value)
- } else {
- const prev = el.$sty
- value = el.$sty = normalizeStyle(value)
- patchStyle(el, prev, value)
- }
-}
-
-function setStyleIncremental(el: any, value: any): NormalizedStyle | undefined {
- const cacheKey = `$styi${isApplyingFallthroughProps ? '$' : ''}`
- const prev = el[cacheKey]
- value = el[cacheKey] = isString(value)
- ? parseStringStyle(value)
- : (normalizeStyle(value) as NormalizedStyle | undefined)
- patchStyle(el, prev, value)
- return value
-}
-
-export function setValue(el: TargetElement, value: any): void {
- if (!isApplyingFallthroughProps && el.$root && hasFallthroughKey('value')) {
- return
- }
-
- // store value as _value as well since
- // non-string values will be stringified.
- el._value = value
- // #4956: <option> value will fallback to its text content so we need to
- // compare against its attribute value instead.
- const oldValue = el.tagName === 'OPTION' ? el.getAttribute('value') : el.value
- const newValue = value == null ? '' : value
- if (oldValue !== newValue) {
- el.value = newValue
- }
- if (value == null) {
- el.removeAttribute('value')
- }
-}
-
-/**
- * Only called on text nodes!
- * Compiler should also ensure value passed here is already converted by
- * `toDisplayString`
- */
-export function setText(el: Text & { $txt?: string }, value: string): void {
- if (el.$txt !== value) {
- el.nodeValue = el.$txt = value
- }
-}
-
-/**
- * Used by setDynamicProps only, so need to guard with `toDisplayString`
- */
-export function setElementText(
- el: Node & { $txt?: string },
- value: unknown,
-): void {
- if (el.$txt !== (value = toDisplayString(value))) {
- el.textContent = el.$txt = value as string
- }
-}
-
-export function setHtml(el: TargetElement, value: any): void {
- value = value == null ? '' : value
- if (el.$html !== value) {
- el.innerHTML = el.$html = value
- }
-}
-
-export function setDynamicProps(el: any, args: any[]): void {
- const props = args.length > 1 ? mergeProps(...args) : args[0]
- const cacheKey = `$dprops${isApplyingFallthroughProps ? '$' : ''}`
- const prevKeys = el[cacheKey] as string[]
-
- if (prevKeys) {
- for (const key of prevKeys) {
- if (!(key in props)) {
- setDynamicProp(el, key, null)
- }
- }
- }
-
- for (const key of (el[cacheKey] = Object.keys(props))) {
- setDynamicProp(el, key, props[key])
- }
-}
-
-/**
- * @internal
- */
-export function setDynamicProp(
- el: TargetElement,
- key: string,
- value: any,
-): void {
- // TODO
- const isSVG = false
- if (key === 'class') {
- setClass(el, value)
- } else if (key === 'style') {
- setStyle(el, value)
- } else if (isOn(key)) {
- on(el, key[2].toLowerCase() + key.slice(3), value, { effect: true })
- } else if (
- key[0] === '.'
- ? ((key = key.slice(1)), true)
- : key[0] === '^'
- ? ((key = key.slice(1)), false)
- : shouldSetAsProp(el, key, value, isSVG)
- ) {
- if (key === 'innerHTML') {
- setHtml(el, value)
- } else if (key === 'textContent') {
- setElementText(el, value)
- } else if (key === 'value' && canSetValueDirectly(el.tagName)) {
- setValue(el, value)
- } else {
- setDOMProp(el, key, value)
- }
- } else {
- // TODO special case for <input v-model type="checkbox">
- setAttr(el, key, value)
- }
- return value
-}
-
-let isOptimized = false
-
-/**
- * Optimize property lookup for cache properties on Element and Text nodes
- */
-export function optimizePropertyLookup(): void {
- if (isOptimized) return
- isOptimized = true
- const proto = Element.prototype as any
- proto.$evtclick = undefined
- proto.$root = false
- proto.$html =
- proto.$txt =
- proto.$cls =
- proto.$sty =
- (Text.prototype as any).$txt =
- ''
-}
+++ /dev/null
-import { adoptTemplate, currentHydrationNode, isHydrating } from './hydration'
-import { child, createTextNode } from './node'
-
-let t: HTMLTemplateElement
-
-/*! #__NO_SIDE_EFFECTS__ */
-export function template(html: string, root?: boolean) {
- let node: Node
- return (): Node & { $root?: true } => {
- if (isHydrating) {
- if (__DEV__ && !currentHydrationNode) {
- // TODO this should not happen
- throw new Error('No current hydration node')
- }
- return adoptTemplate(currentHydrationNode!, html)!
- }
- // fast path for text nodes
- if (html[0] !== '<') {
- return createTextNode(html)
- }
- if (!node) {
- t = t || document.createElement('template')
- t.innerHTML = html
- node = child(t.content)
- }
- const ret = node.cloneNode(true)
- if (root) (ret as any).$root = true
- return ret
- }
-}
+++ /dev/null
-import {
- currentInstance,
- popWarningContext,
- pushWarningContext,
- simpleSetCurrentInstance,
-} from '@vue/runtime-dom'
-import { insert, normalizeBlock, remove } from './block'
-import {
- type VaporComponent,
- type VaporComponentInstance,
- createComponent,
- devRender,
- mountComponent,
- unmountComponent,
-} from './component'
-
-export function hmrRerender(instance: VaporComponentInstance): void {
- const normalized = normalizeBlock(instance.block)
- const parent = normalized[0].parentNode!
- const anchor = normalized[normalized.length - 1].nextSibling
- remove(instance.block, parent)
- const prev = currentInstance
- simpleSetCurrentInstance(instance)
- pushWarningContext(instance)
- devRender(instance)
- popWarningContext()
- simpleSetCurrentInstance(prev, instance)
- insert(instance.block, parent, anchor)
-}
-
-export function hmrReload(
- instance: VaporComponentInstance,
- newComp: VaporComponent,
-): void {
- const normalized = normalizeBlock(instance.block)
- const parent = normalized[0].parentNode!
- const anchor = normalized[normalized.length - 1].nextSibling
- unmountComponent(instance, parent)
- const prev = currentInstance
- simpleSetCurrentInstance(instance.parent)
- const newInstance = createComponent(
- newComp,
- instance.rawProps,
- instance.rawSlots,
- instance.isSingleRoot,
- )
- simpleSetCurrentInstance(prev, instance.parent)
- mountComponent(newInstance, parent, anchor)
-}
+++ /dev/null
-// public APIs
-export { createVaporApp, createVaporSSRApp } from './apiCreateApp'
-export { defineVaporComponent } from './apiDefineComponent'
-export { vaporInteropPlugin } from './vdomInterop'
-export type { VaporDirective } from './directives/custom'
-
-// compiler-use only
-export { insert, prepend, remove, isFragment, VaporFragment } from './block'
-export { setInsertionState } from './insertionState'
-export { createComponent, createComponentWithFallback } from './component'
-export { renderEffect } from './renderEffect'
-export { createSlot } from './componentSlots'
-export { template } from './dom/template'
-export { createTextNode, child, nthChild, next } from './dom/node'
-export {
- setText,
- setHtml,
- setClass,
- setStyle,
- setAttr,
- setValue,
- setProp,
- setDOMProp,
- setDynamicProps,
-} from './dom/prop'
-export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
-export { createIf } from './apiCreateIf'
-export {
- createFor,
- createForSlots,
- getRestElement,
- getDefaultValue,
-} from './apiCreateFor'
-export { createTemplateRefSetter } from './apiTemplateRef'
-export { createDynamicComponent } from './apiCreateDynamicComponent'
-export { applyVShow } from './directives/vShow'
-export {
- applyTextModel,
- applyRadioModel,
- applyCheckboxModel,
- applySelectModel,
- applyDynamicModel,
-} from './directives/vModel'
-export { withVaporDirectives } from './directives/custom'
+++ /dev/null
-export let insertionParent: ParentNode | undefined
-export let insertionAnchor: Node | 0 | undefined
-
-/**
- * This function is called before a block type that requires insertion
- * (component, slot outlet, if, for) is created. The state is used for actual
- * insertion on client-side render, and used for node adoption during hydration.
- */
-export function setInsertionState(parent: ParentNode, anchor?: Node | 0): void {
- insertionParent = parent
- insertionAnchor = anchor
-}
-
-export function resetInsertionState(): void {
- insertionParent = insertionAnchor = undefined
-}
+++ /dev/null
-import { ReactiveEffect, getCurrentScope } from '@vue/reactivity'
-import {
- type SchedulerJob,
- currentInstance,
- queueJob,
- queuePostFlushCb,
- simpleSetCurrentInstance,
- startMeasure,
- warn,
-} from '@vue/runtime-dom'
-import { type VaporComponentInstance, isVaporComponent } from './component'
-import { invokeArrayFns } from '@vue/shared'
-
-export function renderEffect(fn: () => void, noLifecycle = false): void {
- const instance = currentInstance as VaporComponentInstance | null
- const scope = getCurrentScope()
- if (__DEV__ && !__TEST__ && !scope && !isVaporComponent(instance)) {
- warn('renderEffect called without active EffectScope or Vapor instance.')
- }
-
- // renderEffect is always called after user has registered all hooks
- const hasUpdateHooks = instance && (instance.bu || instance.u)
- const renderEffectFn = noLifecycle
- ? fn
- : () => {
- if (__DEV__ && instance) {
- startMeasure(instance, `renderEffect`)
- }
- const prev = currentInstance
- simpleSetCurrentInstance(instance)
- if (scope) scope.on()
- if (hasUpdateHooks && instance.isMounted && !instance.isUpdating) {
- instance.isUpdating = true
- instance.bu && invokeArrayFns(instance.bu)
- fn()
- queuePostFlushCb(() => {
- instance.isUpdating = false
- instance.u && invokeArrayFns(instance.u)
- })
- } else {
- fn()
- }
- if (scope) scope.off()
- simpleSetCurrentInstance(prev, instance)
- if (__DEV__ && instance) {
- startMeasure(instance, `renderEffect`)
- }
- }
-
- const effect = new ReactiveEffect(renderEffectFn)
- const job: SchedulerJob = () => effect.dirty && effect.run()
-
- if (instance) {
- if (__DEV__) {
- effect.onTrack = instance.rtc
- ? e => invokeArrayFns(instance.rtc!, e)
- : void 0
- effect.onTrigger = instance.rtg
- ? e => invokeArrayFns(instance.rtg!, e)
- : void 0
- }
- job.i = instance
- job.id = instance.uid
- }
-
- effect.scheduler = () => queueJob(job)
- effect.run()
-
- // TODO recurse handling
-}
+++ /dev/null
-import {
- type App,
- type ComponentInternalInstance,
- type ConcreteComponent,
- MoveType,
- type Plugin,
- type RendererInternals,
- type ShallowRef,
- type Slots,
- type VNode,
- type VaporInteropInterface,
- createInternalObject,
- createVNode,
- currentInstance,
- ensureRenderer,
- isEmitListener,
- onScopeDispose,
- renderSlot,
- shallowReactive,
- shallowRef,
- simpleSetCurrentInstance,
-} from '@vue/runtime-dom'
-import {
- type LooseRawProps,
- type LooseRawSlots,
- type VaporComponent,
- VaporComponentInstance,
- createComponent,
- mountComponent,
- unmountComponent,
-} from './component'
-import { type Block, VaporFragment, insert, remove } from './block'
-import { EMPTY_OBJ, extend, isFunction } from '@vue/shared'
-import { type RawProps, rawPropsProxyHandlers } from './componentProps'
-import type { RawSlots, VaporSlot } from './componentSlots'
-import { renderEffect } from './renderEffect'
-import { createTextNode } from './dom/node'
-import { optimizePropertyLookup } from './dom/prop'
-
-// mounting vapor components and slots in vdom
-const vaporInteropImpl: Omit<
- VaporInteropInterface,
- 'vdomMount' | 'vdomUnmount' | 'vdomSlot'
-> = {
- mount(vnode, container, anchor, parentComponent) {
- const selfAnchor = (vnode.el = vnode.anchor = createTextNode())
- container.insertBefore(selfAnchor, anchor)
- const prev = currentInstance
- simpleSetCurrentInstance(parentComponent)
-
- const propsRef = shallowRef(vnode.props)
- const slotsRef = shallowRef(vnode.children)
-
- // @ts-expect-error
- const instance = (vnode.component = createComponent(
- vnode.type as any as VaporComponent,
- {
- $: [() => propsRef.value],
- } as RawProps,
- {
- _: slotsRef, // pass the slots ref
- } as any as RawSlots,
- ))
- instance.rawPropsRef = propsRef
- instance.rawSlotsRef = slotsRef
- mountComponent(instance, container, selfAnchor)
- simpleSetCurrentInstance(prev)
- return instance
- },
-
- update(n1, n2, shouldUpdate) {
- n2.component = n1.component
- n2.el = n2.anchor = n1.anchor
- if (shouldUpdate) {
- const instance = n2.component as any as VaporComponentInstance
- instance.rawPropsRef!.value = n2.props
- instance.rawSlotsRef!.value = n2.children
- }
- },
-
- unmount(vnode, doRemove) {
- const container = doRemove ? vnode.anchor!.parentNode : undefined
- if (vnode.component) {
- unmountComponent(vnode.component as any, container)
- } else if (vnode.vb) {
- remove(vnode.vb, container)
- }
- remove(vnode.anchor as Node, container)
- },
-
- /**
- * vapor slot in vdom
- */
- slot(n1: VNode, n2: VNode, container, anchor) {
- if (!n1) {
- // mount
- const selfAnchor = (n2.el = n2.anchor = createTextNode())
- insert(selfAnchor, container, anchor)
- const { slot, fallback } = n2.vs!
- const propsRef = (n2.vs!.ref = shallowRef(n2.props))
- const slotBlock = slot(new Proxy(propsRef, vaporSlotPropsProxyHandler))
- // TODO fallback for slot with v-if content
- // fallback is a vnode slot function here, and slotBlock, if a DynamicFragment,
- // expects a Vapor BlockFn as fallback
- fallback
- insert((n2.vb = slotBlock), container, selfAnchor)
- } else {
- // update
- n2.el = n2.anchor = n1.anchor
- n2.vb = n1.vb
- ;(n2.vs!.ref = n1.vs!.ref)!.value = n2.props
- }
- },
-
- move(vnode, container, anchor) {
- insert(vnode.vb || (vnode.component as any), container, anchor)
- insert(vnode.anchor as any, container, anchor)
- },
-}
-
-const vaporSlotPropsProxyHandler: ProxyHandler<
- ShallowRef<Record<string, any>>
-> = {
- get(target, key: any) {
- return target.value[key]
- },
- has(target, key: any) {
- return target.value[key]
- },
- ownKeys(target) {
- return Object.keys(target.value)
- },
-}
-
-const vaporSlotsProxyHandler: ProxyHandler<any> = {
- get(target, key) {
- if (key === '_vapor') {
- return target
- } else {
- return target[key]
- }
- },
-}
-
-/**
- * Mount vdom component in vapor
- */
-function createVDOMComponent(
- internals: RendererInternals,
- component: ConcreteComponent,
- rawProps?: LooseRawProps | null,
- rawSlots?: LooseRawSlots | null,
-): VaporFragment {
- const frag = new VaporFragment([])
- const vnode = createVNode(
- component,
- rawProps && new Proxy(rawProps, rawPropsProxyHandlers),
- )
- const wrapper = new VaporComponentInstance(
- { props: component.props },
- rawProps as RawProps,
- rawSlots as RawSlots,
- )
-
- // overwrite how the vdom instance handles props
- vnode.vi = (instance: ComponentInternalInstance) => {
- // ensure props are shallow reactive to align with VDOM behavior.
- instance.props = shallowReactive(wrapper.props)
-
- const attrs = (instance.attrs = createInternalObject())
- for (const key in wrapper.attrs) {
- if (!isEmitListener(instance.emitsOptions, key)) {
- attrs[key] = wrapper.attrs[key]
- }
- }
-
- instance.slots =
- wrapper.slots === EMPTY_OBJ
- ? EMPTY_OBJ
- : new Proxy(wrapper.slots, vaporSlotsProxyHandler)
- }
-
- let isMounted = false
- const parentInstance = currentInstance as VaporComponentInstance
- const unmount = (parentNode?: ParentNode) => {
- internals.umt(vnode.component!, null, !!parentNode)
- }
-
- frag.insert = (parentNode, anchor) => {
- if (!isMounted) {
- internals.mt(
- vnode,
- parentNode,
- anchor,
- parentInstance as any,
- null,
- undefined,
- false,
- )
- onScopeDispose(unmount, true)
- isMounted = true
- } else {
- // move
- internals.m(
- vnode,
- parentNode,
- anchor,
- MoveType.REORDER,
- parentInstance as any,
- )
- }
- }
-
- frag.remove = unmount
-
- return frag
-}
-
-/**
- * Mount vdom slot in vapor
- */
-function renderVDOMSlot(
- internals: RendererInternals,
- slotsRef: ShallowRef<Slots>,
- name: string | (() => string),
- props: Record<string, any>,
- parentComponent: VaporComponentInstance,
- fallback?: VaporSlot,
-): VaporFragment {
- const frag = new VaporFragment([])
-
- let isMounted = false
- let fallbackNodes: Block | undefined
- let oldVNode: VNode | null = null
-
- frag.insert = (parentNode, anchor) => {
- if (!isMounted) {
- renderEffect(() => {
- const vnode = renderSlot(
- slotsRef.value,
- isFunction(name) ? name() : name,
- props,
- )
- if ((vnode.children as any[]).length) {
- if (fallbackNodes) {
- remove(fallbackNodes, parentNode)
- fallbackNodes = undefined
- }
- internals.p(
- oldVNode,
- vnode,
- parentNode,
- anchor,
- parentComponent as any,
- )
- oldVNode = vnode
- } else {
- if (fallback && !fallbackNodes) {
- // mount fallback
- if (oldVNode) {
- internals.um(oldVNode, parentComponent as any, null, true)
- }
- insert((fallbackNodes = fallback(props)), parentNode, anchor)
- }
- oldVNode = null
- }
- })
- isMounted = true
- } else {
- // move
- internals.m(
- oldVNode!,
- parentNode,
- anchor,
- MoveType.REORDER,
- parentComponent as any,
- )
- }
-
- frag.remove = parentNode => {
- if (fallbackNodes) {
- remove(fallbackNodes, parentNode)
- } else if (oldVNode) {
- internals.um(oldVNode, parentComponent as any, null)
- }
- }
- }
-
- return frag
-}
-
-export const vaporInteropPlugin: Plugin = app => {
- const internals = ensureRenderer().internals
- app._context.vapor = extend(vaporInteropImpl, {
- vdomMount: createVDOMComponent.bind(null, internals),
- vdomUnmount: internals.umt,
- vdomSlot: renderVDOMSlot.bind(null, internals),
- })
- const mount = app.mount
- app.mount = ((...args) => {
- optimizePropertyLookup()
- return mount(...args)
- }) satisfies App['mount']
-}
if (parent && parent.subTree && parent.subTree === cur.vnode) {
// parent is a non-SSR compiled component and is rendering this
// component as root. inherit its scopeId if present.
- cur = parent as ComponentInternalInstance
+ cur = parent
} else {
break
}
if (curVnode.scopeId) {
openTag += ` ${curVnode.scopeId}`
}
- curParent = curParent.parent as ComponentInternalInstance
+ curParent = curParent.parent
}
if (slotScopeId) {
openTag += ` ${slotScopeId}`
const type = typeof value
return type === 'string' || type === 'number' || type === 'boolean'
}
-
-/*
- * The following attributes must be set as attribute
- */
-export function shouldSetAsAttr(tagName: string, key: string): boolean {
- // these are enumerated attrs, however their corresponding DOM properties
- // are actually booleans - this leads to setting it with a string "false"
- // value leading it to be coerced to `true`, so we need to always treat
- // them as attributes.
- // Note that `contentEditable` doesn't have this problem: its DOM
- // property is also enumerated string values.
- if (
- key === 'spellcheck' ||
- key === 'draggable' ||
- key === 'translate' ||
- key === 'autocorrect'
- ) {
- return true
- }
-
- // #1787, #2840 form property on form elements is readonly and must be set as
- // attribute.
- if (key === 'form') {
- return true
- }
-
- // #1526 <input list> must be set as attribute
- if (key === 'list' && tagName === 'INPUT') {
- return true
- }
-
- // #2766 <textarea type> must be set as attribute
- if (key === 'type' && tagName === 'TEXTAREA') {
- return true
- }
-
- // #8780 the width or height of embedded tags must be set as attribute
- if (
- (key === 'width' || key === 'height') &&
- (tagName === 'IMG' ||
- tagName === 'VIDEO' ||
- tagName === 'CANVAS' ||
- tagName === 'SOURCE')
- ) {
- return true
- }
-
- return false
-}
export const NOOP = (): void => {}
-/**
- * Always return true.
- */
-export const YES = () => true
-
/**
* Always return false.
*/
// uppercase letter
(key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97)
-export const isNativeOn = (key: string): boolean =>
- key.charCodeAt(0) === 111 /* o */ &&
- key.charCodeAt(1) === 110 /* n */ &&
- // lowercase letter
- key.charCodeAt(2) > 96 &&
- key.charCodeAt(2) < 123
-
-export const isModelListener = (key: string): boolean =>
+export const isModelListener = (key: string): key is `onUpdate:${string}` =>
key.startsWith('onUpdate:')
export const extend: typeof Object.assign = Object.assign
'onVnodeBeforeUnmount,onVnodeUnmounted',
)
-export const isBuiltInTag: (key: string) => boolean =
- /*#__PURE__*/ makeMap('slot,component')
-
export const isBuiltInDirective: (key: string) => boolean =
/*@__PURE__*/ makeMap(
'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo',
}
const camelizeRE = /-(\w)/g
-const camelizeReplacer = (_: any, c: string) => (c ? c.toUpperCase() : '')
/**
* @private
*/
export const camelize: (str: string) => string = cacheStringFunction(
- (str: string): string => str.replace(camelizeRE, camelizeReplacer),
+ (str: string): string => {
+ return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))
+ },
)
const hyphenateRE = /\B([A-Z])/g
)
)
}
-
-export function canSetValueDirectly(tagName: string): boolean {
- return (
- tagName !== 'PROGRESS' &&
- // custom elements may use _value internally
- !tagName.includes('-')
- )
-}
export * from './looseEqual'
export * from './toDisplayString'
export * from './typeUtils'
-export * from './subSequence'
export * from './cssVars'
import { hyphenate, isArray, isObject, isString } from './general'
-export type NormalizedStyle = Record<string, unknown>
+export type NormalizedStyle = Record<string, string | number>
export function normalizeStyle(
value: unknown,
+++ /dev/null
-// https://en.wikipedia.org/wiki/Longest_increasing_subsequence
-export function getSequence(arr: number[]): number[] {
- const p = arr.slice()
- const result = [0]
- let i, j, u, v, c
- const len = arr.length
- for (i = 0; i < len; i++) {
- const arrI = arr[i]
- if (arrI !== 0) {
- j = result[result.length - 1]
- if (arr[j] < arrI) {
- p[i] = j
- result.push(i)
- continue
- }
- u = 0
- v = result.length - 1
- while (u < v) {
- c = (u + v) >> 1
- if (arr[result[c]] < arrI) {
- u = c + 1
- } else {
- v = c
- }
- }
- if (arrI < arr[result[u]]) {
- if (u > 0) {
- p[i] = result[u - 1]
- }
- result[u] = i
- }
- }
- }
- u = result.length
- v = result[u - 1]
- while (u-- > 0) {
- result[u] = v
- v = p[v]
- }
- return result
-}
isObject,
isPlainObject,
isSet,
+ isString,
isSymbol,
objectToString,
} from './general'
* @private
*/
export const toDisplayString = (val: unknown): string => {
- switch (typeof val) {
- case 'string':
- return val
- case 'object':
- if (val) {
- if (isRef(val)) {
- return toDisplayString(val.value)
- } else if (
- isArray(val) ||
- val.toString === objectToString ||
- !isFunction(val.toString)
- ) {
- return JSON.stringify(val, replacer, 2)
- }
- }
- default:
- return val == null ? '' : String(val)
- }
+ return isString(val)
+ ? val
+ : val == null
+ ? ''
+ : isArray(val) ||
+ (isObject(val) &&
+ (val.toString === objectToString || !isFunction(val.toString)))
+ ? isRef(val)
+ ? toDisplayString(val.value)
+ : JSON.stringify(val, replacer, 2)
+ : String(val)
}
const replacer = (_key: string, val: unknown): any => {
+++ /dev/null
-/**
- * Flags to optimize vapor `createFor` runtime behavior, shared between the
- * compiler and the runtime
- */
-export enum VaporVForFlags {
- /**
- * v-for is the only child of a parent container, so it can take the fast
- * path with textContent = '' when the whole list is emptied
- */
- FAST_REMOVE = 1,
- /**
- * v-for used on component - we can skip creating child scopes for each block
- * because the component itself already has a scope.
- */
- IS_COMPONENT = 1 << 1,
- /**
- * v-for inside v-ince
- */
- ONCE = 1 << 2,
-}
### Installation
1. Upgrade tooling if applicable.
+
- If using custom webpack setup: Upgrade `vue-loader` to `^16.0.0`.
- If using `vue-cli`: upgrade to the latest `@vue/cli-service` with `vue upgrade`
- (Alternative) migrate to [Vite](https://vitejs.dev/) + [vite-plugin-vue2](https://github.com/underfin/vite-plugin-vue2). [[Example commit](https://github.com/vuejs/vue-hackernews-2.0/commit/565b948919eb58f22a32afca7e321b490cb3b074)]
5. After fixing the errors, the app should be able to run if it is not subject to the [limitations](#known-limitations) mentioned above.
You will likely see a LOT of warnings from both the command line and the browser console. Here are some general tips:
+
- You can filter for specific warnings in the browser console. It's a good idea to use the filter and focus on fixing one item at a time. You can also use negated filters like `-GLOBAL_MOUNT`.
- You can suppress specific deprecations via [compat configuration](#compat-configuration).
### From CDN or without a Bundler
- **`vue(.runtime).global(.prod).js`**:
+
- For direct use via `<script src="...">` in the browser. Exposes the `Vue` global.
- Note that global builds are not [UMD](https://github.com/umdjs/umd) builds. They are built as [IIFEs](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) and is only meant for direct use via `<script src="...">`.
- In-browser template compilation:
### With a Bundler
- **`vue(.runtime).esm-bundler.js`**:
+
- For use with bundlers like `webpack`, `rollup` and `parcel`.
- Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler)
- Does not ship minified builds (to be done together with the rest of the code after bundling)
`esm-bundler` builds of Vue expose global feature flags that can be overwritten at compile time:
- `__VUE_OPTIONS_API__`
+
- Default: `true`
- Enable / disable Options API support
- `__VUE_PROD_DEVTOOLS__`
+
- Default: `false`
- Enable / disable devtools support in production
-// @vitest-environment jsdom
-
import type { ElementHandle } from 'puppeteer'
import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils'
import path from 'node:path'
-// @vitest-environment jsdom
-
import { E2E_TIMEOUT, setupPuppeteer } from './e2eUtils'
import path from 'node:path'
import { createApp, ref } from 'vue'
page.on('console', e => {
if (e.type() === 'error') {
- console.error(`Error from Puppeteer-loaded page:\n`, e.text())
+ const err = e.args()[0]
+ console.error(`Error from Puppeteer-loaded page:\n`, err.remoteObject())
}
})
})
"global",
"global-runtime",
"esm-browser",
- "esm-browser-runtime",
- "esm-browser-vapor"
+ "esm-browser-runtime"
]
},
"repository": {
"type": "git",
- "url": "git+https://github.com/vuejs/vue.git"
+ "url": "git+https://github.com/vuejs/core.git"
},
"keywords": [
"vue"
"author": "Evan You",
"license": "MIT",
"bugs": {
- "url": "https://github.com/vuejs/vue/issues"
+ "url": "https://github.com/vuejs/core/issues"
},
- "homepage": "https://github.com/vuejs/vue/tree/main/packages/vue#readme",
+ "homepage": "https://github.com/vuejs/core/tree/main/packages/vue#readme",
"dependencies": {
"@vue/shared": "workspace:*",
"@vue/compiler-dom": "workspace:*",
"@vue/runtime-dom": "workspace:*",
- "@vue/runtime-vapor": "workspace:*",
"@vue/compiler-sfc": "workspace:*",
"@vue/server-renderer": "workspace:*"
},
+++ /dev/null
-// for type generation only
-export * from './index'
-export * from '@vue/runtime-vapor'
+++ /dev/null
-export * from './runtime'
-export * from '@vue/runtime-vapor'
// This entry exports the runtime only, and is built as
// `dist/vue.esm-bundler.js` which is used by default for bundlers.
-import { NOOP } from '@vue/shared'
import { initDev } from './dev'
-import { type RenderFunction, warn } from '@vue/runtime-dom'
+import { warn } from '@vue/runtime-dom'
if (__DEV__) {
initDev()
export * from '@vue/runtime-dom'
-export const compile = (_template: string): RenderFunction => {
+export const compile = (): void => {
if (__DEV__) {
warn(
`Runtime compilation is not supported in this build of Vue.` +
: ``) /* should not happen */,
)
}
- return NOOP
}
default:
'@babel/parser':
specifier: ^7.27.5
- version: 7.28.0
+ version: 7.27.5
'@babel/types':
specifier: ^7.27.6
- version: 7.28.0
+ version: 7.27.6
'@vitejs/plugin-vue':
specifier: ^5.2.4
version: 5.2.4
specifier: ^1.2.1
version: 1.2.1
vite:
- specifier: ^6.1.0
- version: 6.3.5
+ specifier: ^5.4.15
+ version: 5.4.15
importers:
devDependencies:
'@babel/parser':
specifier: 'catalog:'
- version: 7.28.0
+ version: 7.27.5
'@babel/types':
specifier: 'catalog:'
- version: 7.28.0
+ version: 7.27.6
'@rollup/plugin-alias':
specifier: ^5.1.1
version: 5.1.1(rollup@4.44.1)
version: 6.1.4
'@vitest/coverage-v8':
specifier: ^3.1.4
- version: 3.2.4(vitest@3.2.4)
+ version: 3.1.4(vitest@3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2))
'@vitest/eslint-plugin':
specifier: ^1.2.1
- version: 1.3.4(eslint@9.30.1)(typescript@5.6.3)(vitest@3.2.4)
- '@vitest/ui':
- specifier: ^3.0.2
- version: 3.2.4(vitest@3.2.4)
+ version: 1.2.1(eslint@9.27.0)(typescript@5.6.3)(vitest@3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2))
'@vue/consolidate':
specifier: 1.0.0
version: 1.0.0
version: 0.3.0(esbuild@0.25.5)
eslint:
specifier: ^9.27.0
- version: 9.30.1
+ version: 9.27.0
eslint-plugin-import-x:
specifier: ^4.13.1
- version: 4.16.1(@typescript-eslint/utils@8.35.1(eslint@9.30.1)(typescript@5.6.3))(eslint@9.30.1)
+ version: 4.13.1(eslint@9.27.0)(typescript@5.6.3)
estree-walker:
specifier: 'catalog:'
version: 2.0.2
version: 26.1.0
lint-staged:
specifier: ^16.0.0
- version: 16.1.2
+ version: 16.0.0
lodash:
specifier: ^4.17.21
version: 4.17.21
version: 1.1.1
prettier:
specifier: ^3.5.3
- version: 3.6.2
+ version: 3.5.3
pretty-bytes:
specifier: ^6.1.1
version: 6.1.1
version: 5.6.3
typescript-eslint:
specifier: ^8.32.1
- version: 8.35.1(eslint@9.30.1)(typescript@5.6.3)
+ version: 8.32.1(eslint@9.27.0)(typescript@5.6.3)
vite:
specifier: 'catalog:'
- version: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
+ version: 5.4.15(@types/node@22.16.0)(sass@1.89.2)
vitest:
specifier: ^3.1.4
- version: 3.2.4(@types/node@22.16.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.89.2)(yaml@2.8.0)
-
- packages-private/benchmark:
- dependencies:
- '@vitejs/plugin-vue':
- specifier: 'catalog:'
- version: 5.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))(vue@3.5.17(typescript@5.6.3))
- connect:
- specifier: ^3.7.0
- version: 3.7.0
- sirv:
- specifier: ^2.0.4
- version: 2.0.4
- vite:
- specifier: 'catalog:'
- version: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
- devDependencies:
- '@types/connect':
- specifier: ^3.4.38
- version: 3.4.38
+ version: 3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2)
packages-private/dts-built-test:
dependencies:
specifier: workspace:*
version: link:../../packages/vue
- packages-private/local-playground:
- dependencies:
- '@vueuse/core':
- specifier: ^11.1.0
- version: 11.3.0(vue@packages+vue)
- vue:
- specifier: workspace:*
- version: link:../../packages/vue
- devDependencies:
- '@vitejs/plugin-vue':
- specifier: 'catalog:'
- version: 5.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))(vue@packages+vue)
- '@vue/compiler-sfc':
- specifier: workspace:*
- version: link:../../packages/compiler-sfc
- vite:
- specifier: 'catalog:'
- version: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
- vite-hyper-config:
- specifier: ^0.4.0
- version: 0.4.1(@types/node@22.16.0)(sass@1.89.2)(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))
- vite-plugin-inspect:
- specifier: ^0.8.7
- version: 0.8.9(rollup@4.44.1)(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))
-
packages-private/sfc-playground:
dependencies:
'@vue/repl':
devDependencies:
'@vitejs/plugin-vue':
specifier: 'catalog:'
- version: 5.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))(vue@packages+vue)
+ version: 5.2.4(vite@5.4.15(@types/node@22.16.0)(sass@1.89.2))(vue@packages+vue)
vite:
specifier: 'catalog:'
- version: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
+ version: 5.4.15(@types/node@22.16.0)(sass@1.89.2)
packages-private/template-explorer:
dependencies:
- '@vue/compiler-vapor':
- specifier: workspace:^
- version: link:../../packages/compiler-vapor
monaco-editor:
specifier: ^0.52.2
version: 0.52.2
specifier: ^1.2.1
version: 1.2.1
- packages-private/vapor-e2e-test:
- devDependencies:
- '@types/connect':
- specifier: ^3.4.38
- version: 3.4.38
- '@vitejs/plugin-vue':
- specifier: 'catalog:'
- version: 5.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))(vue@packages+vue)
- connect:
- specifier: ^3.7.0
- version: 3.7.0
- sirv:
- specifier: ^2.0.4
- version: 2.0.4
- vite:
- specifier: 'catalog:'
- version: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
- vue:
- specifier: workspace:*
- version: link:../../packages/vue
-
packages-private/vite-debug:
devDependencies:
'@vitejs/plugin-vue':
specifier: 'catalog:'
- version: 5.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))(vue@packages+vue)
+ version: 5.2.4(vite@5.4.15(@types/node@22.16.0)(sass@1.89.2))(vue@packages+vue)
vite:
specifier: 'catalog:'
- version: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
+ version: 5.4.15(@types/node@22.16.0)(sass@1.89.2)
vue:
specifier: workspace:*
version: link:../../packages/vue
dependencies:
'@babel/parser':
specifier: 'catalog:'
- version: 7.28.0
+ version: 7.27.5
'@vue/shared':
specifier: workspace:*
version: link:../shared
devDependencies:
'@babel/types':
specifier: 'catalog:'
- version: 7.28.0
+ version: 7.27.6
packages/compiler-dom:
dependencies:
dependencies:
'@babel/parser':
specifier: 'catalog:'
- version: 7.28.0
+ version: 7.27.5
'@vue/compiler-core':
specifier: workspace:*
version: link:../compiler-core
'@vue/compiler-ssr':
specifier: workspace:*
version: link:../compiler-ssr
- '@vue/compiler-vapor':
- specifier: workspace:*
- version: link:../compiler-vapor
'@vue/shared':
specifier: workspace:*
version: link:../shared
devDependencies:
'@babel/types':
specifier: 'catalog:'
- version: 7.28.0
+ version: 7.27.6
'@vue/consolidate':
specifier: ^1.0.0
version: 1.0.0
specifier: workspace:*
version: link:../shared
- packages/compiler-vapor:
- dependencies:
- '@vue/compiler-dom':
- specifier: workspace:*
- version: link:../compiler-dom
- '@vue/shared':
- specifier: workspace:*
- version: link:../shared
- source-map-js:
- specifier: 'catalog:'
- version: 1.2.1
-
packages/reactivity:
dependencies:
'@vue/shared':
specifier: workspace:*
version: link:../shared
- packages/runtime-vapor:
- dependencies:
- '@vue/reactivity':
- specifier: workspace:*
- version: link:../reactivity
- '@vue/runtime-dom':
- specifier: workspace:*
- version: link:../runtime-dom
- '@vue/shared':
- specifier: workspace:*
- version: link:../shared
-
packages/server-renderer:
dependencies:
'@vue/compiler-ssr':
'@vue/runtime-dom':
specifier: workspace:*
version: link:../runtime-dom
- '@vue/runtime-vapor':
- specifier: workspace:*
- version: link:../runtime-vapor
'@vue/server-renderer':
specifier: workspace:*
version: link:../server-renderer
dependencies:
'@babel/parser':
specifier: 'catalog:'
- version: 7.28.0
+ version: 7.27.5
estree-walker:
specifier: 'catalog:'
version: 2.0.2
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
- '@antfu/utils@0.7.10':
- resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==}
-
- '@asamuzakjp/css-color@3.2.0':
- resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==}
+ '@asamuzakjp/css-color@2.8.2':
+ resolution: {integrity: sha512-RtWv9jFN2/bLExuZgFFZ0I3pWWeezAHGgrmjqGGWclATl1aDe3yhCUaI0Ilkp6OCk9zX7+FjvDasEX8Q9Rxc5w==}
- '@babel/code-frame@7.27.1':
- resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ '@babel/code-frame@7.26.2':
+ resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
engines: {node: '>=6.9.0'}
- '@babel/parser@7.28.0':
- resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==}
+ '@babel/parser@7.27.5':
+ resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/types@7.28.0':
- resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==}
+ '@babel/types@7.27.6':
+ resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
engines: {node: '>=6.9.0'}
'@bcoe/v8-coverage@1.0.2':
conventional-commits-parser:
optional: true
- '@csstools/color-helpers@5.0.2':
- resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
+ '@csstools/color-helpers@5.0.1':
+ resolution: {integrity: sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==}
engines: {node: '>=18'}
- '@csstools/css-calc@2.1.4':
- resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
+ '@csstools/css-calc@2.1.1':
+ resolution: {integrity: sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==}
engines: {node: '>=18'}
peerDependencies:
- '@csstools/css-parser-algorithms': ^3.0.5
- '@csstools/css-tokenizer': ^3.0.4
+ '@csstools/css-parser-algorithms': ^3.0.4
+ '@csstools/css-tokenizer': ^3.0.3
- '@csstools/css-color-parser@3.0.10':
- resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==}
+ '@csstools/css-color-parser@3.0.7':
+ resolution: {integrity: sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==}
engines: {node: '>=18'}
peerDependencies:
- '@csstools/css-parser-algorithms': ^3.0.5
- '@csstools/css-tokenizer': ^3.0.4
+ '@csstools/css-parser-algorithms': ^3.0.4
+ '@csstools/css-tokenizer': ^3.0.3
- '@csstools/css-parser-algorithms@3.0.5':
- resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
+ '@csstools/css-parser-algorithms@3.0.4':
+ resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==}
engines: {node: '>=18'}
peerDependencies:
- '@csstools/css-tokenizer': ^3.0.4
+ '@csstools/css-tokenizer': ^3.0.3
- '@csstools/css-tokenizer@3.0.4':
- resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
+ '@csstools/css-tokenizer@3.0.3':
+ resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==}
engines: {node: '>=18'}
'@emnapi/core@1.4.3':
cpu: [x64]
os: [win32]
+ '@eslint-community/eslint-utils@4.6.1':
+ resolution: {integrity: sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
'@eslint-community/eslint-utils@4.7.0':
resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
- '@eslint/config-array@0.21.0':
- resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==}
+ '@eslint/config-array@0.20.0':
+ resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/config-helpers@0.3.0':
- resolution: {integrity: sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==}
+ '@eslint/config-helpers@0.2.1':
+ resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/core@0.14.0':
resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/core@0.15.1':
- resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
'@eslint/eslintrc@3.3.1':
resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/js@9.30.1':
- resolution: {integrity: sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==}
+ '@eslint/js@9.27.0':
+ resolution: {integrity: sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.6':
resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@eslint/plugin-kit@0.3.3':
- resolution: {integrity: sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==}
+ '@eslint/plugin-kit@0.3.1':
+ resolution: {integrity: sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
engines: {node: '>=18.18'}
- '@humanwhocodes/retry@0.4.3':
- resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
+ '@humanwhocodes/retry@0.4.2':
+ resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==}
engines: {node: '>=18.18'}
'@hutson/parse-repository-url@5.0.0':
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
- '@jridgewell/gen-mapping@0.3.12':
- resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
+ '@jridgewell/gen-mapping@0.3.5':
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
- '@jridgewell/sourcemap-codec@1.5.4':
- resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==}
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
- '@jridgewell/trace-mapping@0.3.29':
- resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==}
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
- '@jspm/core@2.1.0':
- resolution: {integrity: sha512-3sRl+pkyFY/kLmHl0cgHiFp2xEqErA8N3ECjMs7serSUBmoJ70lBa0PG5t0IM6WJgdZNyyI0R8YFfi5wM8+mzg==}
+ '@jspm/core@2.0.1':
+ resolution: {integrity: sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==}
- '@napi-rs/wasm-runtime@0.2.11':
- resolution: {integrity: sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==}
+ '@napi-rs/wasm-runtime@0.2.9':
+ resolution: {integrity: sha512-OKRBiajrrxB9ATokgEQoG87Z25c67pCpYcCwmXYX8PBftC9pBfN18gnm/fh1wurSLEKIAt+QRFLFCQISrb66Jg==}
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
- '@parcel/watcher-android-arm64@2.5.1':
- resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+ '@parcel/watcher-android-arm64@2.4.1':
+ resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [android]
- '@parcel/watcher-darwin-arm64@2.5.1':
- resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+ '@parcel/watcher-darwin-arm64@2.4.1':
+ resolution: {integrity: sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [darwin]
- '@parcel/watcher-darwin-x64@2.5.1':
- resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+ '@parcel/watcher-darwin-x64@2.4.1':
+ resolution: {integrity: sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [darwin]
- '@parcel/watcher-freebsd-x64@2.5.1':
- resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+ '@parcel/watcher-freebsd-x64@2.4.1':
+ resolution: {integrity: sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [freebsd]
- '@parcel/watcher-linux-arm-glibc@2.5.1':
- resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+ '@parcel/watcher-linux-arm-glibc@2.4.1':
+ resolution: {integrity: sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
- '@parcel/watcher-linux-arm-musl@2.5.1':
- resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
- engines: {node: '>= 10.0.0'}
- cpu: [arm]
- os: [linux]
-
- '@parcel/watcher-linux-arm64-glibc@2.5.1':
- resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+ '@parcel/watcher-linux-arm64-glibc@2.4.1':
+ resolution: {integrity: sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
- '@parcel/watcher-linux-arm64-musl@2.5.1':
- resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+ '@parcel/watcher-linux-arm64-musl@2.4.1':
+ resolution: {integrity: sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
- '@parcel/watcher-linux-x64-glibc@2.5.1':
- resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+ '@parcel/watcher-linux-x64-glibc@2.4.1':
+ resolution: {integrity: sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
- '@parcel/watcher-linux-x64-musl@2.5.1':
- resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+ '@parcel/watcher-linux-x64-musl@2.4.1':
+ resolution: {integrity: sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
- '@parcel/watcher-win32-arm64@2.5.1':
- resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+ '@parcel/watcher-win32-arm64@2.4.1':
+ resolution: {integrity: sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [win32]
- '@parcel/watcher-win32-ia32@2.5.1':
- resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+ '@parcel/watcher-win32-ia32@2.4.1':
+ resolution: {integrity: sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==}
engines: {node: '>= 10.0.0'}
cpu: [ia32]
os: [win32]
- '@parcel/watcher-win32-x64@2.5.1':
- resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+ '@parcel/watcher-win32-x64@2.4.1':
+ resolution: {integrity: sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [win32]
- '@parcel/watcher@2.5.1':
- resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+ '@parcel/watcher@2.4.1':
+ resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==}
engines: {node: '>= 10.0.0'}
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
- '@polka/url@1.0.0-next.29':
- resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
-
'@puppeteer/browsers@2.10.5':
resolution: {integrity: sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==}
engines: {node: '>=18'}
rollup:
optional: true
- '@rollup/pluginutils@5.2.0':
- resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==}
+ '@rollup/pluginutils@5.1.0':
+ resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
'@tybys/wasm-util@0.9.0':
resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
- '@types/chai@5.2.2':
- resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==}
-
- '@types/connect@3.4.38':
- resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
-
- '@types/deep-eql@4.0.2':
- resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+ '@types/estree@1.0.7':
+ resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
- '@types/web-bluetooth@0.0.20':
- resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
-
'@types/yauzl@2.10.3':
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
- '@typescript-eslint/eslint-plugin@8.35.1':
- resolution: {integrity: sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==}
+ '@typescript-eslint/eslint-plugin@8.32.1':
+ resolution: {integrity: sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/parser': ^8.35.1
+ '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/parser@8.35.1':
- resolution: {integrity: sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==}
+ '@typescript-eslint/parser@8.32.1':
+ resolution: {integrity: sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/project-service@8.35.1':
- resolution: {integrity: sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==}
+ '@typescript-eslint/scope-manager@8.32.1':
+ resolution: {integrity: sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- typescript: '>=4.8.4 <5.9.0'
-
- '@typescript-eslint/scope-manager@8.35.1':
- resolution: {integrity: sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
-
- '@typescript-eslint/tsconfig-utils@8.35.1':
- resolution: {integrity: sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==}
- engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- peerDependencies:
- typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/type-utils@8.35.1':
- resolution: {integrity: sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==}
+ '@typescript-eslint/type-utils@8.32.1':
+ resolution: {integrity: sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/types@8.35.1':
- resolution: {integrity: sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==}
+ '@typescript-eslint/types@8.32.1':
+ resolution: {integrity: sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@typescript-eslint/typescript-estree@8.35.1':
- resolution: {integrity: sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==}
+ '@typescript-eslint/typescript-estree@8.32.1':
+ resolution: {integrity: sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/utils@8.35.1':
- resolution: {integrity: sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==}
+ '@typescript-eslint/utils@8.32.1':
+ resolution: {integrity: sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/visitor-keys@8.35.1':
- resolution: {integrity: sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==}
+ '@typescript-eslint/visitor-keys@8.32.1':
+ resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- '@unrs/resolver-binding-android-arm-eabi@1.10.1':
- resolution: {integrity: sha512-zohDKXT1Ok0yhbVGff4YAg9HUs5ietG5GpvJBPFSApZnGe7uf2cd26DRhKZbn0Be6xHUZrSzP+RAgMmzyc71EA==}
- cpu: [arm]
- os: [android]
-
- '@unrs/resolver-binding-android-arm64@1.10.1':
- resolution: {integrity: sha512-tAN6k5UrTd4nicpA7s2PbjR/jagpDzAmvXFjbpTazUe5FRsFxVcBlS1F5Lzp5jtWU6bdiqRhSvd4X8rdpCffeA==}
- cpu: [arm64]
- os: [android]
-
- '@unrs/resolver-binding-darwin-arm64@1.10.1':
- resolution: {integrity: sha512-+FCsag8WkauI4dQ50XumCXdfvDCZEpMUnvZDsKMxfOisnEklpDFXc6ThY0WqybBYZbiwR5tWcFaZmI0G6b4vrg==}
+ '@unrs/resolver-binding-darwin-arm64@1.7.2':
+ resolution: {integrity: sha512-vxtBno4xvowwNmO/ASL0Y45TpHqmNkAaDtz4Jqb+clmcVSSl8XCG/PNFFkGsXXXS6AMjP+ja/TtNCFFa1QwLRg==}
cpu: [arm64]
os: [darwin]
- '@unrs/resolver-binding-darwin-x64@1.10.1':
- resolution: {integrity: sha512-qYKGGm5wk71ONcXTMZ0+J11qQeOAPz3nw6VtqrBUUELRyXFyvK8cHhHsLBFR4GHnilc2pgY1HTB2TvdW9wO26Q==}
+ '@unrs/resolver-binding-darwin-x64@1.7.2':
+ resolution: {integrity: sha512-qhVa8ozu92C23Hsmv0BF4+5Dyyd5STT1FolV4whNgbY6mj3kA0qsrGPe35zNR3wAN7eFict3s4Rc2dDTPBTuFQ==}
cpu: [x64]
os: [darwin]
- '@unrs/resolver-binding-freebsd-x64@1.10.1':
- resolution: {integrity: sha512-hOHMAhbvIQ63gkpgeNsXcWPSyvXH7ZEyeg254hY0Lp/hX8NdW+FsUWq73g9946Pc/BrcVI/I3C1cmZ4RCX9bNw==}
+ '@unrs/resolver-binding-freebsd-x64@1.7.2':
+ resolution: {integrity: sha512-zKKdm2uMXqLFX6Ac7K5ElnnG5VIXbDlFWzg4WJ8CGUedJryM5A3cTgHuGMw1+P5ziV8CRhnSEgOnurTI4vpHpg==}
cpu: [x64]
os: [freebsd]
- '@unrs/resolver-binding-linux-arm-gnueabihf@1.10.1':
- resolution: {integrity: sha512-6ds7+zzHJgTDmpe0gmFcOTvSUhG5oZukkt+cCsSb3k4Uiz2yEQB4iCRITX2hBwSW+p8gAieAfecITjgqCkswXw==}
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.7.2':
+ resolution: {integrity: sha512-8N1z1TbPnHH+iDS/42GJ0bMPLiGK+cUqOhNbMKtWJ4oFGzqSJk/zoXFzcQkgtI63qMcUI7wW1tq2usZQSb2jxw==}
cpu: [arm]
os: [linux]
- '@unrs/resolver-binding-linux-arm-musleabihf@1.10.1':
- resolution: {integrity: sha512-P7A0G2/jW00diNJyFeq4W9/nxovD62Ay8CMP4UK9OymC7qO7rG1a8Upad68/bdfpIOn7KSp7Aj/6lEW3yyznAA==}
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.7.2':
+ resolution: {integrity: sha512-tjYzI9LcAXR9MYd9rO45m1s0B/6bJNuZ6jeOxo1pq1K6OBuRMMmfyvJYval3s9FPPGmrldYA3mi4gWDlWuTFGA==}
cpu: [arm]
os: [linux]
- '@unrs/resolver-binding-linux-arm64-gnu@1.10.1':
- resolution: {integrity: sha512-Cg6xzdkrpltcTPO4At+A79zkC7gPDQIgosJmVV8M104ImB6KZi1MrNXgDYIAfkhUYjPzjNooEDFRAwwPadS7ZA==}
+ '@unrs/resolver-binding-linux-arm64-gnu@1.7.2':
+ resolution: {integrity: sha512-jon9M7DKRLGZ9VYSkFMflvNqu9hDtOCEnO2QAryFWgT6o6AXU8du56V7YqnaLKr6rAbZBWYsYpikF226v423QA==}
cpu: [arm64]
os: [linux]
- '@unrs/resolver-binding-linux-arm64-musl@1.10.1':
- resolution: {integrity: sha512-aNeg99bVkXa4lt+oZbjNRPC8ZpjJTKxijg/wILrJdzNyAymO2UC/HUK1UfDjt6T7U5p/mK24T3CYOi3/+YEQSA==}
+ '@unrs/resolver-binding-linux-arm64-musl@1.7.2':
+ resolution: {integrity: sha512-c8Cg4/h+kQ63pL43wBNaVMmOjXI/X62wQmru51qjfTvI7kmCy5uHTJvK/9LrF0G8Jdx8r34d019P1DVJmhXQpA==}
cpu: [arm64]
os: [linux]
- '@unrs/resolver-binding-linux-ppc64-gnu@1.10.1':
- resolution: {integrity: sha512-ylz5ojeXrkPrtnzVhpCO+YegG63/aKhkoTlY8PfMfBfLaUG8v6m6iqrL7sBUKdVBgOB4kSTUPt9efQdA/Y3Z/w==}
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.7.2':
+ resolution: {integrity: sha512-A+lcwRFyrjeJmv3JJvhz5NbcCkLQL6Mk16kHTNm6/aGNc4FwPHPE4DR9DwuCvCnVHvF5IAd9U4VIs/VvVir5lg==}
cpu: [ppc64]
os: [linux]
- '@unrs/resolver-binding-linux-riscv64-gnu@1.10.1':
- resolution: {integrity: sha512-xcWyhmJfXXOxK7lvE4+rLwBq+on83svlc0AIypfe6x4sMJR+S4oD7n9OynaQShfj2SufPw2KJAotnsNb+4nN2g==}
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.7.2':
+ resolution: {integrity: sha512-hQQ4TJQrSQW8JlPm7tRpXN8OCNP9ez7PajJNjRD1ZTHQAy685OYqPrKjfaMw/8LiHCt8AZ74rfUVHP9vn0N69Q==}
cpu: [riscv64]
os: [linux]
- '@unrs/resolver-binding-linux-riscv64-musl@1.10.1':
- resolution: {integrity: sha512-mW9JZAdOCyorgi1eLJr4gX7xS67WNG9XNPYj5P8VuttK72XNsmdw9yhOO4tDANMgiLXFiSFaiL1gEpoNtRPw/A==}
+ '@unrs/resolver-binding-linux-riscv64-musl@1.7.2':
+ resolution: {integrity: sha512-NoAGbiqrxtY8kVooZ24i70CjLDlUFI7nDj3I9y54U94p+3kPxwd2L692YsdLa+cqQ0VoqMWoehDFp21PKRUoIQ==}
cpu: [riscv64]
os: [linux]
- '@unrs/resolver-binding-linux-s390x-gnu@1.10.1':
- resolution: {integrity: sha512-NZGKhBy6xkJ0k09cWNZz4DnhBcGlhDd3W+j7EYoNvf5TSwj2K6kbmfqTWITEgkvjsMUjm1wsrc4IJaH6VtjyHQ==}
+ '@unrs/resolver-binding-linux-s390x-gnu@1.7.2':
+ resolution: {integrity: sha512-KaZByo8xuQZbUhhreBTW+yUnOIHUsv04P8lKjQ5otiGoSJ17ISGYArc+4vKdLEpGaLbemGzr4ZeUbYQQsLWFjA==}
cpu: [s390x]
os: [linux]
- '@unrs/resolver-binding-linux-x64-gnu@1.10.1':
- resolution: {integrity: sha512-VsjgckJ0gNMw7p0d8In6uPYr+s0p16yrT2rvG4v2jUpEMYkpnfnCiALa9SWshbvlGjKQ98Q2x19agm3iFk8w8Q==}
+ '@unrs/resolver-binding-linux-x64-gnu@1.7.2':
+ resolution: {integrity: sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==}
cpu: [x64]
os: [linux]
- '@unrs/resolver-binding-linux-x64-musl@1.10.1':
- resolution: {integrity: sha512-idMnajMeejnaFi0Mx9UTLSYFDAOTfAEP7VjXNgxKApso3Eu2Njs0p2V95nNIyFi4oQVGFmIuCkoznAXtF/Zbmw==}
+ '@unrs/resolver-binding-linux-x64-musl@1.7.2':
+ resolution: {integrity: sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==}
cpu: [x64]
os: [linux]
- '@unrs/resolver-binding-wasm32-wasi@1.10.1':
- resolution: {integrity: sha512-7jyhjIRNFjzlr8x5pth6Oi9hv3a7ubcVYm2GBFinkBQKcFhw4nIs5BtauSNtDW1dPIGrxF0ciynCZqzxMrYMsg==}
+ '@unrs/resolver-binding-wasm32-wasi@1.7.2':
+ resolution: {integrity: sha512-y797JBmO9IsvXVRCKDXOxjyAE4+CcZpla2GSoBQ33TVb3ILXuFnMrbR/QQZoauBYeOFuu4w3ifWLw52sdHGz6g==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
- '@unrs/resolver-binding-win32-arm64-msvc@1.10.1':
- resolution: {integrity: sha512-TY79+N+Gkoo7E99K+zmsKNeiuNJYlclZJtKqsHSls8We2iGhgxtletVsiBYie93MSTDRDMI8pkBZJlIJSZPrdA==}
+ '@unrs/resolver-binding-win32-arm64-msvc@1.7.2':
+ resolution: {integrity: sha512-gtYTh4/VREVSLA+gHrfbWxaMO/00y+34htY7XpioBTy56YN2eBjkPrY1ML1Zys89X3RJDKVaogzwxlM1qU7egg==}
cpu: [arm64]
os: [win32]
- '@unrs/resolver-binding-win32-ia32-msvc@1.10.1':
- resolution: {integrity: sha512-BAJN5PEPlEV+1m8+PCtFoKm3LQ1P57B4Z+0+efU0NzmCaGk7pUaOxuPgl+m3eufVeeNBKiPDltG0sSB9qEfCxw==}
+ '@unrs/resolver-binding-win32-ia32-msvc@1.7.2':
+ resolution: {integrity: sha512-Ywv20XHvHTDRQs12jd3MY8X5C8KLjDbg/jyaal/QLKx3fAShhJyD4blEANInsjxW3P7isHx1Blt56iUDDJO3jg==}
cpu: [ia32]
os: [win32]
- '@unrs/resolver-binding-win32-x64-msvc@1.10.1':
- resolution: {integrity: sha512-2v3erKKmmCyIVvvhI2nF15qEbdBpISTq44m9pyd5gfIJB1PN94oePTLWEd82XUbIbvKhv76xTSeUQSCOGesLeg==}
+ '@unrs/resolver-binding-win32-x64-msvc@1.7.2':
+ resolution: {integrity: sha512-friS8NEQfHaDbkThxopGk+LuE5v3iY0StruifjQEt7SLbA46OnfgMO15sOTkbpJkol6RB+1l1TYPXh0sCddpvA==}
cpu: [x64]
os: [win32]
vite: ^5.0.0 || ^6.0.0
vue: ^3.2.25
- '@vitest/coverage-v8@3.2.4':
- resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==}
+ '@vitest/coverage-v8@3.1.4':
+ resolution: {integrity: sha512-G4p6OtioySL+hPV7Y6JHlhpsODbJzt1ndwHAFkyk6vVjpK03PFsKnauZIzcd0PrK4zAbc5lc+jeZ+eNGiMA+iw==}
peerDependencies:
- '@vitest/browser': 3.2.4
- vitest: 3.2.4
+ '@vitest/browser': 3.1.4
+ vitest: 3.1.4
peerDependenciesMeta:
'@vitest/browser':
optional: true
- '@vitest/eslint-plugin@1.3.4':
- resolution: {integrity: sha512-EOg8d0jn3BAiKnR55WkFxmxfWA3nmzrbIIuOXyTe6A72duryNgyU+bdBEauA97Aab3ho9kLmAwgPX63Ckj4QEg==}
+ '@vitest/eslint-plugin@1.2.1':
+ resolution: {integrity: sha512-JQr1jdVcrsoS7Sdzn83h9sq4DvREf9Q/onTZbJCqTVlv/76qb+TZrLv/9VhjnjSMHweQH5FdpMDeCR6aDe2fgw==}
peerDependencies:
eslint: '>= 8.57.0'
typescript: '>= 5.0.0'
vitest:
optional: true
- '@vitest/expect@3.2.4':
- resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
+ '@vitest/expect@3.1.4':
+ resolution: {integrity: sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==}
- '@vitest/mocker@3.2.4':
- resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==}
+ '@vitest/mocker@3.1.4':
+ resolution: {integrity: sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==}
peerDependencies:
msw: ^2.4.9
- vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
+ vite: ^5.0.0 || ^6.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
- '@vitest/pretty-format@3.2.4':
- resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
+ '@vitest/pretty-format@3.1.4':
+ resolution: {integrity: sha512-cqv9H9GvAEoTaoq+cYqUTCGscUjKqlJZC7PRwY5FMySVj5J+xOm1KQcCiYHJOEzOKRUhLH4R2pTwvFlWCEScsg==}
- '@vitest/runner@3.2.4':
- resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==}
+ '@vitest/runner@3.1.4':
+ resolution: {integrity: sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==}
- '@vitest/snapshot@3.2.4':
- resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==}
+ '@vitest/snapshot@3.1.4':
+ resolution: {integrity: sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==}
- '@vitest/spy@3.2.4':
- resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
+ '@vitest/spy@3.1.4':
+ resolution: {integrity: sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==}
- '@vitest/ui@3.2.4':
- resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==}
- peerDependencies:
- vitest: 3.2.4
-
- '@vitest/utils@3.2.4':
- resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
-
- '@vue/compiler-core@3.5.17':
- resolution: {integrity: sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==}
-
- '@vue/compiler-dom@3.5.17':
- resolution: {integrity: sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==}
-
- '@vue/compiler-sfc@3.5.17':
- resolution: {integrity: sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==}
-
- '@vue/compiler-ssr@3.5.17':
- resolution: {integrity: sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==}
+ '@vitest/utils@3.1.4':
+ resolution: {integrity: sha512-yriMuO1cfFhmiGc8ataN51+9ooHRuURdfAZfwFd3usWynjzpLslZdYnRegTv32qdgtJTsj15FoeZe2g15fY1gg==}
'@vue/consolidate@1.0.0':
resolution: {integrity: sha512-oTyUE+QHIzLw2PpV14GD/c7EohDyP64xCniWTcqcEmTd699eFqTIwOmtDYjcO1j3QgdXoJEoWv1/cCdLrRoOfg==}
engines: {node: '>= 0.12.0'}
- '@vue/reactivity@3.5.17':
- resolution: {integrity: sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==}
-
'@vue/repl@4.6.1':
resolution: {integrity: sha512-tgeEa+QXzqbFsAIbq/dCXzOJxIW2Nq1F79KXRjbKyPt1ODpCx86bDbFgNzFcBEK3In2/mjPTMpN7fSD6Ig0Qsw==}
- '@vue/runtime-core@3.5.17':
- resolution: {integrity: sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==}
-
- '@vue/runtime-dom@3.5.17':
- resolution: {integrity: sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==}
-
- '@vue/server-renderer@3.5.17':
- resolution: {integrity: sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==}
- peerDependencies:
- vue: 3.5.17
-
- '@vue/shared@3.5.17':
- resolution: {integrity: sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==}
-
- '@vueuse/core@11.3.0':
- resolution: {integrity: sha512-7OC4Rl1f9G8IT6rUfi9JrKiXy4bfmHhZ5x2Ceojy0jnd3mHNEvV4JaRygH362ror6/NZ+Nl+n13LPzGiPN8cKA==}
-
- '@vueuse/metadata@11.3.0':
- resolution: {integrity: sha512-pwDnDspTqtTo2HwfLw4Rp6yywuuBdYnPYDq+mO38ZYKGebCUQC/nVj/PXSiK9HX5otxLz8Fn7ECPbjiRz2CC3g==}
-
- '@vueuse/shared@11.3.0':
- resolution: {integrity: sha512-P8gSSWQeucH5821ek2mn/ciCk+MS/zoRKqdQIM3bHq6p7GXDAJLmnRRKmF5F65sAVJIfzQlwR3aDzwCn10s8hA==}
-
'@zeit/schemas@2.36.0':
resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==}
engines: {node: '>=0.4.0'}
hasBin: true
- acorn@8.15.0:
- resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
+ acorn@8.14.0:
+ resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
engines: {node: '>=0.4.0'}
hasBin: true
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
- ansi-regex@6.1.0:
- resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
+ ansi-regex@6.0.1:
+ resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
ansi-styles@4.3.0:
asap@2.0.6:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
- assert-never@1.4.0:
- resolution: {integrity: sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==}
+ assert-never@1.3.0:
+ resolution: {integrity: sha512-9Z3vxQ+berkL/JJo0dK+EY3Lp0s3NtSnP3VCLsh5HDcZPrh0M+KQRK5sWhUeyPPH+/RCxZqOxLMR+YC6vlviEQ==}
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
engines: {node: '>=4'}
- ast-v8-to-istanbul@0.3.3:
- resolution: {integrity: sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==}
-
- b4a@1.6.7:
- resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==}
+ b4a@1.6.6:
+ resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==}
babel-walk@3.0.0-canary-5:
resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- bare-events@2.5.4:
- resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==}
+ bare-events@2.4.2:
+ resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==}
- bare-fs@4.1.5:
- resolution: {integrity: sha512-1zccWBMypln0jEE05LzZt+V/8y8AQsQQqxtklqaIyg5nu6OAYFhZxPXinJTSG+kU5qyNmeLgcn9AW7eHiCHVLA==}
- engines: {bare: '>=1.16.0'}
- peerDependencies:
- bare-buffer: '*'
- peerDependenciesMeta:
- bare-buffer:
- optional: true
+ bare-fs@4.0.1:
+ resolution: {integrity: sha512-ilQs4fm/l9eMfWY2dY0WCIUplSUp7U0CT1vrqMg1MUdeZl4fypu5UP0XcDBK5WBQPJAKP1b7XEodISmekH/CEg==}
+ engines: {bare: '>=1.7.0'}
- bare-os@3.6.1:
- resolution: {integrity: sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==}
- engines: {bare: '>=1.14.0'}
+ bare-os@3.4.0:
+ resolution: {integrity: sha512-9Ous7UlnKbe3fMi7Y+qh0DwAup6A1JkYgPnjvMDNOlmnxNRQvQ/7Nst+OnUQKzk0iAT0m9BisbDVp9gCv8+ETA==}
+ engines: {bare: '>=1.6.0'}
bare-path@3.0.0:
resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==}
- bare-stream@2.6.5:
- resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==}
- peerDependencies:
- bare-buffer: '*'
- bare-events: '*'
- peerDependenciesMeta:
- bare-buffer:
- optional: true
- bare-events:
- optional: true
+ bare-stream@2.1.3:
+ resolution: {integrity: sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==}
basic-ftp@5.0.5:
resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==}
resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==}
engines: {node: '>=14.16'}
- brace-expansion@1.1.12:
- resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
+ brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
- brace-expansion@2.0.2:
- resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+ brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
- bundle-name@4.1.0:
- resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
- engines: {node: '>=18'}
-
bytes@3.0.0:
resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==}
engines: {node: '>= 0.8'}
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
- call-bind-apply-helpers@1.0.2:
- resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
- engines: {node: '>= 0.4'}
-
- call-bound@1.0.4:
- resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ call-bind@1.0.7:
+ resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
engines: {node: '>= 0.4'}
callsites@3.1.0:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
engines: {node: '>= 16'}
- chokidar@4.0.3:
- resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+ chokidar@4.0.1:
+ resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==}
engines: {node: '>= 14.16.0'}
chromium-bidi@5.1.0:
colorette@2.0.20:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
- commander@14.0.0:
- resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==}
- engines: {node: '>=20'}
+ commander@13.1.0:
+ resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==}
+ engines: {node: '>=18'}
comment-parser@1.4.1:
resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- connect@3.7.0:
- resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
- engines: {node: '>= 0.10.0'}
-
constantinople@4.0.1:
resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==}
resolution: {integrity: sha512-SetDSntXLk8Jh1NOAl1Gu5uLiCNSYenB5tm0YVeZKePRIgDW9lQImromTwLa3c/Gae298tsgOM+/CYT9XAl0NA==}
engines: {node: '>=18'}
- conventional-changelog-writer@8.1.0:
- resolution: {integrity: sha512-dpC440QnORNCO81XYuRRFOLCsjKj4W7tMkUIn3lR6F/FAaJcWLi7iCj6IcEvSQY2zw6VUgwUKd5DEHKEWrpmEQ==}
+ conventional-changelog-writer@8.0.0:
+ resolution: {integrity: sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA==}
engines: {node: '>=18'}
hasBin: true
resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==}
engines: {node: '>=18'}
- conventional-commits-parser@6.2.0:
- resolution: {integrity: sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==}
+ conventional-commits-parser@6.0.0:
+ resolution: {integrity: sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==}
engines: {node: '>=18'}
hasBin: true
engines: {node: '>=4'}
hasBin: true
- cssstyle@4.6.0:
- resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==}
+ cssstyle@4.2.1:
+ resolution: {integrity: sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==}
engines: {node: '>=18'}
csstype@3.1.3:
supports-color:
optional: true
+ debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.4.0:
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
debug@4.4.1:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'}
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
- default-browser-id@5.0.0:
- resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
- engines: {node: '>=18'}
-
- default-browser@5.2.1:
- resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
- engines: {node: '>=18'}
-
- define-lazy-prop@3.0.0:
- resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
- engines: {node: '>=12'}
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
degenerator@5.0.1:
resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
engines: {node: '>=8'}
- dunder-proto@1.0.1:
- resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
- engines: {node: '>= 0.4'}
-
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- ee-first@1.1.1:
- resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
-
- emoji-regex@10.4.0:
- resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
+ emoji-regex@10.3.0:
+ resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
- encodeurl@1.0.2:
- resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
- engines: {node: '>= 0.8'}
-
- end-of-stream@1.4.5:
- resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
+ end-of-stream@1.4.4:
+ resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
enquirer@2.4.1:
resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
- entities@6.0.1:
- resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
- engines: {node: '>=0.12'}
-
env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
- error-stack-parser-es@0.1.5:
- resolution: {integrity: sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==}
-
- es-define-property@1.0.1:
- resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ es-define-property@1.0.0:
+ resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
+ es-module-lexer@1.6.0:
+ resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
+
es-module-lexer@1.7.0:
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
- es-object-atoms@1.1.1:
- resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
- engines: {node: '>= 0.4'}
-
esbuild-plugin-polyfill-node@0.3.0:
resolution: {integrity: sha512-SHG6CKUfWfYyYXGpW143NEZtcVVn8S/WHcEOxk62LuDXnY4Zpmc+WmxJKN6GMTgTClXJXhEM5KQlxKY6YjbucQ==}
peerDependencies:
engines: {node: '>=18'}
hasBin: true
- escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ escalade@3.1.2:
+ resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
- escape-html@1.0.3:
- resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
-
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
engines: {node: '>=6.0'}
hasBin: true
- eslint-import-context@0.1.9:
- resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==}
+ eslint-import-context@0.1.4:
+ resolution: {integrity: sha512-x3+etvB5TPxjFIq2m4tTnpt/9Ekp5GZKzXNp5ExLaS7Qv9E5BVs/Td7jxSnRtSzrgTCExXZlc0MuOdSuDLURiQ==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
peerDependencies:
unrs-resolver: ^1.0.0
unrs-resolver:
optional: true
- eslint-plugin-import-x@4.16.1:
- resolution: {integrity: sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==}
+ eslint-import-resolver-node@0.3.9:
+ resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+
+ eslint-plugin-import-x@4.13.1:
+ resolution: {integrity: sha512-Ua4HZBmG5TNr18q3Is+nT6mKCzNNpycqtv/+TkIK7E3w4LBlPlZI6vLwmDjXdIZtJPP2Z1Oh5+wksWwlcCjMpA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/utils': ^8.0.0
eslint: ^8.57.0 || ^9.0.0
- eslint-import-resolver-node: '*'
- peerDependenciesMeta:
- '@typescript-eslint/utils':
- optional: true
- eslint-import-resolver-node:
- optional: true
- eslint-scope@8.4.0:
- resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
+ eslint-scope@8.3.0:
+ resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
- eslint-visitor-keys@4.2.1:
- resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
+ eslint-visitor-keys@4.2.0:
+ resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
- eslint@9.30.1:
- resolution: {integrity: sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==}
+ eslint@9.27.0:
+ resolution: {integrity: sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
peerDependencies:
jiti:
optional: true
- espree@10.4.0:
- resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
+ espree@10.3.0:
+ resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
esprima@4.0.1:
fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
- fdir@6.4.6:
- resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==}
+ fdir@6.4.4:
+ resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==}
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'}
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
- finalhandler@1.1.2:
- resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==}
- engines: {node: '>= 0.8'}
-
- find-up-simple@1.0.1:
- resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==}
+ find-up-simple@1.0.0:
+ resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==}
engines: {node: '>=18'}
find-up@5.0.0:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
- flatted@3.3.3:
- resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+ flatted@3.3.1:
+ resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
- foreground-child@3.3.1:
- resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
+ foreground-child@3.3.0:
+ resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
engines: {node: '>=14'}
- fs-extra@11.3.0:
- resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
+ fs-extra@11.2.0:
+ resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
engines: {node: '>=14.14'}
fsevents@2.3.3:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
- get-east-asian-width@1.3.0:
- resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==}
+ get-east-asian-width@1.2.0:
+ resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==}
engines: {node: '>=18'}
- get-intrinsic@1.3.0:
- resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
- engines: {node: '>= 0.4'}
-
- get-proto@1.0.1:
- resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ get-intrinsic@1.2.4:
+ resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
engines: {node: '>= 0.4'}
get-stream@5.2.0:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
+ get-tsconfig@4.10.0:
+ resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
+
get-tsconfig@4.10.1:
resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==}
- get-uri@6.0.4:
- resolution: {integrity: sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==}
+ get-uri@6.0.3:
+ resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==}
engines: {node: '>= 14'}
git-raw-commits@5.0.0:
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
hasBin: true
- glob@11.0.3:
- resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==}
+ glob@11.0.0:
+ resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==}
engines: {node: 20 || >=22}
hasBin: true
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
- gopd@1.2.0:
- resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
- engines: {node: '>= 0.4'}
+ gopd@1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
- has-symbols@1.1.0:
- resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+ has-proto@1.0.3:
+ resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+ engines: {node: '>= 0.4'}
+
+ has-symbols@1.0.3:
+ resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
- ignore@7.0.5:
- resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
+ ignore@7.0.4:
+ resolution: {integrity: sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==}
engines: {node: '>= 4'}
immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
- immutable@5.1.3:
- resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==}
+ immutable@5.0.2:
+ resolution: {integrity: sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==}
- import-fresh@3.3.1:
- resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
import-meta-resolve@3.1.1:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
- index-to-position@1.1.0:
- resolution: {integrity: sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==}
+ index-to-position@0.1.2:
+ resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==}
engines: {node: '>=18'}
inherits@2.0.4:
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
- is-core-module@2.16.1:
- resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ is-core-module@2.15.0:
+ resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==}
engines: {node: '>= 0.4'}
is-docker@2.2.1:
engines: {node: '>=8'}
hasBin: true
- is-docker@3.0.0:
- resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- hasBin: true
-
is-expression@4.0.0:
resolution: {integrity: sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==}
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
- is-inside-container@1.0.0:
- resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
- engines: {node: '>=14.16'}
- hasBin: true
-
is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
- is-regex@1.2.1:
- resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
+ is-regex@1.1.4:
+ resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
is-stream@2.0.1:
resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
engines: {node: '>=8'}
- is-wsl@3.1.0:
- resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
- engines: {node: '>=16'}
-
isarray@1.0.0:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
- jackspeak@4.1.1:
- resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==}
+ jackspeak@4.0.1:
+ resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==}
engines: {node: 20 || >=22}
js-stringify@1.0.2:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
- js-tokens@9.0.1:
- resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
-
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- lint-staged@16.1.2:
- resolution: {integrity: sha512-sQKw2Si2g9KUZNY3XNvRuDq4UJqpHwF0/FQzZR2M7I5MvtpWvibikCjUVJzZdGE0ByurEl3KQNvsGetd1ty1/Q==}
- engines: {node: '>=20.17'}
+ lint-staged@16.0.0:
+ resolution: {integrity: sha512-sUCprePs6/rbx4vKC60Hez6X10HPkpDJaGcy3D1NdwR7g1RcNkWL8q9mJMreOqmHBTs+1sNFp+wOiX9fr+hoOQ==}
+ engines: {node: '>=20.18'}
hasBin: true
listr2@8.3.3:
resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==}
engines: {node: '>=18'}
- loupe@3.1.4:
- resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==}
+ loupe@3.1.3:
+ resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
lru-cache@10.1.0:
resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==}
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- lru-cache@11.1.0:
- resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==}
+ lru-cache@11.0.0:
+ resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==}
+ engines: {node: 20 || >=22}
+
+ lru-cache@11.0.2:
+ resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==}
engines: {node: 20 || >=22}
lru-cache@7.18.3:
engines: {node: '>= 18'}
hasBin: true
- math-intrinsics@1.1.0:
- resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
- engines: {node: '>= 0.4'}
-
memorystream@0.3.1:
resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
engines: {node: '>= 0.10.0'}
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
- mime-db@1.54.0:
- resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
+ mime-db@1.53.0:
+ resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==}
engines: {node: '>= 0.6'}
mime-types@2.1.18:
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
engines: {node: '>=18'}
+ minimatch@10.0.1:
+ resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
+ engines: {node: 20 || >=22}
+
minimatch@10.0.3:
resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==}
engines: {node: 20 || >=22}
monaco-editor@0.52.2:
resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
- mrmime@2.0.1:
- resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
- engines: {node: '>=10'}
-
ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
- napi-postinstall@0.3.0:
- resolution: {integrity: sha512-M7NqKyhODKV1gRLdkwE7pDsZP2/SC2a2vHkOYh9MCpKMbWVfyVfUw5MaH83Fv6XMjxr5jryUp3IDDL9rlxsTeA==}
+ napi-postinstall@0.2.3:
+ resolution: {integrity: sha512-Mi7JISo/4Ij2tDZ2xBE2WH+/KvVlkhA6juEjpEeRAVPNCpN3nxJo/5FhDNKgBcdmcmhaH6JjgST4xY/23ZYK0w==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
hasBin: true
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
engines: {node: '>=8'}
- nwsapi@2.2.20:
- resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==}
+ nwsapi@2.2.16:
+ resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
- on-finished@2.3.0:
- resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
- engines: {node: '>= 0.8'}
-
on-headers@1.0.2:
resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
engines: {node: '>= 0.8'}
resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
engines: {node: '>=18'}
- open@10.1.2:
- resolution: {integrity: sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==}
- engines: {node: '>=18'}
-
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
- pac-proxy-agent@7.2.0:
- resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==}
+ pac-proxy-agent@7.1.0:
+ resolution: {integrity: sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==}
engines: {node: '>= 14'}
pac-resolver@7.0.1:
resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==}
engines: {node: '>= 14'}
- package-json-from-dist@1.0.1:
- resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+ package-json-from-dist@1.0.0:
+ resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
pako@1.0.11:
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
- parse-json@8.3.0:
- resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==}
+ parse-json@8.1.0:
+ resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==}
engines: {node: '>=18'}
- parse5@7.3.0:
- resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
-
- parseurl@1.3.3:
- resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
- engines: {node: '>= 0.8'}
+ parse5@7.2.1:
+ resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
path-to-regexp@3.3.0:
resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==}
- pathe@1.1.2:
- resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
-
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
- pathval@2.0.1:
- resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
+ pathval@2.0.0:
+ resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
engines: {node: '>= 14.16'}
pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
- perfect-debounce@1.0.0:
- resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
-
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
peerDependencies:
postcss: ^8.1.0
- postcss-modules-local-by-default@4.2.0:
- resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==}
+ postcss-modules-local-by-default@4.0.5:
+ resolution: {integrity: sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
- postcss-modules-scope@3.2.1:
- resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==}
+ postcss-modules-scope@3.2.0:
+ resolution: {integrity: sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==}
engines: {node: ^10 || ^12 || >= 14}
peerDependencies:
postcss: ^8.1.0
peerDependencies:
postcss: ^8.0.0
+ postcss-selector-parser@6.1.2:
+ resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
+ engines: {node: '>=4'}
+
postcss-selector-parser@7.1.0:
resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==}
engines: {node: '>=4'}
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
- prettier@3.6.2:
- resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
+ prettier@3.5.3:
+ resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
engines: {node: '>=14'}
hasBin: true
pug@3.0.3:
resolution: {integrity: sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==}
- pump@3.0.3:
- resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
+ pump@3.0.0:
+ resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ queue-tick@1.0.1:
+ resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
+
range-parser@1.2.0:
resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==}
engines: {node: '>= 0.6'}
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
- readdirp@4.1.2:
- resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
- engines: {node: '>= 14.18.0'}
+ readdirp@4.0.1:
+ resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==}
+ engines: {node: '>= 14.16.0'}
registry-auth-token@3.3.2:
resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==}
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
- resolve@1.22.10:
- resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
- engines: {node: '>= 0.4'}
+ resolve@1.22.8:
+ resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true
restore-cursor@5.1.0:
rrweb-cssom@0.8.0:
resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
- run-applescript@7.0.0:
- resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
- engines: {node: '>=18'}
-
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
engines: {node: '>= 14'}
hasBin: true
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
setimmediate@1.0.5:
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
- shell-quote@1.8.3:
- resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==}
- engines: {node: '>= 0.4'}
+ shell-quote@1.8.1:
+ resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
resolution: {integrity: sha512-N+goiLxlkHJlyaYEglFypzVNMaNplPAk5syu0+OPp/Bk6dwVoXF6FfOw2vO0Dp+JHsBaI+w6cm8TnFl2Hw6tDA==}
hasBin: true
- sirv@2.0.4:
- resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
- engines: {node: '>= 10'}
-
- sirv@3.0.1:
- resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
- engines: {node: '>=18'}
-
slice-ansi@5.0.0:
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
engines: {node: '>=12'}
resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==}
engines: {node: '>= 14'}
- socks@2.8.5:
- resolution: {integrity: sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww==}
+ socks@2.8.3:
+ resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==}
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
source-map-js@1.2.1:
spdx-expression-parse@3.0.1:
resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
- spdx-license-ids@3.0.21:
- resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==}
+ spdx-license-ids@3.0.18:
+ resolution: {integrity: sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==}
sprintf-js@1.1.3:
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
- stable-hash-x@0.2.0:
- resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==}
- engines: {node: '>=12.0.0'}
+ stable-hash@0.0.5:
+ resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
- statuses@1.5.0:
- resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
- engines: {node: '>= 0.6'}
-
std-env@3.9.0:
resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
- streamx@2.22.1:
- resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==}
+ streamx@2.18.0:
+ resolution: {integrity: sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==}
string-argv@0.3.2:
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
- strip-literal@3.0.0:
- resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
-
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
- tar-fs@3.1.0:
- resolution: {integrity: sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==}
+ tar-fs@3.0.8:
+ resolution: {integrity: sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==}
tar-stream@3.1.7:
resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==}
engines: {node: '>=18'}
- text-decoder@1.2.3:
- resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==}
+ 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==}
tinyexec@0.3.2:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
- tinyglobby@0.2.14:
- resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
+ tinyglobby@0.2.13:
+ resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==}
engines: {node: '>=12.0.0'}
- tinypool@1.1.1:
- resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
+ tinypool@1.0.2:
+ resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
engines: {node: ^18.0.0 || >=20.0.0}
tinyrainbow@2.0.0:
resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
engines: {node: '>=14.0.0'}
- tinyspy@4.0.3:
- resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==}
+ tinyspy@3.0.2:
+ resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
tldts-core@6.1.86:
token-stream@1.0.0:
resolution: {integrity: sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==}
- totalist@3.0.1:
- resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
- engines: {node: '>=6'}
-
tough-cookie@5.1.2:
resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
engines: {node: '>=16'}
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
engines: {node: '>=12.20'}
- type-fest@4.41.0:
- resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
+ type-fest@4.24.0:
+ resolution: {integrity: sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==}
engines: {node: '>=16'}
typed-query-selector@2.12.0:
resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==}
- typescript-eslint@8.35.1:
- resolution: {integrity: sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==}
+ typescript-eslint@8.32.1:
+ resolution: {integrity: sha512-D7el+eaDHAmXvrZBy1zpzSNIRqnCOrkwTgZxTu3MUqRWk8k0q9m9Ho4+vPf7iHtgUfrK/o8IZaEApsxPlHTFCg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
engines: {node: '>=14.17'}
hasBin: true
- uglify-js@3.19.3:
- resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
+ uglify-js@3.19.1:
+ resolution: {integrity: sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A==}
engines: {node: '>=0.8.0'}
hasBin: true
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
- unpipe@1.0.0:
- resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
- engines: {node: '>= 0.8'}
-
unplugin-utils@0.2.4:
resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==}
engines: {node: '>=18.12.0'}
- unrs-resolver@1.10.1:
- resolution: {integrity: sha512-EFrL7Hw4kmhZdwWO3dwwFJo6hO3FXuQ6Bg8BK/faHZ9m1YxqBS31BNSTxklIQkxK/4LlV8zTYnPsIRLBzTzjCA==}
+ unrs-resolver@1.7.2:
+ resolution: {integrity: sha512-BBKpaylOW8KbHsu378Zky/dGh4ckT/4NW/0SHRABdqRLcQJ2dAOjDo9g97p04sWflm0kqPqpUatxReNV/dqI5A==}
update-check@1.5.4:
resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==}
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
- utils-merge@1.0.1:
- resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
- engines: {node: '>= 0.4.0'}
-
validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
- vite-hyper-config@0.4.1:
- resolution: {integrity: sha512-w9D4g0+5Km8XCgkBY/BZrXZAl8FF2q1UpDXT/Fsm6VLEU5tkkzDCko8fjLPOaSbvirUJgbY5OsD5wuuZ6581Fg==}
- engines: {node: '>=18.0.0'}
- peerDependencies:
- vite: ^4.0.0 || ^5.0.0 || ^6.0.0
-
- vite-node@2.1.9:
- resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
- engines: {node: ^18.0.0 || >=20.0.0}
- hasBin: true
-
- vite-node@3.2.4:
- resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
+ vite-node@3.1.4:
+ resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
- vite-plugin-inspect@0.8.9:
- resolution: {integrity: sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==}
- engines: {node: '>=14'}
- peerDependencies:
- '@nuxt/kit': '*'
- vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.1
- peerDependenciesMeta:
- '@nuxt/kit':
- optional: true
-
- vite@5.4.19:
- resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==}
+ vite@5.4.15:
+ resolution: {integrity: sha512-6ANcZRivqL/4WtwPGTKNaosuNJr5tWiftOC7liM7G9+rMb8+oeJeyzymDu4rTN93seySBmbjSfsS3Vzr19KNtA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
terser:
optional: true
- vite@6.3.5:
- resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ vite@5.4.19:
+ resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
- '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
- jiti: '>=1.21.0'
+ '@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
sass-embedded: '*'
stylus: '*'
sugarss: '*'
- terser: ^5.16.0
- tsx: ^4.8.1
- yaml: ^2.4.2
+ terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
- jiti:
- optional: true
less:
optional: true
lightningcss:
optional: true
terser:
optional: true
- tsx:
- optional: true
- yaml:
- optional: true
- vitest@3.2.4:
- resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==}
+ vitest@3.1.4:
+ resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/debug': ^4.1.12
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
- '@vitest/browser': 3.2.4
- '@vitest/ui': 3.2.4
+ '@vitest/browser': 3.1.4
+ '@vitest/ui': 3.1.4
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
- vue-demi@0.14.10:
- resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
- 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.17:
- resolution: {integrity: sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==}
- peerDependencies:
- typescript: '*'
- peerDependenciesMeta:
- typescript:
- optional: true
-
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- ws@8.18.3:
- resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
+ ws@8.18.1:
+ resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ ws@8.18.2:
+ resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
- zod@3.25.72:
- resolution: {integrity: sha512-Cl+fe4dNL4XumOBNBsr0lHfA80PQiZXHI4xEMTEr8gt6aGz92t3lBA32e71j9+JeF/VAYvdfBnuwJs+BMx/BrA==}
+ zod@3.24.1:
+ resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==}
snapshots:
'@ampproject/remapping@2.3.0':
dependencies:
- '@jridgewell/gen-mapping': 0.3.12
- '@jridgewell/trace-mapping': 0.3.29
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
- '@antfu/utils@0.7.10': {}
-
- '@asamuzakjp/css-color@3.2.0':
+ '@asamuzakjp/css-color@2.8.2':
dependencies:
- '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
- '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
- '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
- '@csstools/css-tokenizer': 3.0.4
- lru-cache: 10.4.3
+ '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-color-parser': 3.0.7(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-tokenizer': 3.0.3
+ lru-cache: 11.0.2
- '@babel/code-frame@7.27.1':
+ '@babel/code-frame@7.26.2':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
js-tokens: 4.0.0
'@babel/helper-validator-identifier@7.27.1': {}
- '@babel/parser@7.28.0':
+ '@babel/parser@7.27.5':
dependencies:
- '@babel/types': 7.28.0
+ '@babel/types': 7.27.6
- '@babel/types@7.28.0':
+ '@babel/types@7.27.6':
dependencies:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@bcoe/v8-coverage@1.0.2': {}
- '@conventional-changelog/git-client@1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0)':
+ '@conventional-changelog/git-client@1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0)':
dependencies:
'@types/semver': 7.7.0
semver: 7.7.2
optionalDependencies:
conventional-commits-filter: 5.0.0
- conventional-commits-parser: 6.2.0
+ conventional-commits-parser: 6.0.0
- '@csstools/color-helpers@5.0.2': {}
+ '@csstools/color-helpers@5.0.1': {}
- '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ '@csstools/css-calc@2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
dependencies:
- '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
- '@csstools/css-tokenizer': 3.0.4
+ '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-tokenizer': 3.0.3
- '@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ '@csstools/css-color-parser@3.0.7(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
dependencies:
- '@csstools/color-helpers': 5.0.2
- '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
- '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
- '@csstools/css-tokenizer': 3.0.4
+ '@csstools/color-helpers': 5.0.1
+ '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-tokenizer': 3.0.3
- '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
+ '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)':
dependencies:
- '@csstools/css-tokenizer': 3.0.4
+ '@csstools/css-tokenizer': 3.0.3
- '@csstools/css-tokenizer@3.0.4': {}
+ '@csstools/css-tokenizer@3.0.3': {}
'@emnapi/core@1.4.3':
dependencies:
'@esbuild/win32-x64@0.25.5':
optional: true
- '@eslint-community/eslint-utils@4.7.0(eslint@9.30.1)':
+ '@eslint-community/eslint-utils@4.6.1(eslint@9.27.0)':
dependencies:
- eslint: 9.30.1
+ eslint: 9.27.0
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/eslint-utils@4.7.0(eslint@9.27.0)':
+ dependencies:
+ eslint: 9.27.0
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.1': {}
- '@eslint/config-array@0.21.0':
+ '@eslint/config-array@0.20.0':
dependencies:
'@eslint/object-schema': 2.1.6
- debug: 4.4.1
+ debug: 4.4.0
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
- '@eslint/config-helpers@0.3.0': {}
+ '@eslint/config-helpers@0.2.1': {}
'@eslint/core@0.14.0':
dependencies:
'@types/json-schema': 7.0.15
- '@eslint/core@0.15.1':
- dependencies:
- '@types/json-schema': 7.0.15
-
'@eslint/eslintrc@3.3.1':
dependencies:
ajv: 6.12.6
- debug: 4.4.1
- espree: 10.4.0
+ debug: 4.4.0
+ espree: 10.3.0
globals: 14.0.0
ignore: 5.3.2
- import-fresh: 3.3.1
+ import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
- '@eslint/js@9.30.1': {}
+ '@eslint/js@9.27.0': {}
'@eslint/object-schema@2.1.6': {}
- '@eslint/plugin-kit@0.3.3':
+ '@eslint/plugin-kit@0.3.1':
dependencies:
- '@eslint/core': 0.15.1
+ '@eslint/core': 0.14.0
levn: 0.4.1
'@humanfs/core@0.19.1': {}
'@humanwhocodes/retry@0.3.1': {}
- '@humanwhocodes/retry@0.4.3': {}
+ '@humanwhocodes/retry@0.4.2': {}
'@hutson/parse-repository-url@5.0.0': {}
'@istanbuljs/schema@0.1.3': {}
- '@jridgewell/gen-mapping@0.3.12':
+ '@jridgewell/gen-mapping@0.3.5':
dependencies:
- '@jridgewell/sourcemap-codec': 1.5.4
- '@jridgewell/trace-mapping': 0.3.29
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.25
'@jridgewell/resolve-uri@3.1.2': {}
- '@jridgewell/sourcemap-codec@1.5.4': {}
+ '@jridgewell/set-array@1.2.1': {}
+
+ '@jridgewell/sourcemap-codec@1.5.0': {}
- '@jridgewell/trace-mapping@0.3.29':
+ '@jridgewell/trace-mapping@0.3.25':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.4
+ '@jridgewell/sourcemap-codec': 1.5.0
- '@jspm/core@2.1.0': {}
+ '@jspm/core@2.0.1': {}
- '@napi-rs/wasm-runtime@0.2.11':
+ '@napi-rs/wasm-runtime@0.2.9':
dependencies:
'@emnapi/core': 1.4.3
'@emnapi/runtime': 1.4.3
'@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1
- '@parcel/watcher-android-arm64@2.5.1':
- optional: true
-
- '@parcel/watcher-darwin-arm64@2.5.1':
+ '@parcel/watcher-android-arm64@2.4.1':
optional: true
- '@parcel/watcher-darwin-x64@2.5.1':
+ '@parcel/watcher-darwin-arm64@2.4.1':
optional: true
- '@parcel/watcher-freebsd-x64@2.5.1':
+ '@parcel/watcher-darwin-x64@2.4.1':
optional: true
- '@parcel/watcher-linux-arm-glibc@2.5.1':
+ '@parcel/watcher-freebsd-x64@2.4.1':
optional: true
- '@parcel/watcher-linux-arm-musl@2.5.1':
+ '@parcel/watcher-linux-arm-glibc@2.4.1':
optional: true
- '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ '@parcel/watcher-linux-arm64-glibc@2.4.1':
optional: true
- '@parcel/watcher-linux-arm64-musl@2.5.1':
+ '@parcel/watcher-linux-arm64-musl@2.4.1':
optional: true
- '@parcel/watcher-linux-x64-glibc@2.5.1':
+ '@parcel/watcher-linux-x64-glibc@2.4.1':
optional: true
- '@parcel/watcher-linux-x64-musl@2.5.1':
+ '@parcel/watcher-linux-x64-musl@2.4.1':
optional: true
- '@parcel/watcher-win32-arm64@2.5.1':
+ '@parcel/watcher-win32-arm64@2.4.1':
optional: true
- '@parcel/watcher-win32-ia32@2.5.1':
+ '@parcel/watcher-win32-ia32@2.4.1':
optional: true
- '@parcel/watcher-win32-x64@2.5.1':
+ '@parcel/watcher-win32-x64@2.4.1':
optional: true
- '@parcel/watcher@2.5.1':
+ '@parcel/watcher@2.4.1':
dependencies:
detect-libc: 1.0.3
is-glob: 4.0.3
micromatch: 4.0.8
node-addon-api: 7.1.1
optionalDependencies:
- '@parcel/watcher-android-arm64': 2.5.1
- '@parcel/watcher-darwin-arm64': 2.5.1
- '@parcel/watcher-darwin-x64': 2.5.1
- '@parcel/watcher-freebsd-x64': 2.5.1
- '@parcel/watcher-linux-arm-glibc': 2.5.1
- '@parcel/watcher-linux-arm-musl': 2.5.1
- '@parcel/watcher-linux-arm64-glibc': 2.5.1
- '@parcel/watcher-linux-arm64-musl': 2.5.1
- '@parcel/watcher-linux-x64-glibc': 2.5.1
- '@parcel/watcher-linux-x64-musl': 2.5.1
- '@parcel/watcher-win32-arm64': 2.5.1
- '@parcel/watcher-win32-ia32': 2.5.1
- '@parcel/watcher-win32-x64': 2.5.1
+ '@parcel/watcher-android-arm64': 2.4.1
+ '@parcel/watcher-darwin-arm64': 2.4.1
+ '@parcel/watcher-darwin-x64': 2.4.1
+ '@parcel/watcher-freebsd-x64': 2.4.1
+ '@parcel/watcher-linux-arm-glibc': 2.4.1
+ '@parcel/watcher-linux-arm64-glibc': 2.4.1
+ '@parcel/watcher-linux-arm64-musl': 2.4.1
+ '@parcel/watcher-linux-x64-glibc': 2.4.1
+ '@parcel/watcher-linux-x64-musl': 2.4.1
+ '@parcel/watcher-win32-arm64': 2.4.1
+ '@parcel/watcher-win32-ia32': 2.4.1
+ '@parcel/watcher-win32-x64': 2.4.1
optional: true
'@pkgjs/parseargs@0.11.0':
optional: true
- '@polka/url@1.0.0-next.29': {}
-
'@puppeteer/browsers@2.10.5':
dependencies:
debug: 4.4.1
progress: 2.0.3
proxy-agent: 6.5.0
semver: 7.7.2
- tar-fs: 3.1.0
+ tar-fs: 3.0.8
yargs: 17.7.2
transitivePeerDependencies:
- - bare-buffer
- supports-color
'@rollup/plugin-alias@5.1.1(rollup@4.44.1)':
'@rollup/plugin-commonjs@28.0.6(rollup@4.44.1)':
dependencies:
- '@rollup/pluginutils': 5.2.0(rollup@4.44.1)
+ '@rollup/pluginutils': 5.1.0(rollup@4.44.1)
commondir: 1.0.1
estree-walker: 2.0.2
- fdir: 6.4.6(picomatch@4.0.2)
+ fdir: 6.4.4(picomatch@4.0.2)
is-reference: 1.2.1
magic-string: 0.30.17
picomatch: 4.0.2
'@rollup/plugin-inject@5.0.5(rollup@4.44.1)':
dependencies:
- '@rollup/pluginutils': 5.2.0(rollup@4.44.1)
+ '@rollup/pluginutils': 5.1.0(rollup@4.44.1)
estree-walker: 2.0.2
magic-string: 0.30.17
optionalDependencies:
'@rollup/plugin-json@6.1.0(rollup@4.44.1)':
dependencies:
- '@rollup/pluginutils': 5.2.0(rollup@4.44.1)
+ '@rollup/pluginutils': 5.1.0(rollup@4.44.1)
optionalDependencies:
rollup: 4.44.1
'@rollup/plugin-node-resolve@16.0.1(rollup@4.44.1)':
dependencies:
- '@rollup/pluginutils': 5.2.0(rollup@4.44.1)
+ '@rollup/pluginutils': 5.1.0(rollup@4.44.1)
'@types/resolve': 1.20.2
deepmerge: 4.3.1
is-module: 1.0.0
- resolve: 1.22.10
+ resolve: 1.22.8
optionalDependencies:
rollup: 4.44.1
'@rollup/plugin-replace@5.0.4(rollup@4.44.1)':
dependencies:
- '@rollup/pluginutils': 5.2.0(rollup@4.44.1)
+ '@rollup/pluginutils': 5.1.0(rollup@4.44.1)
magic-string: 0.30.17
optionalDependencies:
rollup: 4.44.1
- '@rollup/pluginutils@5.2.0(rollup@4.44.1)':
+ '@rollup/pluginutils@5.1.0(rollup@4.44.1)':
dependencies:
- '@types/estree': 1.0.8
+ '@types/estree': 1.0.7
estree-walker: 2.0.2
- picomatch: 4.0.2
+ picomatch: 2.3.1
optionalDependencies:
rollup: 4.44.1
tslib: 2.8.1
optional: true
- '@types/chai@5.2.2':
- dependencies:
- '@types/deep-eql': 4.0.2
-
- '@types/connect@3.4.38':
- dependencies:
- '@types/node': 22.16.0
-
- '@types/deep-eql@4.0.2': {}
+ '@types/estree@1.0.7': {}
'@types/estree@1.0.8': {}
'@types/trusted-types@2.0.7': {}
- '@types/web-bluetooth@0.0.20': {}
-
'@types/yauzl@2.10.3':
dependencies:
'@types/node': 22.16.0
optional: true
- '@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1)(typescript@5.6.3))(eslint@9.30.1)(typescript@5.6.3)':
+ '@typescript-eslint/eslint-plugin@8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.27.0)(typescript@5.6.3))(eslint@9.27.0)(typescript@5.6.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
- '@typescript-eslint/parser': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
- '@typescript-eslint/scope-manager': 8.35.1
- '@typescript-eslint/type-utils': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
- '@typescript-eslint/utils': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
- '@typescript-eslint/visitor-keys': 8.35.1
- eslint: 9.30.1
+ '@typescript-eslint/parser': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
+ '@typescript-eslint/scope-manager': 8.32.1
+ '@typescript-eslint/type-utils': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
+ '@typescript-eslint/utils': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
+ '@typescript-eslint/visitor-keys': 8.32.1
+ eslint: 9.27.0
graphemer: 1.4.0
- ignore: 7.0.5
+ ignore: 7.0.4
natural-compare: 1.4.0
ts-api-utils: 2.1.0(typescript@5.6.3)
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.35.1(eslint@9.30.1)(typescript@5.6.3)':
+ '@typescript-eslint/parser@8.32.1(eslint@9.27.0)(typescript@5.6.3)':
dependencies:
- '@typescript-eslint/scope-manager': 8.35.1
- '@typescript-eslint/types': 8.35.1
- '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.6.3)
- '@typescript-eslint/visitor-keys': 8.35.1
+ '@typescript-eslint/scope-manager': 8.32.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.6.3)
+ '@typescript-eslint/visitor-keys': 8.32.1
debug: 4.4.1
- eslint: 9.30.1
+ eslint: 9.27.0
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/project-service@8.35.1(typescript@5.6.3)':
+ '@typescript-eslint/scope-manager@8.32.1':
dependencies:
- '@typescript-eslint/tsconfig-utils': 8.35.1(typescript@5.6.3)
- '@typescript-eslint/types': 8.35.1
- debug: 4.4.1
- typescript: 5.6.3
- transitivePeerDependencies:
- - supports-color
-
- '@typescript-eslint/scope-manager@8.35.1':
- dependencies:
- '@typescript-eslint/types': 8.35.1
- '@typescript-eslint/visitor-keys': 8.35.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/visitor-keys': 8.32.1
- '@typescript-eslint/tsconfig-utils@8.35.1(typescript@5.6.3)':
+ '@typescript-eslint/type-utils@8.32.1(eslint@9.27.0)(typescript@5.6.3)':
dependencies:
- typescript: 5.6.3
-
- '@typescript-eslint/type-utils@8.35.1(eslint@9.30.1)(typescript@5.6.3)':
- dependencies:
- '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.6.3)
- '@typescript-eslint/utils': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
+ '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.6.3)
+ '@typescript-eslint/utils': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
debug: 4.4.1
- eslint: 9.30.1
+ eslint: 9.27.0
ts-api-utils: 2.1.0(typescript@5.6.3)
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/types@8.35.1': {}
+ '@typescript-eslint/types@8.32.1': {}
- '@typescript-eslint/typescript-estree@8.35.1(typescript@5.6.3)':
+ '@typescript-eslint/typescript-estree@8.32.1(typescript@5.6.3)':
dependencies:
- '@typescript-eslint/project-service': 8.35.1(typescript@5.6.3)
- '@typescript-eslint/tsconfig-utils': 8.35.1(typescript@5.6.3)
- '@typescript-eslint/types': 8.35.1
- '@typescript-eslint/visitor-keys': 8.35.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/visitor-keys': 8.32.1
debug: 4.4.1
fast-glob: 3.3.3
is-glob: 4.0.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.35.1(eslint@9.30.1)(typescript@5.6.3)':
+ '@typescript-eslint/utils@8.32.1(eslint@9.27.0)(typescript@5.6.3)':
dependencies:
- '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1)
- '@typescript-eslint/scope-manager': 8.35.1
- '@typescript-eslint/types': 8.35.1
- '@typescript-eslint/typescript-estree': 8.35.1(typescript@5.6.3)
- eslint: 9.30.1
+ '@eslint-community/eslint-utils': 4.7.0(eslint@9.27.0)
+ '@typescript-eslint/scope-manager': 8.32.1
+ '@typescript-eslint/types': 8.32.1
+ '@typescript-eslint/typescript-estree': 8.32.1(typescript@5.6.3)
+ eslint: 9.27.0
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/visitor-keys@8.35.1':
+ '@typescript-eslint/visitor-keys@8.32.1':
dependencies:
- '@typescript-eslint/types': 8.35.1
- eslint-visitor-keys: 4.2.1
-
- '@unrs/resolver-binding-android-arm-eabi@1.10.1':
- optional: true
-
- '@unrs/resolver-binding-android-arm64@1.10.1':
- optional: true
+ '@typescript-eslint/types': 8.32.1
+ eslint-visitor-keys: 4.2.0
- '@unrs/resolver-binding-darwin-arm64@1.10.1':
+ '@unrs/resolver-binding-darwin-arm64@1.7.2':
optional: true
- '@unrs/resolver-binding-darwin-x64@1.10.1':
+ '@unrs/resolver-binding-darwin-x64@1.7.2':
optional: true
- '@unrs/resolver-binding-freebsd-x64@1.10.1':
+ '@unrs/resolver-binding-freebsd-x64@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-arm-gnueabihf@1.10.1':
+ '@unrs/resolver-binding-linux-arm-gnueabihf@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-arm-musleabihf@1.10.1':
+ '@unrs/resolver-binding-linux-arm-musleabihf@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-arm64-gnu@1.10.1':
+ '@unrs/resolver-binding-linux-arm64-gnu@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-arm64-musl@1.10.1':
+ '@unrs/resolver-binding-linux-arm64-musl@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-ppc64-gnu@1.10.1':
+ '@unrs/resolver-binding-linux-ppc64-gnu@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-riscv64-gnu@1.10.1':
+ '@unrs/resolver-binding-linux-riscv64-gnu@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-riscv64-musl@1.10.1':
+ '@unrs/resolver-binding-linux-riscv64-musl@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-s390x-gnu@1.10.1':
+ '@unrs/resolver-binding-linux-s390x-gnu@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-x64-gnu@1.10.1':
+ '@unrs/resolver-binding-linux-x64-gnu@1.7.2':
optional: true
- '@unrs/resolver-binding-linux-x64-musl@1.10.1':
+ '@unrs/resolver-binding-linux-x64-musl@1.7.2':
optional: true
- '@unrs/resolver-binding-wasm32-wasi@1.10.1':
+ '@unrs/resolver-binding-wasm32-wasi@1.7.2':
dependencies:
- '@napi-rs/wasm-runtime': 0.2.11
+ '@napi-rs/wasm-runtime': 0.2.9
optional: true
- '@unrs/resolver-binding-win32-arm64-msvc@1.10.1':
+ '@unrs/resolver-binding-win32-arm64-msvc@1.7.2':
optional: true
- '@unrs/resolver-binding-win32-ia32-msvc@1.10.1':
+ '@unrs/resolver-binding-win32-ia32-msvc@1.7.2':
optional: true
- '@unrs/resolver-binding-win32-x64-msvc@1.10.1':
+ '@unrs/resolver-binding-win32-x64-msvc@1.7.2':
optional: true
- '@vitejs/plugin-vue@5.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))(vue@3.5.17(typescript@5.6.3))':
- dependencies:
- vite: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
- vue: 3.5.17(typescript@5.6.3)
-
- '@vitejs/plugin-vue@5.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))(vue@packages+vue)':
+ '@vitejs/plugin-vue@5.2.4(vite@5.4.15(@types/node@22.16.0)(sass@1.89.2))(vue@packages+vue)':
dependencies:
- vite: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
+ vite: 5.4.15(@types/node@22.16.0)(sass@1.89.2)
vue: link:packages/vue
- '@vitest/coverage-v8@3.2.4(vitest@3.2.4)':
+ '@vitest/coverage-v8@3.1.4(vitest@3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 1.0.2
- ast-v8-to-istanbul: 0.3.3
- debug: 4.4.1
+ debug: 4.4.0
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-lib-source-maps: 5.0.6
std-env: 3.9.0
test-exclude: 7.0.1
tinyrainbow: 2.0.0
- vitest: 3.2.4(@types/node@22.16.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.89.2)(yaml@2.8.0)
+ vitest: 3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2)
transitivePeerDependencies:
- supports-color
- '@vitest/eslint-plugin@1.3.4(eslint@9.30.1)(typescript@5.6.3)(vitest@3.2.4)':
+ '@vitest/eslint-plugin@1.2.1(eslint@9.27.0)(typescript@5.6.3)(vitest@3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2))':
dependencies:
- '@typescript-eslint/utils': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
- eslint: 9.30.1
+ '@typescript-eslint/utils': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
+ eslint: 9.27.0
optionalDependencies:
typescript: 5.6.3
- vitest: 3.2.4(@types/node@22.16.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.89.2)(yaml@2.8.0)
+ vitest: 3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2)
transitivePeerDependencies:
- supports-color
- '@vitest/expect@3.2.4':
+ '@vitest/expect@3.1.4':
dependencies:
- '@types/chai': 5.2.2
- '@vitest/spy': 3.2.4
- '@vitest/utils': 3.2.4
+ '@vitest/spy': 3.1.4
+ '@vitest/utils': 3.1.4
chai: 5.2.0
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))':
+ '@vitest/mocker@3.1.4(vite@5.4.19(@types/node@22.16.0)(sass@1.89.2))':
dependencies:
- '@vitest/spy': 3.2.4
+ '@vitest/spy': 3.1.4
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
- vite: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
+ vite: 5.4.19(@types/node@22.16.0)(sass@1.89.2)
- '@vitest/pretty-format@3.2.4':
+ '@vitest/pretty-format@3.1.4':
dependencies:
tinyrainbow: 2.0.0
- '@vitest/runner@3.2.4':
+ '@vitest/runner@3.1.4':
dependencies:
- '@vitest/utils': 3.2.4
+ '@vitest/utils': 3.1.4
pathe: 2.0.3
- strip-literal: 3.0.0
- '@vitest/snapshot@3.2.4':
+ '@vitest/snapshot@3.1.4':
dependencies:
- '@vitest/pretty-format': 3.2.4
+ '@vitest/pretty-format': 3.1.4
magic-string: 0.30.17
pathe: 2.0.3
- '@vitest/spy@3.2.4':
+ '@vitest/spy@3.1.4':
dependencies:
- tinyspy: 4.0.3
+ tinyspy: 3.0.2
- '@vitest/ui@3.2.4(vitest@3.2.4)':
+ '@vitest/utils@3.1.4':
dependencies:
- '@vitest/utils': 3.2.4
- fflate: 0.8.2
- flatted: 3.3.3
- pathe: 2.0.3
- sirv: 3.0.1
- tinyglobby: 0.2.14
+ '@vitest/pretty-format': 3.1.4
+ loupe: 3.1.3
tinyrainbow: 2.0.0
- vitest: 3.2.4(@types/node@22.16.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.89.2)(yaml@2.8.0)
-
- '@vitest/utils@3.2.4':
- dependencies:
- '@vitest/pretty-format': 3.2.4
- loupe: 3.1.4
- tinyrainbow: 2.0.0
-
- '@vue/compiler-core@3.5.17':
- dependencies:
- '@babel/parser': 7.28.0
- '@vue/shared': 3.5.17
- entities: 4.5.0
- estree-walker: 2.0.2
- source-map-js: 1.2.1
-
- '@vue/compiler-dom@3.5.17':
- dependencies:
- '@vue/compiler-core': 3.5.17
- '@vue/shared': 3.5.17
-
- '@vue/compiler-sfc@3.5.17':
- dependencies:
- '@babel/parser': 7.28.0
- '@vue/compiler-core': 3.5.17
- '@vue/compiler-dom': 3.5.17
- '@vue/compiler-ssr': 3.5.17
- '@vue/shared': 3.5.17
- estree-walker: 2.0.2
- magic-string: 0.30.17
- postcss: 8.5.6
- source-map-js: 1.2.1
-
- '@vue/compiler-ssr@3.5.17':
- dependencies:
- '@vue/compiler-dom': 3.5.17
- '@vue/shared': 3.5.17
'@vue/consolidate@1.0.0': {}
- '@vue/reactivity@3.5.17':
- dependencies:
- '@vue/shared': 3.5.17
-
'@vue/repl@4.6.1': {}
- '@vue/runtime-core@3.5.17':
- dependencies:
- '@vue/reactivity': 3.5.17
- '@vue/shared': 3.5.17
-
- '@vue/runtime-dom@3.5.17':
- dependencies:
- '@vue/reactivity': 3.5.17
- '@vue/runtime-core': 3.5.17
- '@vue/shared': 3.5.17
- csstype: 3.1.3
-
- '@vue/server-renderer@3.5.17(vue@3.5.17(typescript@5.6.3))':
- dependencies:
- '@vue/compiler-ssr': 3.5.17
- '@vue/shared': 3.5.17
- vue: 3.5.17(typescript@5.6.3)
-
- '@vue/shared@3.5.17': {}
-
- '@vueuse/core@11.3.0(vue@packages+vue)':
- dependencies:
- '@types/web-bluetooth': 0.0.20
- '@vueuse/metadata': 11.3.0
- '@vueuse/shared': 11.3.0(vue@packages+vue)
- vue-demi: 0.14.10(vue@packages+vue)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
-
- '@vueuse/metadata@11.3.0': {}
-
- '@vueuse/shared@11.3.0(vue@packages+vue)':
- dependencies:
- vue-demi: 0.14.10(vue@packages+vue)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
-
'@zeit/schemas@2.36.0': {}
accepts@1.3.8:
mime-types: 2.1.35
negotiator: 0.6.3
- acorn-jsx@5.3.2(acorn@8.15.0):
+ acorn-jsx@5.3.2(acorn@8.14.0):
dependencies:
- acorn: 8.15.0
+ acorn: 8.14.0
acorn@7.4.1: {}
- acorn@8.15.0: {}
+ acorn@8.14.0: {}
add-stream@1.0.0: {}
ansi-regex@5.0.1: {}
- ansi-regex@6.1.0: {}
+ ansi-regex@6.0.1: {}
ansi-styles@4.3.0:
dependencies:
asap@2.0.6: {}
- assert-never@1.4.0: {}
+ assert-never@1.3.0: {}
assertion-error@2.0.1: {}
dependencies:
tslib: 2.8.1
- ast-v8-to-istanbul@0.3.3:
- dependencies:
- '@jridgewell/trace-mapping': 0.3.29
- estree-walker: 3.0.3
- js-tokens: 9.0.1
-
- b4a@1.6.7: {}
+ b4a@1.6.6: {}
babel-walk@3.0.0-canary-5:
dependencies:
- '@babel/types': 7.28.0
+ '@babel/types': 7.27.6
balanced-match@1.0.2: {}
- bare-events@2.5.4:
+ bare-events@2.4.2:
optional: true
- bare-fs@4.1.5:
+ bare-fs@4.0.1:
dependencies:
- bare-events: 2.5.4
+ bare-events: 2.4.2
bare-path: 3.0.0
- bare-stream: 2.6.5(bare-events@2.5.4)
+ bare-stream: 2.1.3
optional: true
- bare-os@3.6.1:
+ bare-os@3.4.0:
optional: true
bare-path@3.0.0:
dependencies:
- bare-os: 3.6.1
+ bare-os: 3.4.0
optional: true
- bare-stream@2.6.5(bare-events@2.5.4):
+ bare-stream@2.1.3:
dependencies:
- streamx: 2.22.1
- optionalDependencies:
- bare-events: 2.5.4
+ streamx: 2.18.0
optional: true
basic-ftp@5.0.5: {}
dependencies:
ansi-align: 3.0.1
camelcase: 7.0.1
- chalk: 5.0.1
+ chalk: 5.4.1
cli-boxes: 3.0.0
string-width: 5.1.2
type-fest: 2.19.0
widest-line: 4.0.1
wrap-ansi: 8.1.0
- brace-expansion@1.1.12:
+ brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
- brace-expansion@2.0.2:
+ brace-expansion@2.0.1:
dependencies:
balanced-match: 1.0.2
buffer-crc32@0.2.13: {}
- bundle-name@4.1.0:
- dependencies:
- run-applescript: 7.0.0
-
bytes@3.0.0: {}
cac@6.7.14: {}
- call-bind-apply-helpers@1.0.2:
+ call-bind@1.0.7:
dependencies:
+ es-define-property: 1.0.0
es-errors: 1.3.0
function-bind: 1.1.2
-
- call-bound@1.0.4:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- get-intrinsic: 1.3.0
+ get-intrinsic: 1.2.4
+ set-function-length: 1.2.2
callsites@3.1.0: {}
assertion-error: 2.0.1
check-error: 2.1.1
deep-eql: 5.0.2
- loupe: 3.1.4
- pathval: 2.0.1
+ loupe: 3.1.3
+ pathval: 2.0.0
chalk-template@0.4.0:
dependencies:
character-parser@2.2.0:
dependencies:
- is-regex: 1.2.1
+ is-regex: 1.1.4
check-error@2.1.1: {}
- chokidar@4.0.3:
+ chokidar@4.0.1:
dependencies:
- readdirp: 4.1.2
+ readdirp: 4.0.1
chromium-bidi@5.1.0(devtools-protocol@0.0.1439962):
dependencies:
devtools-protocol: 0.0.1439962
mitt: 3.0.1
- zod: 3.25.72
+ zod: 3.24.1
cli-boxes@3.0.0: {}
colorette@2.0.20: {}
- commander@14.0.0: {}
+ commander@13.1.0: {}
comment-parser@1.4.1: {}
compressible@2.0.18:
dependencies:
- mime-db: 1.54.0
+ mime-db: 1.53.0
compression@1.7.4:
dependencies:
concat-map@0.0.1: {}
- 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.28.0
- '@babel/types': 7.28.0
+ '@babel/parser': 7.27.5
+ '@babel/types': 7.27.6
content-disposition@0.5.2: {}
dependencies:
'@hutson/parse-repository-url': 5.0.0
add-stream: 1.0.0
- conventional-changelog-writer: 8.1.0
- conventional-commits-parser: 6.2.0
- git-raw-commits: 5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0)
- git-semver-tags: 8.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0)
+ conventional-changelog-writer: 8.0.0
+ conventional-commits-parser: 6.0.0
+ git-raw-commits: 5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0)
+ git-semver-tags: 8.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0)
hosted-git-info: 7.0.2
normalize-package-data: 6.0.2
read-package-up: 11.0.0
conventional-changelog-preset-loader@5.0.0: {}
- conventional-changelog-writer@8.1.0:
+ conventional-changelog-writer@8.0.0:
dependencies:
+ '@types/semver': 7.7.0
conventional-commits-filter: 5.0.0
handlebars: 4.7.8
meow: 13.2.0
conventional-commits-filter@5.0.0: {}
- conventional-commits-parser@6.2.0:
+ conventional-commits-parser@6.0.0:
dependencies:
meow: 13.2.0
cosmiconfig@9.0.0(typescript@5.6.3):
dependencies:
env-paths: 2.2.1
- import-fresh: 3.3.1
+ import-fresh: 3.3.0
js-yaml: 4.1.0
parse-json: 5.2.0
optionalDependencies:
cssesc@3.0.0: {}
- cssstyle@4.6.0:
+ cssstyle@4.2.1:
dependencies:
- '@asamuzakjp/css-color': 3.2.0
+ '@asamuzakjp/css-color': 2.8.2
rrweb-cssom: 0.8.0
csstype@3.1.3: {}
dependencies:
ms: 2.0.0
+ debug@3.2.7:
+ dependencies:
+ ms: 2.1.3
+
+ debug@4.4.0:
+ dependencies:
+ ms: 2.1.3
+
debug@4.4.1:
dependencies:
ms: 2.1.3
deepmerge@4.3.1: {}
- default-browser-id@5.0.0: {}
-
- default-browser@5.2.1:
+ define-data-property@1.1.4:
dependencies:
- bundle-name: 4.1.0
- default-browser-id: 5.0.0
-
- define-lazy-prop@3.0.0: {}
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ gopd: 1.0.1
degenerator@5.0.1:
dependencies:
dependencies:
is-obj: 2.0.0
- dunder-proto@1.0.1:
- dependencies:
- call-bind-apply-helpers: 1.0.2
- es-errors: 1.3.0
- gopd: 1.2.0
-
eastasianwidth@0.2.0: {}
- ee-first@1.1.1: {}
-
- emoji-regex@10.4.0: {}
+ emoji-regex@10.3.0: {}
emoji-regex@8.0.0: {}
emoji-regex@9.2.2: {}
- encodeurl@1.0.2: {}
-
- end-of-stream@1.4.5:
+ end-of-stream@1.4.4:
dependencies:
once: 1.4.0
entities@4.5.0: {}
- entities@6.0.1: {}
-
env-paths@2.2.1: {}
environment@1.1.0: {}
dependencies:
is-arrayish: 0.2.1
- error-stack-parser-es@0.1.5: {}
-
- es-define-property@1.0.1: {}
+ es-define-property@1.0.0:
+ dependencies:
+ get-intrinsic: 1.2.4
es-errors@1.3.0: {}
- es-module-lexer@1.7.0: {}
+ es-module-lexer@1.6.0: {}
- es-object-atoms@1.1.1:
- dependencies:
- es-errors: 1.3.0
+ es-module-lexer@1.7.0: {}
esbuild-plugin-polyfill-node@0.3.0(esbuild@0.25.5):
dependencies:
- '@jspm/core': 2.1.0
+ '@jspm/core': 2.0.1
esbuild: 0.25.5
import-meta-resolve: 3.1.1
'@esbuild/win32-ia32': 0.25.5
'@esbuild/win32-x64': 0.25.5
- escalade@3.2.0: {}
-
- escape-html@1.0.3: {}
+ escalade@3.1.2: {}
escape-string-regexp@4.0.0: {}
optionalDependencies:
source-map: 0.6.1
- eslint-import-context@0.1.9(unrs-resolver@1.10.1):
+ eslint-import-context@0.1.4(unrs-resolver@1.7.2):
dependencies:
get-tsconfig: 4.10.1
- stable-hash-x: 0.2.0
+ stable-hash: 0.0.5
optionalDependencies:
- unrs-resolver: 1.10.1
+ unrs-resolver: 1.7.2
- eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.35.1(eslint@9.30.1)(typescript@5.6.3))(eslint@9.30.1):
+ eslint-import-resolver-node@0.3.9:
dependencies:
- '@typescript-eslint/types': 8.35.1
+ debug: 3.2.7
+ is-core-module: 2.15.0
+ resolve: 1.22.8
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-plugin-import-x@4.13.1(eslint@9.27.0)(typescript@5.6.3):
+ dependencies:
+ '@typescript-eslint/utils': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
comment-parser: 1.4.1
debug: 4.4.1
- eslint: 9.30.1
- eslint-import-context: 0.1.9(unrs-resolver@1.10.1)
+ eslint: 9.27.0
+ eslint-import-context: 0.1.4(unrs-resolver@1.7.2)
+ eslint-import-resolver-node: 0.3.9
is-glob: 4.0.3
- minimatch: 10.0.3
+ minimatch: 10.0.1
semver: 7.7.2
- stable-hash-x: 0.2.0
- unrs-resolver: 1.10.1
- optionalDependencies:
- '@typescript-eslint/utils': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
+ stable-hash: 0.0.5
+ tslib: 2.8.1
+ unrs-resolver: 1.7.2
transitivePeerDependencies:
- supports-color
+ - typescript
- eslint-scope@8.4.0:
+ eslint-scope@8.3.0:
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
eslint-visitor-keys@3.4.3: {}
- eslint-visitor-keys@4.2.1: {}
+ eslint-visitor-keys@4.2.0: {}
- eslint@9.30.1:
+ eslint@9.27.0:
dependencies:
- '@eslint-community/eslint-utils': 4.7.0(eslint@9.30.1)
+ '@eslint-community/eslint-utils': 4.6.1(eslint@9.27.0)
'@eslint-community/regexpp': 4.12.1
- '@eslint/config-array': 0.21.0
- '@eslint/config-helpers': 0.3.0
+ '@eslint/config-array': 0.20.0
+ '@eslint/config-helpers': 0.2.1
'@eslint/core': 0.14.0
'@eslint/eslintrc': 3.3.1
- '@eslint/js': 9.30.1
- '@eslint/plugin-kit': 0.3.3
+ '@eslint/js': 9.27.0
+ '@eslint/plugin-kit': 0.3.1
'@humanfs/node': 0.16.6
'@humanwhocodes/module-importer': 1.0.1
- '@humanwhocodes/retry': 0.4.3
- '@types/estree': 1.0.8
+ '@humanwhocodes/retry': 0.4.2
+ '@types/estree': 1.0.7
'@types/json-schema': 7.0.15
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.6
- debug: 4.4.1
+ debug: 4.4.0
escape-string-regexp: 4.0.0
- eslint-scope: 8.4.0
- eslint-visitor-keys: 4.2.1
- espree: 10.4.0
+ eslint-scope: 8.3.0
+ eslint-visitor-keys: 4.2.0
+ espree: 10.3.0
esquery: 1.6.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
transitivePeerDependencies:
- supports-color
- espree@10.4.0:
+ espree@10.3.0:
dependencies:
- acorn: 8.15.0
- acorn-jsx: 5.3.2(acorn@8.15.0)
- eslint-visitor-keys: 4.2.1
+ acorn: 8.14.0
+ acorn-jsx: 5.3.2(acorn@8.14.0)
+ eslint-visitor-keys: 4.2.0
esprima@4.0.1: {}
dependencies:
pend: 1.2.0
- fdir@6.4.6(picomatch@4.0.2):
+ fdir@6.4.4(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
dependencies:
to-regex-range: 5.0.1
- finalhandler@1.1.2:
- dependencies:
- debug: 2.6.9
- encodeurl: 1.0.2
- escape-html: 1.0.3
- on-finished: 2.3.0
- parseurl: 1.3.3
- statuses: 1.5.0
- unpipe: 1.0.0
- transitivePeerDependencies:
- - supports-color
-
- find-up-simple@1.0.1: {}
+ find-up-simple@1.0.0: {}
find-up@5.0.0:
dependencies:
flat-cache@4.0.1:
dependencies:
- flatted: 3.3.3
+ flatted: 3.3.1
keyv: 4.5.4
- flatted@3.3.3: {}
+ flatted@3.3.1: {}
- foreground-child@3.3.1:
+ foreground-child@3.3.0:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
- fs-extra@11.3.0:
+ fs-extra@11.2.0:
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.1.0
get-caller-file@2.0.5: {}
- get-east-asian-width@1.3.0: {}
+ get-east-asian-width@1.2.0: {}
- get-intrinsic@1.3.0:
+ get-intrinsic@1.2.4:
dependencies:
- call-bind-apply-helpers: 1.0.2
- es-define-property: 1.0.1
es-errors: 1.3.0
- es-object-atoms: 1.1.1
function-bind: 1.1.2
- get-proto: 1.0.1
- gopd: 1.2.0
- has-symbols: 1.1.0
+ has-proto: 1.0.3
+ has-symbols: 1.0.3
hasown: 2.0.2
- math-intrinsics: 1.1.0
-
- get-proto@1.0.1:
- dependencies:
- dunder-proto: 1.0.1
- es-object-atoms: 1.1.1
get-stream@5.2.0:
dependencies:
- pump: 3.0.3
+ pump: 3.0.0
get-stream@6.0.1: {}
+ get-tsconfig@4.10.0:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
get-tsconfig@4.10.1:
dependencies:
resolve-pkg-maps: 1.0.0
- get-uri@6.0.4:
+ get-uri@6.0.3:
dependencies:
basic-ftp: 5.0.5
data-uri-to-buffer: 6.0.2
debug: 4.4.1
+ fs-extra: 11.2.0
transitivePeerDependencies:
- supports-color
- git-raw-commits@5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0):
+ git-raw-commits@5.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0):
dependencies:
- '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0)
+ '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0)
meow: 13.2.0
transitivePeerDependencies:
- conventional-commits-filter
- conventional-commits-parser
- git-semver-tags@8.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0):
+ git-semver-tags@8.0.0(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0):
dependencies:
- '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.2.0)
+ '@conventional-changelog/git-client': 1.0.1(conventional-commits-filter@5.0.0)(conventional-commits-parser@6.0.0)
meow: 13.2.0
transitivePeerDependencies:
- conventional-commits-filter
glob@10.4.5:
dependencies:
- foreground-child: 3.3.1
+ foreground-child: 3.3.0
jackspeak: 3.4.3
minimatch: 9.0.5
minipass: 7.1.2
- package-json-from-dist: 1.0.1
+ package-json-from-dist: 1.0.0
path-scurry: 1.11.1
- glob@11.0.3:
+ glob@11.0.0:
dependencies:
- foreground-child: 3.3.1
- jackspeak: 4.1.1
+ foreground-child: 3.3.0
+ jackspeak: 4.0.1
minimatch: 10.0.3
minipass: 7.1.2
- package-json-from-dist: 1.0.1
+ package-json-from-dist: 1.0.0
path-scurry: 2.0.0
globals@14.0.0: {}
- gopd@1.2.0: {}
+ gopd@1.0.1:
+ dependencies:
+ get-intrinsic: 1.2.4
graceful-fs@4.2.11: {}
source-map: 0.6.1
wordwrap: 1.0.0
optionalDependencies:
- uglify-js: 3.19.3
+ uglify-js: 3.19.1
has-flag@4.0.0: {}
- has-symbols@1.1.0: {}
+ has-property-descriptors@1.0.2:
+ dependencies:
+ es-define-property: 1.0.0
+
+ has-proto@1.0.3: {}
+
+ has-symbols@1.0.3: {}
has-tostringtag@1.0.2:
dependencies:
- has-symbols: 1.1.0
+ has-symbols: 1.0.3
hash-sum@2.0.0: {}
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.3
- debug: 4.4.1
+ debug: 4.4.0
transitivePeerDependencies:
- supports-color
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.3
- debug: 4.4.1
+ debug: 4.4.0
transitivePeerDependencies:
- supports-color
ignore@5.3.2: {}
- ignore@7.0.5: {}
+ ignore@7.0.4: {}
immediate@3.0.6: {}
- immutable@5.1.3: {}
+ immutable@5.0.2: {}
- import-fresh@3.3.1:
+ import-fresh@3.3.0:
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
imurmurhash@0.1.4: {}
- index-to-position@1.1.0: {}
+ index-to-position@0.1.2: {}
inherits@2.0.4: {}
is-arrayish@0.2.1: {}
- is-core-module@2.16.1:
+ is-core-module@2.15.0:
dependencies:
hasown: 2.0.2
is-docker@2.2.1: {}
- is-docker@3.0.0: {}
-
is-expression@4.0.0:
dependencies:
acorn: 7.4.1
is-fullwidth-code-point@5.0.0:
dependencies:
- get-east-asian-width: 1.3.0
+ get-east-asian-width: 1.2.0
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
- is-inside-container@1.0.0:
- dependencies:
- is-docker: 3.0.0
-
is-module@1.0.0: {}
is-number@7.0.0: {}
is-reference@1.2.1:
dependencies:
- '@types/estree': 1.0.8
+ '@types/estree': 1.0.7
- is-regex@1.2.1:
+ is-regex@1.1.4:
dependencies:
- call-bound: 1.0.4
- gopd: 1.2.0
+ call-bind: 1.0.7
has-tostringtag: 1.0.2
- hasown: 2.0.2
is-stream@2.0.1: {}
dependencies:
is-docker: 2.2.1
- is-wsl@3.1.0:
- dependencies:
- is-inside-container: 1.0.0
-
isarray@1.0.0: {}
isexe@2.0.0: {}
istanbul-lib-source-maps@5.0.6:
dependencies:
- '@jridgewell/trace-mapping': 0.3.29
- debug: 4.4.1
+ '@jridgewell/trace-mapping': 0.3.25
+ debug: 4.4.0
istanbul-lib-coverage: 3.2.2
transitivePeerDependencies:
- supports-color
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
- jackspeak@4.1.1:
+ jackspeak@4.0.1:
dependencies:
'@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
js-stringify@1.0.2: {}
js-tokens@4.0.0: {}
- js-tokens@9.0.1: {}
-
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
jsdom@26.1.0:
dependencies:
- cssstyle: 4.6.0
+ cssstyle: 4.2.1
data-urls: 5.0.0
decimal.js: 10.5.0
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
is-potential-custom-element-name: 1.0.1
- nwsapi: 2.2.20
- parse5: 7.3.0
+ nwsapi: 2.2.16
+ parse5: 7.2.1
rrweb-cssom: 0.8.0
saxes: 6.0.0
symbol-tree: 3.2.4
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.2.0
- ws: 8.18.3
+ ws: 8.18.1
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
lines-and-columns@1.2.4: {}
- lint-staged@16.1.2:
+ lint-staged@16.0.0:
dependencies:
chalk: 5.4.1
- commander: 14.0.0
+ commander: 13.1.0
debug: 4.4.1
lilconfig: 3.1.3
listr2: 8.3.3
strip-ansi: 7.1.0
wrap-ansi: 9.0.0
- loupe@3.1.4: {}
+ loupe@3.1.3: {}
lru-cache@10.1.0: {}
lru-cache@10.4.3: {}
- lru-cache@11.1.0: {}
+ lru-cache@11.0.0: {}
+
+ lru-cache@11.0.2: {}
lru-cache@7.18.3: {}
magic-string@0.30.17:
dependencies:
- '@jridgewell/sourcemap-codec': 1.5.4
+ '@jridgewell/sourcemap-codec': 1.5.0
magicast@0.3.5:
dependencies:
- '@babel/parser': 7.28.0
- '@babel/types': 7.28.0
+ '@babel/parser': 7.27.5
+ '@babel/types': 7.27.6
source-map-js: 1.2.1
make-dir@4.0.0:
marked@13.0.3: {}
- math-intrinsics@1.1.0: {}
-
memorystream@0.3.1: {}
meow@13.2.0: {}
mime-db@1.52.0: {}
- mime-db@1.54.0: {}
+ mime-db@1.53.0: {}
mime-types@2.1.18:
dependencies:
mimic-function@5.0.1: {}
+ minimatch@10.0.1:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimatch@10.0.3:
dependencies:
'@isaacs/brace-expansion': 5.0.0
minimatch@3.1.2:
dependencies:
- brace-expansion: 1.1.12
+ brace-expansion: 1.1.11
minimatch@9.0.5:
dependencies:
- brace-expansion: 2.0.2
+ brace-expansion: 2.0.1
minimist@1.2.8: {}
monaco-editor@0.52.2: {}
- mrmime@2.0.1: {}
-
ms@2.0.0: {}
ms@2.1.3: {}
nanoid@3.3.11: {}
- napi-postinstall@0.3.0: {}
+ napi-postinstall@0.2.3: {}
natural-compare@1.4.0: {}
minimatch: 9.0.5
pidtree: 0.6.0
read-package-json-fast: 4.0.0
- shell-quote: 1.8.3
+ shell-quote: 1.8.1
which: 5.0.0
npm-run-path@4.0.1:
dependencies:
path-key: 3.1.1
- nwsapi@2.2.20: {}
+ nwsapi@2.2.16: {}
object-assign@4.1.1: {}
- on-finished@2.3.0:
- dependencies:
- ee-first: 1.1.1
-
on-headers@1.0.2: {}
once@1.4.0:
dependencies:
mimic-function: 5.0.1
- open@10.1.2:
- dependencies:
- default-browser: 5.2.1
- define-lazy-prop: 3.0.0
- is-inside-container: 1.0.0
- is-wsl: 3.1.0
-
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
dependencies:
p-limit: 3.1.0
- pac-proxy-agent@7.2.0:
+ pac-proxy-agent@7.1.0:
dependencies:
'@tootallnate/quickjs-emscripten': 0.23.0
agent-base: 7.1.3
debug: 4.4.1
- get-uri: 6.0.4
+ get-uri: 6.0.3
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
pac-resolver: 7.0.1
degenerator: 5.0.1
netmask: 2.0.2
- package-json-from-dist@1.0.1: {}
+ package-json-from-dist@1.0.0: {}
pako@1.0.11: {}
parse-json@5.2.0:
dependencies:
- '@babel/code-frame': 7.27.1
+ '@babel/code-frame': 7.26.2
error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
- parse-json@8.3.0:
+ parse-json@8.1.0:
dependencies:
- '@babel/code-frame': 7.27.1
- index-to-position: 1.1.0
- type-fest: 4.41.0
+ '@babel/code-frame': 7.26.2
+ index-to-position: 0.1.2
+ type-fest: 4.24.0
- parse5@7.3.0:
+ parse5@7.2.1:
dependencies:
- entities: 6.0.1
-
- parseurl@1.3.3: {}
+ entities: 4.5.0
path-exists@4.0.0: {}
path-scurry@2.0.0:
dependencies:
- lru-cache: 11.1.0
+ lru-cache: 11.0.0
minipass: 7.1.2
path-to-regexp@3.3.0: {}
- pathe@1.1.2: {}
-
pathe@2.0.3: {}
- pathval@2.0.1: {}
+ pathval@2.0.0: {}
pend@1.2.0: {}
- perfect-debounce@1.0.0: {}
-
picocolors@1.1.1: {}
picomatch@2.3.1: {}
dependencies:
postcss: 8.5.6
- postcss-modules-local-by-default@4.2.0(postcss@8.5.6):
+ postcss-modules-local-by-default@4.0.5(postcss@8.5.6):
dependencies:
icss-utils: 5.1.0(postcss@8.5.6)
postcss: 8.5.6
- postcss-selector-parser: 7.1.0
+ postcss-selector-parser: 6.1.2
postcss-value-parser: 4.2.0
- postcss-modules-scope@3.2.1(postcss@8.5.6):
+ postcss-modules-scope@3.2.0(postcss@8.5.6):
dependencies:
postcss: 8.5.6
- postcss-selector-parser: 7.1.0
+ postcss-selector-parser: 6.1.2
postcss-modules-values@4.0.0(postcss@8.5.6):
dependencies:
lodash.camelcase: 4.3.0
postcss: 8.5.6
postcss-modules-extract-imports: 3.1.0(postcss@8.5.6)
- postcss-modules-local-by-default: 4.2.0(postcss@8.5.6)
- postcss-modules-scope: 3.2.1(postcss@8.5.6)
+ postcss-modules-local-by-default: 4.0.5(postcss@8.5.6)
+ postcss-modules-scope: 3.2.0(postcss@8.5.6)
postcss-modules-values: 4.0.0(postcss@8.5.6)
string-hash: 1.1.3
+ postcss-selector-parser@6.1.2:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
postcss-selector-parser@7.1.0:
dependencies:
cssesc: 3.0.0
prelude-ls@1.2.1: {}
- prettier@3.6.2: {}
+ prettier@3.5.3: {}
pretty-bytes@6.1.1: {}
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.6
lru-cache: 7.18.3
- pac-proxy-agent: 7.2.0
+ pac-proxy-agent: 7.1.0
proxy-from-env: 1.1.0
socks-proxy-agent: 8.0.5
transitivePeerDependencies:
jstransformer: 1.0.0
pug-error: 2.1.0
pug-walk: 2.0.0
- resolve: 1.22.10
+ resolve: 1.22.8
pug-lexer@5.0.1:
dependencies:
pug-runtime: 3.0.1
pug-strip-comments: 2.0.0
- pump@3.0.3:
+ pump@3.0.0:
dependencies:
- end-of-stream: 1.4.5
+ end-of-stream: 1.4.4
once: 1.4.0
punycode@2.3.1: {}
debug: 4.4.1
devtools-protocol: 0.0.1439962
typed-query-selector: 2.12.0
- ws: 8.18.3
+ ws: 8.18.2
transitivePeerDependencies:
- - bare-buffer
- bufferutil
- supports-color
- utf-8-validate
puppeteer-core: 24.9.0
typed-query-selector: 2.12.0
transitivePeerDependencies:
- - bare-buffer
- bufferutil
- supports-color
- typescript
queue-microtask@1.2.3: {}
+ queue-tick@1.0.1: {}
+
range-parser@1.2.0: {}
rc@1.2.8:
read-package-up@11.0.0:
dependencies:
- find-up-simple: 1.0.1
+ find-up-simple: 1.0.0
read-pkg: 9.0.1
- type-fest: 4.41.0
+ type-fest: 4.24.0
read-pkg@9.0.1:
dependencies:
'@types/normalize-package-data': 2.4.4
normalize-package-data: 6.0.2
- parse-json: 8.3.0
- type-fest: 4.41.0
+ parse-json: 8.1.0
+ type-fest: 4.24.0
unicorn-magic: 0.1.0
readable-stream@2.3.8:
string_decoder: 1.1.1
util-deprecate: 1.0.2
- readdirp@4.1.2: {}
+ readdirp@4.0.1: {}
registry-auth-token@3.3.2:
dependencies:
resolve-pkg-maps@1.0.0: {}
- resolve@1.22.10:
+ resolve@1.22.8:
dependencies:
- is-core-module: 2.16.1
+ is-core-module: 2.15.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
rimraf@6.0.1:
dependencies:
- glob: 11.0.3
- package-json-from-dist: 1.0.1
+ glob: 11.0.0
+ package-json-from-dist: 1.0.0
rollup-plugin-dts@6.2.1(rollup@4.44.1)(typescript@5.6.3):
dependencies:
rollup: 4.44.1
typescript: 5.6.3
optionalDependencies:
- '@babel/code-frame': 7.27.1
+ '@babel/code-frame': 7.26.2
rollup-plugin-esbuild@6.2.1(esbuild@0.25.5)(rollup@4.44.1):
dependencies:
- debug: 4.4.1
- es-module-lexer: 1.7.0
+ debug: 4.4.0
+ es-module-lexer: 1.6.0
esbuild: 0.25.5
- get-tsconfig: 4.10.1
+ get-tsconfig: 4.10.0
rollup: 4.44.1
unplugin-utils: 0.2.4
transitivePeerDependencies:
rrweb-cssom@0.8.0: {}
- run-applescript@7.0.0: {}
-
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
sass@1.89.2:
dependencies:
- chokidar: 4.0.3
- immutable: 5.1.3
+ chokidar: 4.0.1
+ immutable: 5.0.2
source-map-js: 1.2.1
optionalDependencies:
- '@parcel/watcher': 2.5.1
+ '@parcel/watcher': 2.4.1
saxes@6.0.0:
dependencies:
transitivePeerDependencies:
- supports-color
+ set-function-length@1.2.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+
setimmediate@1.0.5: {}
shebang-command@2.0.0:
shebang-regex@3.0.0: {}
- shell-quote@1.8.3: {}
+ shell-quote@1.8.1: {}
siginfo@2.0.0: {}
simple-git-hooks@2.13.0: {}
- sirv@2.0.4:
- dependencies:
- '@polka/url': 1.0.0-next.29
- mrmime: 2.0.1
- totalist: 3.0.1
-
- sirv@3.0.1:
- dependencies:
- '@polka/url': 1.0.0-next.29
- mrmime: 2.0.1
- totalist: 3.0.1
-
slice-ansi@5.0.0:
dependencies:
ansi-styles: 6.2.1
dependencies:
agent-base: 7.1.3
debug: 4.4.1
- socks: 2.8.5
+ socks: 2.8.3
transitivePeerDependencies:
- supports-color
- socks@2.8.5:
+ socks@2.8.3:
dependencies:
ip-address: 9.0.5
smart-buffer: 4.2.0
spdx-correct@3.2.0:
dependencies:
spdx-expression-parse: 3.0.1
- spdx-license-ids: 3.0.21
+ spdx-license-ids: 3.0.18
spdx-exceptions@2.5.0: {}
spdx-expression-parse@3.0.1:
dependencies:
spdx-exceptions: 2.5.0
- spdx-license-ids: 3.0.21
+ spdx-license-ids: 3.0.18
- spdx-license-ids@3.0.21: {}
+ spdx-license-ids@3.0.18: {}
sprintf-js@1.1.3: {}
- stable-hash-x@0.2.0: {}
+ stable-hash@0.0.5: {}
stackback@0.0.2: {}
- statuses@1.5.0: {}
-
std-env@3.9.0: {}
- streamx@2.22.1:
+ streamx@2.18.0:
dependencies:
fast-fifo: 1.3.2
- text-decoder: 1.2.3
+ queue-tick: 1.0.1
+ text-decoder: 1.1.1
optionalDependencies:
- bare-events: 2.5.4
+ bare-events: 2.4.2
string-argv@0.3.2: {}
string-width@7.2.0:
dependencies:
- emoji-regex: 10.4.0
- get-east-asian-width: 1.3.0
+ emoji-regex: 10.3.0
+ get-east-asian-width: 1.2.0
strip-ansi: 7.1.0
string_decoder@1.1.1:
strip-ansi@7.1.0:
dependencies:
- ansi-regex: 6.1.0
+ ansi-regex: 6.0.1
strip-final-newline@2.0.0: {}
strip-json-comments@3.1.1: {}
- strip-literal@3.0.0:
- dependencies:
- js-tokens: 9.0.1
-
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
symbol-tree@3.2.4: {}
- tar-fs@3.1.0:
+ tar-fs@3.0.8:
dependencies:
- pump: 3.0.3
+ pump: 3.0.0
tar-stream: 3.1.7
optionalDependencies:
- bare-fs: 4.1.5
+ bare-fs: 4.0.1
bare-path: 3.0.0
- transitivePeerDependencies:
- - bare-buffer
tar-stream@3.1.7:
dependencies:
- b4a: 1.6.7
+ b4a: 1.6.6
fast-fifo: 1.3.2
- streamx: 2.22.1
+ streamx: 2.18.0
temp-dir@3.0.0: {}
glob: 10.4.5
minimatch: 9.0.5
- text-decoder@1.2.3:
+ text-decoder@1.1.1:
dependencies:
- b4a: 1.6.7
+ b4a: 1.6.6
tinybench@2.9.0: {}
tinyexec@0.3.2: {}
- tinyglobby@0.2.14:
+ tinyglobby@0.2.13:
dependencies:
- fdir: 6.4.6(picomatch@4.0.2)
+ fdir: 6.4.4(picomatch@4.0.2)
picomatch: 4.0.2
- tinypool@1.1.1: {}
+ tinypool@1.0.2: {}
tinyrainbow@2.0.0: {}
- tinyspy@4.0.3: {}
+ tinyspy@3.0.2: {}
tldts-core@6.1.86: {}
token-stream@1.0.0: {}
- totalist@3.0.1: {}
-
tough-cookie@5.1.2:
dependencies:
tldts: 6.1.86
type-fest@2.19.0: {}
- type-fest@4.41.0: {}
+ type-fest@4.24.0: {}
typed-query-selector@2.12.0: {}
- typescript-eslint@8.35.1(eslint@9.30.1)(typescript@5.6.3):
+ typescript-eslint@8.32.1(eslint@9.27.0)(typescript@5.6.3):
dependencies:
- '@typescript-eslint/eslint-plugin': 8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1)(typescript@5.6.3))(eslint@9.30.1)(typescript@5.6.3)
- '@typescript-eslint/parser': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
- '@typescript-eslint/utils': 8.35.1(eslint@9.30.1)(typescript@5.6.3)
- eslint: 9.30.1
+ '@typescript-eslint/eslint-plugin': 8.32.1(@typescript-eslint/parser@8.32.1(eslint@9.27.0)(typescript@5.6.3))(eslint@9.27.0)(typescript@5.6.3)
+ '@typescript-eslint/parser': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
+ '@typescript-eslint/utils': 8.32.1(eslint@9.27.0)(typescript@5.6.3)
+ eslint: 9.27.0
typescript: 5.6.3
transitivePeerDependencies:
- supports-color
typescript@5.6.3: {}
- uglify-js@3.19.3:
+ uglify-js@3.19.1:
optional: true
undici-types@6.21.0: {}
universalify@2.0.1: {}
- unpipe@1.0.0: {}
-
unplugin-utils@0.2.4:
dependencies:
pathe: 2.0.3
picomatch: 4.0.2
- unrs-resolver@1.10.1:
+ unrs-resolver@1.7.2:
dependencies:
- napi-postinstall: 0.3.0
+ napi-postinstall: 0.2.3
optionalDependencies:
- '@unrs/resolver-binding-android-arm-eabi': 1.10.1
- '@unrs/resolver-binding-android-arm64': 1.10.1
- '@unrs/resolver-binding-darwin-arm64': 1.10.1
- '@unrs/resolver-binding-darwin-x64': 1.10.1
- '@unrs/resolver-binding-freebsd-x64': 1.10.1
- '@unrs/resolver-binding-linux-arm-gnueabihf': 1.10.1
- '@unrs/resolver-binding-linux-arm-musleabihf': 1.10.1
- '@unrs/resolver-binding-linux-arm64-gnu': 1.10.1
- '@unrs/resolver-binding-linux-arm64-musl': 1.10.1
- '@unrs/resolver-binding-linux-ppc64-gnu': 1.10.1
- '@unrs/resolver-binding-linux-riscv64-gnu': 1.10.1
- '@unrs/resolver-binding-linux-riscv64-musl': 1.10.1
- '@unrs/resolver-binding-linux-s390x-gnu': 1.10.1
- '@unrs/resolver-binding-linux-x64-gnu': 1.10.1
- '@unrs/resolver-binding-linux-x64-musl': 1.10.1
- '@unrs/resolver-binding-wasm32-wasi': 1.10.1
- '@unrs/resolver-binding-win32-arm64-msvc': 1.10.1
- '@unrs/resolver-binding-win32-ia32-msvc': 1.10.1
- '@unrs/resolver-binding-win32-x64-msvc': 1.10.1
+ '@unrs/resolver-binding-darwin-arm64': 1.7.2
+ '@unrs/resolver-binding-darwin-x64': 1.7.2
+ '@unrs/resolver-binding-freebsd-x64': 1.7.2
+ '@unrs/resolver-binding-linux-arm-gnueabihf': 1.7.2
+ '@unrs/resolver-binding-linux-arm-musleabihf': 1.7.2
+ '@unrs/resolver-binding-linux-arm64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-arm64-musl': 1.7.2
+ '@unrs/resolver-binding-linux-ppc64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-riscv64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-riscv64-musl': 1.7.2
+ '@unrs/resolver-binding-linux-s390x-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-x64-gnu': 1.7.2
+ '@unrs/resolver-binding-linux-x64-musl': 1.7.2
+ '@unrs/resolver-binding-wasm32-wasi': 1.7.2
+ '@unrs/resolver-binding-win32-arm64-msvc': 1.7.2
+ '@unrs/resolver-binding-win32-ia32-msvc': 1.7.2
+ '@unrs/resolver-binding-win32-x64-msvc': 1.7.2
update-check@1.5.4:
dependencies:
util-deprecate@1.0.2: {}
- utils-merge@1.0.1: {}
-
validate-npm-package-license@3.0.4:
dependencies:
spdx-correct: 3.2.0
vary@1.1.2: {}
- vite-hyper-config@0.4.1(@types/node@22.16.0)(sass@1.89.2)(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)):
- dependencies:
- cac: 6.7.14
- picocolors: 1.1.1
- vite: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
- vite-node: 2.1.9(@types/node@22.16.0)(sass@1.89.2)
- transitivePeerDependencies:
- - '@types/node'
- - less
- - lightningcss
- - sass
- - sass-embedded
- - stylus
- - sugarss
- - supports-color
- - terser
-
- vite-node@2.1.9(@types/node@22.16.0)(sass@1.89.2):
- dependencies:
- cac: 6.7.14
- debug: 4.4.1
- es-module-lexer: 1.7.0
- pathe: 1.1.2
- vite: 5.4.19(@types/node@22.16.0)(sass@1.89.2)
- transitivePeerDependencies:
- - '@types/node'
- - less
- - lightningcss
- - sass
- - sass-embedded
- - stylus
- - sugarss
- - supports-color
- - terser
-
- vite-node@3.2.4(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0):
+ vite-node@3.1.4(@types/node@22.16.0)(sass@1.89.2):
dependencies:
cac: 6.7.14
debug: 4.4.1
es-module-lexer: 1.7.0
pathe: 2.0.3
- vite: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
+ vite: 5.4.19(@types/node@22.16.0)(sass@1.89.2)
transitivePeerDependencies:
- '@types/node'
- - jiti
- less
- lightningcss
- sass
- sugarss
- supports-color
- terser
- - tsx
- - yaml
- vite-plugin-inspect@0.8.9(rollup@4.44.1)(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)):
- dependencies:
- '@antfu/utils': 0.7.10
- '@rollup/pluginutils': 5.2.0(rollup@4.44.1)
- debug: 4.4.1
- error-stack-parser-es: 0.1.5
- fs-extra: 11.3.0
- open: 10.1.2
- perfect-debounce: 1.0.0
- picocolors: 1.1.1
- sirv: 3.0.1
- vite: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
- transitivePeerDependencies:
- - rollup
- - supports-color
-
- vite@5.4.19(@types/node@22.16.0)(sass@1.89.2):
+ vite@5.4.15(@types/node@22.16.0)(sass@1.89.2):
dependencies:
esbuild: 0.21.5
postcss: 8.5.6
fsevents: 2.3.3
sass: 1.89.2
- vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0):
+ vite@5.4.19(@types/node@22.16.0)(sass@1.89.2):
dependencies:
- esbuild: 0.25.5
- fdir: 6.4.6(picomatch@4.0.2)
- picomatch: 4.0.2
+ esbuild: 0.21.5
postcss: 8.5.6
rollup: 4.44.1
- tinyglobby: 0.2.14
optionalDependencies:
'@types/node': 22.16.0
fsevents: 2.3.3
sass: 1.89.2
- yaml: 2.8.0
- vitest@3.2.4(@types/node@22.16.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.89.2)(yaml@2.8.0):
+ vitest@3.1.4(@types/node@22.16.0)(jsdom@26.1.0)(sass@1.89.2):
dependencies:
- '@types/chai': 5.2.2
- '@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0))
- '@vitest/pretty-format': 3.2.4
- '@vitest/runner': 3.2.4
- '@vitest/snapshot': 3.2.4
- '@vitest/spy': 3.2.4
- '@vitest/utils': 3.2.4
+ '@vitest/expect': 3.1.4
+ '@vitest/mocker': 3.1.4(vite@5.4.19(@types/node@22.16.0)(sass@1.89.2))
+ '@vitest/pretty-format': 3.1.4
+ '@vitest/runner': 3.1.4
+ '@vitest/snapshot': 3.1.4
+ '@vitest/spy': 3.1.4
+ '@vitest/utils': 3.1.4
chai: 5.2.0
- debug: 4.4.1
+ debug: 4.4.0
expect-type: 1.2.1
magic-string: 0.30.17
pathe: 2.0.3
- picomatch: 4.0.2
std-env: 3.9.0
tinybench: 2.9.0
tinyexec: 0.3.2
- tinyglobby: 0.2.14
- tinypool: 1.1.1
+ tinyglobby: 0.2.13
+ tinypool: 1.0.2
tinyrainbow: 2.0.0
- vite: 6.3.5(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
- vite-node: 3.2.4(@types/node@22.16.0)(sass@1.89.2)(yaml@2.8.0)
+ vite: 5.4.19(@types/node@22.16.0)(sass@1.89.2)
+ vite-node: 3.1.4(@types/node@22.16.0)(sass@1.89.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.16.0
- '@vitest/ui': 3.2.4(vitest@3.2.4)
jsdom: 26.1.0
transitivePeerDependencies:
- - jiti
- less
- lightningcss
- msw
- sugarss
- supports-color
- terser
- - tsx
- - yaml
void-elements@3.1.0: {}
- vue-demi@0.14.10(vue@packages+vue):
- dependencies:
- vue: link:packages/vue
-
- vue@3.5.17(typescript@5.6.3):
- dependencies:
- '@vue/compiler-dom': 3.5.17
- '@vue/compiler-sfc': 3.5.17
- '@vue/runtime-dom': 3.5.17
- '@vue/server-renderer': 3.5.17(vue@3.5.17(typescript@5.6.3))
- '@vue/shared': 3.5.17
- optionalDependencies:
- typescript: 5.6.3
-
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
with@7.0.2:
dependencies:
- '@babel/parser': 7.28.0
- '@babel/types': 7.28.0
- assert-never: 1.4.0
+ '@babel/parser': 7.27.5
+ '@babel/types': 7.27.6
+ assert-never: 1.3.0
babel-walk: 3.0.0-canary-5
word-wrap@1.2.5: {}
wrappy@1.0.2: {}
- ws@8.18.3: {}
+ ws@8.18.1: {}
+
+ ws@8.18.2: {}
xml-name-validator@5.0.0: {}
yargs@17.7.2:
dependencies:
cliui: 8.0.1
- escalade: 3.2.0
+ escalade: 3.1.2
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
yocto-queue@0.1.0: {}
- zod@3.25.72: {}
+ zod@3.24.1: {}
'@babel/parser': ^7.27.5
'@babel/types': ^7.27.6
'estree-walker': ^2.0.2
- 'vite': ^6.1.0
- '@vitejs/plugin-vue': ^5.2.4
'magic-string': ^0.30.17
'source-map-js': ^1.2.1
+ 'vite': ^5.4.15
+ '@vitejs/plugin-vue': ^5.2.4
onlyBuiltDependencies:
- '@swc/core'
import { entries } from './scripts/aliases.js'
import { inlineEnums } from './scripts/inline-enums.js'
import { minify as minifySwc } from '@swc/core'
-import { trimVaporExportsPlugin } from './scripts/trim-vapor-exports.js'
/**
* @template T
* @template {keyof T} K
* @typedef { Omit<T, K> & Required<Pick<T, K>> } MarkRequired
*/
-/** @typedef {'cjs' | 'esm-bundler' | 'global' | 'global-runtime' | 'esm-browser' | 'esm-bundler-runtime' | 'esm-browser-runtime' | 'esm-browser-vapor'} PackageFormat */
+/** @typedef {'cjs' | 'esm-bundler' | 'global' | 'global-runtime' | 'esm-browser' | 'esm-bundler-runtime' | 'esm-browser-runtime'} PackageFormat */
/** @typedef {MarkRequired<import('rollup').OutputOptions, 'file' | 'format'>} OutputOptions */
if (!process.env.TARGET) {
file: resolve(`dist/${name}.runtime.global.js`),
format: 'iife',
},
- // The vapor format is a esm-browser + runtime only build that is meant for
- // the SFC playground only.
- 'esm-browser-vapor': {
- file: resolve(`dist/${name}.runtime-with-vapor.esm-browser.js`),
- format: 'es',
- },
}
/** @type {ReadonlyArray<PackageFormat>} */
const defaultFormats = ['esm-bundler', 'cjs']
/** @type {ReadonlyArray<PackageFormat>} */
const inlineFormats = /** @type {any} */ (
- process.env.FORMATS && process.env.FORMATS.split('+')
+ process.env.FORMATS && process.env.FORMATS.split(',')
)
/** @type {ReadonlyArray<PackageFormat>} */
const packageFormats = inlineFormats || packageOptions.formats || defaultFormats
if (format === 'cjs') {
packageConfigs.push(createProductionConfig(format))
}
- if (
- format === 'esm-browser-vapor' ||
- /^(global|esm-browser)(-runtime)?/.test(format)
- ) {
+ if (/^(global|esm-browser)(-runtime)?/.test(format)) {
packageConfigs.push(createMinifiedConfig(format))
}
})
output.name = packageOptions.name
}
- let entryFile = 'index.ts'
- if (pkg.name === 'vue') {
- if (format === 'esm-browser-vapor' || format === 'esm-bundler-runtime') {
- entryFile = 'runtime-with-vapor.ts'
- } else if (format === 'esm-bundler') {
- entryFile = 'index-with-vapor.ts'
- } else if (format.includes('runtime')) {
- entryFile = 'runtime.ts'
- }
- }
+ let entryFile = /runtime$/.test(format) ? `src/runtime.ts` : `src/index.ts`
// the compat build needs both default AND named exports. This will cause
// Rollup to complain for non-ESM targets, so we use separate entries for
// esm vs. non-esm builds.
if (isCompatPackage && (isBrowserESMBuild || isBundlerESMBuild)) {
- entryFile = `esm-${entryFile}`
- }
- entryFile = 'src/' + entryFile
-
- return {
- input: resolve(entryFile),
- // Global and Browser ESM builds inlines everything so that they can be
- // used alone.
- external: resolveExternal(),
- plugins: [
- ...trimVaporExportsPlugin(format, pkg.name),
- json({
- namedExports: false,
- }),
- alias({
- entries,
- }),
- enumPlugin,
- ...resolveReplace(),
- esbuild({
- tsconfig: path.resolve(__dirname, 'tsconfig.json'),
- sourceMap: output.sourcemap,
- minify: false,
- target: isServerRenderer || isCJSBuild ? 'es2019' : 'es2016',
- define: resolveDefine(),
- }),
- ...resolveNodePlugins(),
- ...plugins,
- ],
- output,
- onwarn(msg, warn) {
- if (msg.code !== 'CIRCULAR_DEPENDENCY') {
- warn(msg)
- }
- },
- treeshake: {
- moduleSideEffects: false,
- },
+ entryFile = /runtime$/.test(format)
+ ? `src/esm-runtime.ts`
+ : `src/esm-index.ts`
}
function resolveDefine() {
__CJS__: String(isCJSBuild),
// need SSR-specific branches?
__SSR__: String(!isGlobalBuild),
- __BENCHMARK__: process.env.BENCHMARK || 'false',
// 2.x compat build
__COMPAT__: String(isCompatBuild),
return nodePlugins
}
+
+ return {
+ input: resolve(entryFile),
+ // Global and Browser ESM builds inlines everything so that they can be
+ // used alone.
+ external: resolveExternal(),
+ plugins: [
+ json({
+ namedExports: false,
+ }),
+ alias({
+ entries,
+ }),
+ enumPlugin,
+ ...resolveReplace(),
+ esbuild({
+ tsconfig: path.resolve(__dirname, 'tsconfig.json'),
+ sourceMap: output.sourcemap,
+ minify: false,
+ target: isServerRenderer || isCJSBuild ? 'es2019' : 'es2016',
+ define: resolveDefine(),
+ }),
+ ...resolveNodePlugins(),
+ ...plugins,
+ ],
+ output,
+ onwarn: (msg, warn) => {
+ if (msg.code !== 'CIRCULAR_DEPENDENCY') {
+ warn(msg)
+ }
+ },
+ treeshake: {
+ moduleSideEffects: false,
+ },
+ }
}
function createProductionConfig(/** @type {PackageFormat} */ format) {
return createConfig(format, {
- ...outputConfigs[format],
file: resolve(`dist/${name}.${format}.prod.js`),
+ format: outputConfigs[format].format,
})
}
return createConfig(
format,
{
- ...outputConfigs[format],
file: outputConfigs[format].file.replace(/\.js$/, '.prod.js'),
+ format: outputConfigs[format].format,
},
[
{
/** @returns {import('rollup').RollupOptions} */
pkg => {
return {
- input: `./temp/packages/${pkg}/src/index${pkg === 'vue' ? '-with-vapor' : ''}.d.ts`,
+ input: `./temp/packages/${pkg}/src/index.d.ts`,
output: {
file: `packages/${pkg}/dist/${pkg}.d.ts`,
format: 'es',
To specify the package to build, simply pass its name and the desired build
formats to output (defaults to `buildOptions.formats` specified in that package,
-or ["esm-bundler", "cjs"]):
+or "esm,cjs"):
```
# name supports fuzzy match. will build all packages with name containing "dom":
nr build dom
# specify the format to output
-nr build vue -f cjs
-
-# to specify multiple formats, separate with "+":
-nr build vue -f esm-bundler+esm-browser
+nr build core --formats cjs
```
*/
return
}
- let resolvedFormats
- if (formats) {
- const isNegation = formats.startsWith('~')
- resolvedFormats = (isNegation ? formats.slice(1) : formats).split('+')
- const pkgFormats = pkg.buildOptions?.formats
- if (pkgFormats) {
- if (isNegation) {
- resolvedFormats = pkgFormats.filter(f => !resolvedFormats.includes(f))
- } else {
- resolvedFormats = resolvedFormats.filter(f => pkgFormats.includes(f))
- }
- }
- if (!resolvedFormats.length) {
- return
- }
- }
-
// if building a specific format, do not remove dist.
if (!formats && fs.existsSync(`${pkgDir}/dist`)) {
fs.rmSync(`${pkgDir}/dist`, { recursive: true })
`COMMIT:${commit}`,
`NODE_ENV:${env}`,
`TARGET:${target}`,
- resolvedFormats ? `FORMATS:${resolvedFormats.join('+')}` : ``,
+ formats ? `FORMATS:${formats}` : ``,
prodOnly ? `PROD_ONLY:true` : ``,
sourceMap ? `SOURCE_MAP:true` : ``,
]
* @returns {Promise<void>}
*/
async function checkAllSizes(targets) {
- if (
- devOnly ||
- (formats && (formats.startsWith('~') || !formats.includes('global')))
- ) {
+ if (devOnly || (formats && !formats.includes('global'))) {
return
}
console.log()
? 'cjs'
: 'esm'
-const postfix =
- format === 'esm-browser-vapor'
- ? 'runtime-with-vapor.esm-browser'
- : format.endsWith('-runtime')
- ? `runtime.${format.replace(/-runtime$/, '')}`
- : format
+const postfix = format.endsWith('-runtime')
+ ? `runtime.${format.replace(/-runtime$/, '')}`
+ : format
const privatePackages = fs.readdirSync('packages-private')
plugins.push(polyfillNode())
}
- const entry =
- format === 'esm-browser-vapor'
- ? 'runtime-with-vapor.ts'
- : format.endsWith('-runtime')
- ? 'runtime.ts'
- : 'index.ts'
-
esbuild
.context({
- entryPoints: [resolve(__dirname, `${pkgBasePath}/src/${entry}`)],
+ entryPoints: [resolve(__dirname, `${pkgBasePath}/src/index.ts`)],
outfile,
bundle: true,
external,
__ESM_BROWSER__: String(format.includes('esm-browser')),
__CJS__: String(format === 'cjs'),
__SSR__: String(format !== 'global'),
- __BENCHMARK__: process.env.BENCHMARK || 'false',
__COMPAT__: String(target === 'vue-compat'),
__FEATURE_SUSPENSE__: `true`,
__FEATURE_OPTIONS_API__: `true`,
}
// 3. save cache
- try {
- mkdirSync('temp')
- } catch {}
+ if (!existsSync('temp')) mkdirSync('temp')
/** @type {EnumData} */
const enumData = {
'compiler-core',
'compiler-dom',
'compiler-ssr',
- 'compiler-vapor',
'shared',
]
import enquirer from 'enquirer'
import { createRequire } from 'node:module'
import { fileURLToPath } from 'node:url'
-import { exec, getSha } from './utils.js'
+import { exec } from './utils.js'
import { parseArgs } from 'node:util'
/**
}
}
+async function getSha() {
+ return (await exec('git', ['rev-parse', 'HEAD'])).stdout
+}
+
async function getBranch() {
return (await exec('git', ['rev-parse', '--abbrev-ref', 'HEAD'])).stdout
}
+++ /dev/null
-// @ts-check
-
-/**
- * runtime-core exports a number of internal helpers that are only used by
- * runtime-vapor, which should be only preserved in vapor / esm-bundler builds.
- * This plugin should be included as the first plugin for all other formats
- * other than vapor / esm-bundler.
- *
- * @param {string} format
- * @param {string} pkgName
- * @returns {import('rollup').Plugin[]}
- */
-export function trimVaporExportsPlugin(format, pkgName) {
- if (
- format.includes('vapor') ||
- format.startsWith('esm-bundler') ||
- pkgName === '@vue/runtime-vapor'
- ) {
- return []
- } else {
- return [
- {
- name: 'trim-vapor-exports',
- transform(code, id) {
- if (
- id.endsWith('runtime-core/src/index.ts') ||
- id.endsWith('runtime-dom/src/index.ts')
- ) {
- const index = code.lastIndexOf('// VAPOR ---')
- return code.slice(0, index)
- }
- },
- },
- ]
- }
-}
})
const sizeDir = path.resolve('temp/size')
-const vuePath = path.resolve('./packages/vue/dist/vue.runtime.esm-bundler.js')
+const entry = path.resolve('./packages/vue/dist/vue.runtime.esm-bundler.js')
/**
* @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 {Record<string, string>} [replace]
*/
replace: { __VUE_OPTIONS_API__: 'false' },
},
{ name: 'createApp', imports: ['createApp'] },
- {
- name: 'createApp + vaporInteropPlugin',
- imports: ['createApp', 'vaporInteropPlugin'],
- },
- { name: 'createVaporApp', imports: ['createVaporApp'] },
{ name: 'createSSRApp', imports: ['createSSRApp'] },
{ name: 'defineCustomElement', imports: ['defineCustomElement'] },
{
*/
async function generateBundle(preset) {
const id = 'virtual:entry'
- const exportSpecifiers =
- preset.imports === '*'
- ? `* as ${preset.name}`
- : `{ ${preset.imports.join(', ')} }`
- const content = `export ${exportSpecifiers} from '${vuePath}'`
+ const content = `export { ${preset.imports.join(', ')} } from '${entry}'`
+
const result = await rollup({
input: id,
plugins: [
import pico from 'picocolors'
import { createRequire } from 'node:module'
import { spawn } from 'node:child_process'
-import path from 'node:path'
const require = createRequire(import.meta.url)
-const packagesPath = path.resolve(import.meta.dirname, '../packages')
export const targets = fs
- .readdirSync(packagesPath)
+ .readdirSync('packages')
.filter(f => {
- const folder = path.resolve(packagesPath, f)
if (
- !fs.statSync(folder).isDirectory() ||
- !fs.existsSync(`${folder}/package.json`)
+ !fs.statSync(`packages/${f}`).isDirectory() ||
+ !fs.existsSync(`packages/${f}/package.json`)
) {
return false
}
- const pkg = require(`${folder}/package.json`)
+ const pkg = require(`../packages/${f}/package.json`)
if (pkg.private && !pkg.buildOptions) {
return false
}
/** @type {Array<string>} */
const matched = []
partialTargets.forEach(partialTarget => {
- if (!includeAllMatching && targets.includes(partialTarget)) {
- matched.push(partialTarget)
- return
- }
for (const target of targets) {
if (target.match(partialTarget)) {
matched.push(target)
* @param {string} command
* @param {ReadonlyArray<string>} args
* @param {object} [options]
- * @returns {Promise<{ ok: boolean, code: number | null, stderr: string, stdout: string }>}
*/
export async function exec(command, args, options) {
return new Promise((resolve, reject) => {
})
})
}
-
-/**
- * @param {boolean=} short
- */
-export async function getSha(short) {
- return (
- await exec('git', ['rev-parse', ...(short ? ['--short'] : []), 'HEAD'])
- ).stdout
-}
"paths": {
"@vue/compat": ["packages/vue-compat/src"],
"@vue/*": ["packages/*/src"],
- "vue": ["packages/vue/src/runtime-with-vapor.ts"]
+ "vue": ["packages/vue/src"]
},
"isolatedDeclarations": true,
"composite": true
-import { configDefaults, defineConfig } from 'vitest/config'
+import { defineConfig } from 'vitest/config'
import { entries } from './scripts/aliases.js'
export default defineConfig({
__ESM_BROWSER__: false,
__CJS__: true,
__SSR__: true,
- __BENCHMARK__: false,
__FEATURE_OPTIONS_API__: true,
__FEATURE_SUSPENSE__: true,
__FEATURE_PROD_DEVTOOLS__: false,
},
},
setupFiles: 'scripts/setup-vitest.ts',
+ environmentMatchGlobs: [
+ ['packages/{vue,vue-compat,runtime-dom}/**', 'jsdom'],
+ ],
sequence: {
hooks: 'list',
},
'packages/runtime-dom/src/components/Transition*',
],
},
- workspace: [
- {
- extends: true,
- test: {
- name: 'unit',
- exclude: [
- ...configDefaults.exclude,
- '**/e2e/**',
- '**/vapor-e2e-test/**',
- 'packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**',
- ],
- },
- },
- {
- extends: true,
- test: {
- name: 'unit-jsdom',
- environment: 'jsdom',
- include: [
- 'packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**/*.spec.ts',
- ],
- exclude: [...configDefaults.exclude, '**/e2e/**'],
- },
- },
- {
- extends: true,
- test: {
- name: 'e2e',
- poolOptions: {
- threads: {
- singleThread: !!process.env.CI,
- },
- },
- include: ['packages/vue/__tests__/e2e/*.spec.ts'],
- },
- },
- {
- extends: true,
- test: {
- name: 'e2e-vapor',
- poolOptions: {
- threads: {
- singleThread: !!process.env.CI,
- },
- },
- include: ['packages-private/vapor-e2e-test/__tests__/*.spec.ts'],
- },
- },
- ],
},
})
--- /dev/null
+import { mergeConfig } from 'vitest/config'
+import config from './vitest.config'
+
+export default mergeConfig(config, {
+ test: {
+ name: 'e2e',
+ poolOptions: {
+ threads: {
+ singleThread: !!process.env.CI,
+ },
+ },
+ include: ['packages/vue/__tests__/e2e/*.spec.ts'],
+ },
+})
--- /dev/null
+import { configDefaults, mergeConfig } from 'vitest/config'
+import config from './vitest.config'
+
+export default mergeConfig(config, {
+ test: {
+ name: 'unit',
+ exclude: [...configDefaults.exclude, '**/e2e/**'],
+ },
+})
--- /dev/null
+import { defineWorkspace } from 'vitest/config'
+
+export default defineWorkspace([
+ './vitest.unit.config.ts',
+ './vitest.e2e.config.ts',
+])