mirror of https://github.com/vuejs/core.git
Merge bb4ae25793
into 77067abd33
This commit is contained in:
commit
54440580d1
|
@ -290,27 +290,39 @@ This is made possible via several configurations:
|
|||
|
||||
```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:
|
||||
|
|
|
@ -9,6 +9,7 @@ on:
|
|||
branches:
|
||||
- main
|
||||
- minor
|
||||
- vapor
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
@ -16,7 +17,7 @@ jobs:
|
|||
uses: ./.github/workflows/test.yml
|
||||
|
||||
continuous-release:
|
||||
if: github.repository == 'vuejs/core'
|
||||
if: github.repository == 'vuejs/core' && github.ref_name != 'vapor'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
|
|
@ -80,6 +80,32 @@ jobs:
|
|||
- 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:
|
||||
|
|
|
@ -11,3 +11,4 @@ TODOs.md
|
|||
dts-build/packages
|
||||
*.tsbuildinfo
|
||||
*.tgz
|
||||
packages-private/benchmark/reference
|
||||
|
|
|
@ -14,5 +14,6 @@
|
|||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"editor.formatOnSave": true
|
||||
"editor.formatOnSave": true,
|
||||
"vitest.disableWorkspaceWarning": true
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ export default tseslint.config(
|
|||
|
||||
// Packages targeting DOM
|
||||
{
|
||||
files: ['packages/{vue,vue-compat,runtime-dom}/**'],
|
||||
files: ['packages/{vue,vue-compat,runtime-dom,runtime-vapor}/**'],
|
||||
rules: {
|
||||
'no-restricted-globals': ['error', ...NodeGlobals],
|
||||
},
|
||||
|
@ -126,6 +126,7 @@ export default tseslint.config(
|
|||
files: [
|
||||
'packages-private/template-explorer/**',
|
||||
'packages-private/sfc-playground/**',
|
||||
'packages-private/local-playground/**',
|
||||
],
|
||||
rules: {
|
||||
'no-restricted-globals': ['error', ...NodeGlobals],
|
||||
|
@ -152,6 +153,8 @@ export default tseslint.config(
|
|||
'./*.{js,ts}',
|
||||
'packages/*/*.js',
|
||||
'packages/vue/*/*.js',
|
||||
'packages-private/benchmark/*',
|
||||
'packages-private/e2e-utils/*',
|
||||
],
|
||||
rules: {
|
||||
'no-restricted-globals': 'off',
|
||||
|
|
29
package.json
29
package.json
|
@ -9,16 +9,18 @@
|
|||
"build-dts": "tsc -p tsconfig.build.json --noCheck && rollup -c rollup.dts.config.js",
|
||||
"clean": "rimraf --glob packages/*/dist temp .eslintcache",
|
||||
"size": "run-s \"size-*\" && node scripts/usage-size.js",
|
||||
"size-global": "node scripts/build.js vue runtime-dom -f global -p --size",
|
||||
"size-global": "node scripts/build.js vue runtime-dom compiler-dom -f global -p --size",
|
||||
"size-esm-runtime": "node scripts/build.js vue -f esm-bundler-runtime",
|
||||
"size-esm": "node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler",
|
||||
"size-esm": "node scripts/build.js runtime-shared runtime-dom runtime-core reactivity shared runtime-vapor -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",
|
||||
"test-unit": "vitest --project unit --project unit-jsdom",
|
||||
"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",
|
||||
|
@ -29,19 +31,17 @@
|
|||
"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-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",
|
||||
"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",
|
||||
"serve": "serve",
|
||||
"open": "open http://localhost:3000/packages-private/template-explorer/local.html",
|
||||
"build-sfc-playground": "run-s build-all-cjs build-runtime-esm build-browser-esm build-ssr-esm build-sfc-playground-self",
|
||||
"build-all-cjs": "node scripts/build.js vue runtime compiler reactivity shared -af cjs",
|
||||
"build-runtime-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler-runtime && node scripts/build.js vue -f esm-browser-runtime",
|
||||
"build-browser-esm": "node scripts/build.js runtime reactivity shared -af esm-bundler && node scripts/build.js vue -f esm-bundler && node scripts/build.js vue -f esm-browser",
|
||||
"build-ssr-esm": "node scripts/build.js compiler-sfc server-renderer -f esm-browser",
|
||||
"build-sfc-playground-self": "cd packages-private/sfc-playground && npm run build",
|
||||
"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",
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"postinstall": "simple-git-hooks"
|
||||
},
|
||||
|
@ -74,6 +74,7 @@
|
|||
"@types/node": "^22.14.1",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@types/serve-handler": "^6.1.4",
|
||||
"@vitest/ui": "^3.0.2",
|
||||
"@vitest/coverage-v8": "^3.1.3",
|
||||
"@vitest/eslint-plugin": "^1.1.44",
|
||||
"@vue/consolidate": "1.0.0",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
results/*
|
|
@ -0,0 +1,136 @@
|
|||
<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>
|
|
@ -0,0 +1,136 @@
|
|||
<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>
|
|
@ -0,0 +1,78 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<!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>
|
|
@ -0,0 +1,5 @@
|
|||
if (import.meta.env.IS_VAPOR) {
|
||||
import('./vapor')
|
||||
} else {
|
||||
import('./vdom')
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/* 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)
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
import { createVaporApp } from 'vue'
|
||||
import App from './AppVapor.vue'
|
||||
|
||||
createVaporApp(App as any).mount('#app')
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).mount('#app')
|
|
@ -0,0 +1,393 @@
|
|||
// @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)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"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": ["**/*"]
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<!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>
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// @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`,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// @ts-check
|
||||
|
||||
import { startVite } from 'vite-hyper-config'
|
||||
import { DevPlugin } from './dev.js'
|
||||
|
||||
startVite(
|
||||
undefined,
|
||||
{ plugins: [DevPlugin()] },
|
||||
{
|
||||
deps: {
|
||||
inline: ['@vitejs/plugin-vue'],
|
||||
},
|
||||
},
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
*
|
||||
!.gitignore
|
||||
!App.vue
|
||||
!main.ts
|
||||
!style.css
|
|
@ -0,0 +1,20 @@
|
|||
<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>
|
|
@ -0,0 +1 @@
|
|||
import './_entry'
|
|
@ -0,0 +1,6 @@
|
|||
.red {
|
||||
color: red;
|
||||
}
|
||||
.green {
|
||||
color: green;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"isolatedDeclarations": false,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["./**/*", "../../packages/*/src"]
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
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'],
|
||||
},
|
||||
})
|
|
@ -0,0 +1,26 @@
|
|||
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,
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
|
@ -1,6 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import Header from './Header.vue'
|
||||
import { Repl, useStore, SFCOptions, useVueImportMap } from '@vue/repl'
|
||||
import {
|
||||
Repl,
|
||||
type SFCOptions,
|
||||
useStore,
|
||||
useVueImportMap,
|
||||
StoreState,
|
||||
} from '@vue/repl'
|
||||
import Monaco from '@vue/repl/monaco-editor'
|
||||
import { ref, watchEffect, onMounted, computed } from 'vue'
|
||||
|
||||
|
@ -20,13 +26,17 @@ const initAutoSave: boolean = JSON.parse(
|
|||
)
|
||||
const autoSave = ref(initAutoSave)
|
||||
|
||||
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`,
|
||||
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`
|
||||
},
|
||||
serverRenderer: import.meta.env.PROD
|
||||
? `${location.origin}/server-renderer.esm-browser.js`
|
||||
: `${location.origin}/src/vue-server-renderer-dev-proxy`,
|
||||
|
@ -46,6 +56,8 @@ if (hash.startsWith('__SSR__')) {
|
|||
useSSRMode.value = true
|
||||
}
|
||||
|
||||
const files: StoreState['files'] = ref(Object.create(null))
|
||||
|
||||
// enable experimental features
|
||||
const sfcOptions = computed(
|
||||
(): SFCOptions => ({
|
||||
|
@ -53,11 +65,13 @@ const sfcOptions = computed(
|
|||
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) =>
|
||||
|
@ -69,8 +83,9 @@ const sfcOptions = computed(
|
|||
|
||||
const store = useStore(
|
||||
{
|
||||
builtinImportMap: importMap,
|
||||
files,
|
||||
vueVersion,
|
||||
builtinImportMap: importMap,
|
||||
sfcOptions,
|
||||
},
|
||||
hash,
|
||||
|
@ -145,8 +160,10 @@ onMounted(() => {
|
|||
:clearConsole="false"
|
||||
:preview-options="{
|
||||
customCode: {
|
||||
importCode: `import { initCustomFormatter } from 'vue'`,
|
||||
useCode: `if (window.devtoolsFormatters) {
|
||||
importCode: `import { initCustomFormatter, vaporInteropPlugin } from 'vue'`,
|
||||
useCode: `
|
||||
app.use(vaporInteropPlugin)
|
||||
if (window.devtoolsFormatters) {
|
||||
const index = window.devtoolsFormatters.findIndex((v) => v.__vue_custom_formatter)
|
||||
window.devtoolsFormatters.splice(index, 1)
|
||||
initCustomFormatter()
|
||||
|
|
|
@ -21,6 +21,7 @@ const emit = defineEmits([
|
|||
'toggle-theme',
|
||||
'toggle-ssr',
|
||||
'toggle-prod',
|
||||
'toggle-vapor',
|
||||
'toggle-autosave',
|
||||
'reload-page',
|
||||
])
|
||||
|
@ -215,6 +216,7 @@ h1 img {
|
|||
}
|
||||
|
||||
.toggle-prod span,
|
||||
.toggle-vapor span,
|
||||
.toggle-ssr span,
|
||||
.toggle-autosave span {
|
||||
font-size: 12px;
|
||||
|
@ -242,6 +244,15 @@ h1 img {
|
|||
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;
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// serve vue to the iframe sandbox during dev.
|
||||
export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
|
||||
export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.prod.js'
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
// serve vue to the iframe sandbox during dev.
|
||||
export * from 'vue'
|
||||
export * from 'vue/dist/vue.runtime-with-vapor.esm-browser.js'
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const msg = ref('Hello World!')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
</template>
|
|
@ -53,6 +53,8 @@ function copyVuePlugin(): Plugin {
|
|||
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`)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"enableNonBrowserBranches": true
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/compiler-vapor": "workspace:^",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
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,
|
||||
} from '@vue/compiler-dom'
|
||||
import { compile as ssrCompile } from '@vue/compiler-ssr'
|
||||
compile as vaporCompile,
|
||||
} from '@vue/compiler-vapor'
|
||||
// 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'
|
||||
|
@ -77,10 +80,16 @@ window.init = () => {
|
|||
console.clear()
|
||||
try {
|
||||
const errors: CompilerError[] = []
|
||||
const compileFn = ssrMode.value ? ssrCompile : compile
|
||||
const compileFn = /* ssrMode.value ? ssrCompile : */ (
|
||||
vaporMode.value ? vaporCompile : compile
|
||||
) as typeof vaporCompile
|
||||
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 => {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { createApp, h, reactive, ref } from 'vue'
|
||||
import type { CompilerOptions } from '@vue/compiler-dom'
|
||||
import type { CompilerOptions } from '@vue/compiler-vapor'
|
||||
import { BindingTypes } from '@vue/compiler-core'
|
||||
|
||||
export const ssrMode = ref(false)
|
||||
export const vaporMode = ref(true)
|
||||
|
||||
export const defaultOptions: CompilerOptions = {
|
||||
mode: 'module',
|
||||
|
@ -39,11 +40,11 @@ const App = {
|
|||
compilerOptions.prefixIdentifiers || compilerOptions.mode === 'module'
|
||||
|
||||
return [
|
||||
h('h1', `Vue 3 Template Explorer`),
|
||||
h('h1', `Vue Template Explorer`),
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
href: `https://github.com/vuejs/core/tree/${__COMMIT__}`,
|
||||
href: `https://github.com/vuejs/vue/tree/${__COMMIT__}`,
|
||||
target: `_blank`,
|
||||
},
|
||||
`@${__COMMIT__}`,
|
||||
|
@ -222,6 +223,18 @@ const App = {
|
|||
}),
|
||||
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'),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
]
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
"compilerOptions": {
|
||||
"isolatedDeclarations": false
|
||||
},
|
||||
"include": ["."]
|
||||
"include": [".", "../packages/vue/__tests__/e2e/e2eUtils.ts"]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
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,
|
||||
)
|
||||
})
|
|
@ -0,0 +1,84 @@
|
|||
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,
|
||||
)
|
||||
})
|
|
@ -0,0 +1,2 @@
|
|||
<a href="/interop/">VDOM / Vapor interop</a>
|
||||
<a href="/todomvc/">Vapor TodoMVC</a>
|
|
@ -0,0 +1,22 @@
|
|||
<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>
|
|
@ -0,0 +1,50 @@
|
|||
<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>
|
|
@ -0,0 +1,28 @@
|
|||
<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>
|
|
@ -0,0 +1,2 @@
|
|||
<script type="module" src="./main.ts"></script>
|
||||
<div id="app"></div>
|
|
@ -0,0 +1,4 @@
|
|||
import { createApp, vaporInteropPlugin } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
createApp(App).use(vaporInteropPlugin).mount('#app')
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"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:*"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
<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>
|
|
@ -0,0 +1,2 @@
|
|||
<script type="module" src="./main.ts"></script>
|
||||
<div id="app"></div>
|
|
@ -0,0 +1,5 @@
|
|||
import { createVaporApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import 'todomvc-app-css/index.css'
|
||||
|
||||
createVaporApp(App).mount('#app')
|
|
@ -0,0 +1,20 @@
|
|||
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'),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
|
@ -86,6 +86,13 @@ export interface Position {
|
|||
column: number
|
||||
}
|
||||
|
||||
export type AllNode =
|
||||
| ParentNode
|
||||
| ExpressionNode
|
||||
| TemplateChildNode
|
||||
| AttributeNode
|
||||
| DirectiveNode
|
||||
|
||||
export type ParentNode = RootNode | ElementNode | IfBranchNode | ForNode
|
||||
|
||||
export type ExpressionNode = SimpleExpressionNode | CompoundExpressionNode
|
||||
|
|
|
@ -12,6 +12,7 @@ import type {
|
|||
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
|
||||
|
@ -308,8 +309,8 @@ export const isFunctionType = (node: Node): node is Function => {
|
|||
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
|
||||
|
||||
|
@ -510,3 +511,77 @@ export function unwrapTSNode(node: Node): Node {
|
|||
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
|
||||
}
|
||||
|
|
|
@ -105,22 +105,38 @@ const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}`
|
|||
|
||||
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
|
||||
|
||||
export interface CodegenResult {
|
||||
export interface BaseCodegenResult {
|
||||
code: string
|
||||
preamble: string
|
||||
ast: RootNode
|
||||
ast: unknown
|
||||
map?: RawSourceMap
|
||||
helpers?: Set<string> | Set<symbol>
|
||||
}
|
||||
|
||||
enum NewlineType {
|
||||
export interface CodegenResult extends BaseCodegenResult {
|
||||
ast: RootNode
|
||||
helpers: Set<symbol>
|
||||
}
|
||||
|
||||
export enum NewlineType {
|
||||
/** Start with `\n` */
|
||||
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'> {
|
||||
extends Omit<
|
||||
Required<CodegenOptions>,
|
||||
| 'bindingMetadata'
|
||||
| 'inline'
|
||||
| 'vaporRuntimeModuleName'
|
||||
| 'expressionPlugins'
|
||||
> {
|
||||
source: string
|
||||
code: string
|
||||
line: number
|
||||
|
@ -398,6 +414,7 @@ export function generate(
|
|||
code: context.code,
|
||||
preamble: isSetupInlined ? preambleContext.code : ``,
|
||||
map: context.map ? context.map.toJSON() : undefined,
|
||||
helpers: ast.helpers,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,21 +17,26 @@ export {
|
|||
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'
|
||||
|
@ -52,6 +57,7 @@ export {
|
|||
transformExpression,
|
||||
processExpression,
|
||||
stringifyExpression,
|
||||
isLiteralWhitelisted,
|
||||
} from './transforms/transformExpression'
|
||||
export {
|
||||
buildSlots,
|
||||
|
@ -75,4 +81,5 @@ export {
|
|||
checkCompatEnabled,
|
||||
warnDeprecation,
|
||||
CompilerDeprecationTypes,
|
||||
type CompilerCompatOptions,
|
||||
} from './compat/compatConfig'
|
||||
|
|
|
@ -174,6 +174,12 @@ interface SharedTransformCodegenOptions {
|
|||
* @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
|
||||
|
@ -272,12 +278,6 @@ export interface TransformOptions
|
|||
* @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
|
||||
*/
|
||||
|
|
|
@ -123,6 +123,11 @@ export interface TransformContext
|
|||
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,
|
||||
{
|
||||
|
@ -150,11 +155,10 @@ export function createTransformContext(
|
|||
compatConfig,
|
||||
}: TransformOptions,
|
||||
): TransformContext {
|
||||
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
|
||||
const context: TransformContext = {
|
||||
// options
|
||||
filename,
|
||||
selfName: nameMatch && capitalize(camelize(nameMatch[1])),
|
||||
selfName: getSelfName(filename),
|
||||
prefixIdentifiers,
|
||||
hoistStatic,
|
||||
hmr,
|
||||
|
|
|
@ -44,7 +44,8 @@ import { parseExpression } from '@babel/parser'
|
|||
import { IS_REF, UNREF } from '../runtimeHelpers'
|
||||
import { BindingTypes } from '../options'
|
||||
|
||||
const isLiteralWhitelisted = /*@__PURE__*/ makeMap('true,false,null,this')
|
||||
export const isLiteralWhitelisted: (key: string) => boolean =
|
||||
/*@__PURE__*/ makeMap('true,false,null,this')
|
||||
|
||||
export const transformExpression: NodeTransform = (node, context) => {
|
||||
if (node.type === NodeTypes.INTERPOLATION) {
|
||||
|
|
|
@ -160,7 +160,7 @@ export const isMemberExpressionBrowser = (exp: ExpressionNode): boolean => {
|
|||
|
||||
export const isMemberExpressionNode: (
|
||||
exp: ExpressionNode,
|
||||
context: TransformContext,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
) => boolean = __BROWSER__
|
||||
? (NOOP as any)
|
||||
: (exp, context) => {
|
||||
|
@ -185,7 +185,7 @@ export const isMemberExpressionNode: (
|
|||
|
||||
export const isMemberExpression: (
|
||||
exp: ExpressionNode,
|
||||
context: TransformContext,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
|
||||
|
||||
const fnExpRE =
|
||||
|
@ -196,7 +196,7 @@ export const isFnExpressionBrowser: (exp: ExpressionNode) => boolean = exp =>
|
|||
|
||||
export const isFnExpressionNode: (
|
||||
exp: ExpressionNode,
|
||||
context: TransformContext,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
) => boolean = __BROWSER__
|
||||
? (NOOP as any)
|
||||
: (exp, context) => {
|
||||
|
@ -227,7 +227,7 @@ export const isFnExpressionNode: (
|
|||
|
||||
export const isFnExpression: (
|
||||
exp: ExpressionNode,
|
||||
context: TransformContext,
|
||||
context: Pick<TransformContext, 'expressionPlugins'>,
|
||||
) => boolean = __BROWSER__ ? isFnExpressionBrowser : isFnExpressionNode
|
||||
|
||||
export function advancePositionWithClone(
|
||||
|
@ -279,6 +279,7 @@ export function assert(condition: boolean, msg?: string): void {
|
|||
}
|
||||
}
|
||||
|
||||
/** find directive */
|
||||
export function findDir(
|
||||
node: ElementNode,
|
||||
name: string | RegExp,
|
||||
|
|
|
@ -48,7 +48,7 @@ if (__TEST__) {
|
|||
}
|
||||
}
|
||||
|
||||
export const DOMErrorMessages: { [code: number]: string } = {
|
||||
export const DOMErrorMessages: Record<DOMErrorCodes, 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.`,
|
||||
|
@ -60,4 +60,7 @@ export const DOMErrorMessages: { [code: number]: string } = {
|
|||
[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__]: ``,
|
||||
}
|
||||
|
|
|
@ -74,4 +74,6 @@ export {
|
|||
DOMErrorCodes,
|
||||
DOMErrorMessages,
|
||||
} from './errors'
|
||||
export { resolveModifiers } from './transforms/vOn'
|
||||
export { isValidHTMLNesting } from './htmlNesting'
|
||||
export * from '@vue/compiler-core'
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
isStaticExp,
|
||||
} from '@vue/compiler-core'
|
||||
import { V_ON_WITH_KEYS, V_ON_WITH_MODIFIERS } from '../runtimeHelpers'
|
||||
import { capitalize, makeMap } from '@vue/shared'
|
||||
import { capitalize, isString, makeMap } from '@vue/shared'
|
||||
|
||||
const isEventOptionModifier = /*@__PURE__*/ makeMap(`passive,once,capture`)
|
||||
const isNonKeyModifier = /*@__PURE__*/ makeMap(
|
||||
|
@ -30,12 +30,16 @@ const isNonKeyModifier = /*@__PURE__*/ makeMap(
|
|||
const maybeKeyModifier = /*@__PURE__*/ makeMap('left,right')
|
||||
const isKeyboardEvent = /*@__PURE__*/ makeMap(`onkeyup,onkeydown,onkeypress`)
|
||||
|
||||
const resolveModifiers = (
|
||||
key: ExpressionNode,
|
||||
export const resolveModifiers = (
|
||||
key: ExpressionNode | string,
|
||||
modifiers: SimpleExpressionNode[],
|
||||
context: TransformContext,
|
||||
context: TransformContext | null,
|
||||
loc: SourceLocation,
|
||||
) => {
|
||||
): {
|
||||
keyModifiers: string[]
|
||||
nonKeyModifiers: string[]
|
||||
eventOptionModifiers: string[]
|
||||
} => {
|
||||
const keyModifiers = []
|
||||
const nonKeyModifiers = []
|
||||
const eventOptionModifiers = []
|
||||
|
@ -46,6 +50,7 @@ const resolveModifiers = (
|
|||
if (
|
||||
__COMPAT__ &&
|
||||
modifier === 'native' &&
|
||||
context &&
|
||||
checkCompatEnabled(
|
||||
CompilerDeprecationTypes.COMPILER_V_ON_NATIVE,
|
||||
context,
|
||||
|
@ -58,12 +63,16 @@ const resolveModifiers = (
|
|||
// e.g. .passive & .capture
|
||||
eventOptionModifiers.push(modifier)
|
||||
} else {
|
||||
const keyString = isString(key)
|
||||
? key
|
||||
: isStaticExp(key)
|
||||
? key.content
|
||||
: null
|
||||
|
||||
// runtimeModifiers: modifiers that needs runtime guards
|
||||
if (maybeKeyModifier(modifier)) {
|
||||
if (isStaticExp(key)) {
|
||||
if (
|
||||
isKeyboardEvent((key as SimpleExpressionNode).content.toLowerCase())
|
||||
) {
|
||||
if (keyString) {
|
||||
if (isKeyboardEvent(keyString.toLowerCase())) {
|
||||
keyModifiers.push(modifier)
|
||||
} else {
|
||||
nonKeyModifiers.push(modifier)
|
||||
|
|
|
@ -117,6 +117,8 @@ return () => {}
|
|||
|
||||
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: {
|
||||
|
@ -129,7 +131,9 @@ export default /*@__PURE__*/_defineComponent({
|
|||
|
||||
|
||||
|
||||
return () => {}
|
||||
return (_ctx: any,_cache: any) => {
|
||||
return _toDisplayString(__props.foo)
|
||||
}
|
||||
}
|
||||
|
||||
})"
|
||||
|
|
|
@ -155,6 +155,7 @@ describe('sfc reactive props destructure', () => {
|
|||
"onUpdate:modelValue": (val: number) => void // double-quoted string containing symbols
|
||||
}>()
|
||||
</script>
|
||||
<template>{{ foo }}</template>
|
||||
`)
|
||||
expect(bindings).toStrictEqual({
|
||||
__propsAliases: {
|
||||
|
@ -173,6 +174,7 @@ describe('sfc reactive props destructure', () => {
|
|||
"foo:bar": { type: String, required: true, default: 'foo-bar' },
|
||||
"onUpdate:modelValue": { type: Function, required: true }
|
||||
},`)
|
||||
expect(content).toMatch(`__props.foo`)
|
||||
assertCode(content)
|
||||
})
|
||||
|
||||
|
|
|
@ -381,6 +381,17 @@ h1 { color: red }
|
|||
})
|
||||
})
|
||||
|
||||
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)
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
"@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:",
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
BindingTypes,
|
||||
UNREF,
|
||||
isFunctionType,
|
||||
isStaticNode,
|
||||
unwrapTSNode,
|
||||
walkIdentifiers,
|
||||
} from '@vue/compiler-dom'
|
||||
|
@ -125,6 +126,10 @@ export interface SFCScriptCompileOptions {
|
|||
* Transform Vue SFCs into custom elements.
|
||||
*/
|
||||
customElement?: boolean | ((filename: string) => boolean)
|
||||
/**
|
||||
* Force to use of Vapor mode.
|
||||
*/
|
||||
vapor?: boolean
|
||||
}
|
||||
|
||||
export interface ImportBinding {
|
||||
|
@ -169,6 +174,8 @@ export function compileScript(
|
|||
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) {
|
||||
|
@ -743,7 +750,7 @@ export function compileScript(
|
|||
if (
|
||||
sfc.cssVars.length &&
|
||||
// no need to do this when targeting SSR
|
||||
!options.templateOptions?.ssr
|
||||
!ssr
|
||||
) {
|
||||
ctx.helperImports.add(CSS_VARS_HELPER)
|
||||
ctx.helperImports.add('unref')
|
||||
|
@ -853,12 +860,12 @@ export function compileScript(
|
|||
} else {
|
||||
// inline mode
|
||||
if (sfc.template && !sfc.template.src) {
|
||||
if (options.templateOptions && options.templateOptions.ssr) {
|
||||
if (ssr) {
|
||||
hasInlinedSsrRenderFn = true
|
||||
}
|
||||
// inline render function mode - we are going to compile the template and
|
||||
// inline it right here
|
||||
const { code, ast, preamble, tips, errors } = compileTemplate({
|
||||
const { code, preamble, tips, errors, helpers } = compileTemplate({
|
||||
filename,
|
||||
ast: sfc.template.ast,
|
||||
source: sfc.template.content,
|
||||
|
@ -868,6 +875,7 @@ export function compileScript(
|
|||
scoped: sfc.styles.some(s => s.scoped),
|
||||
isProd: options.isProd,
|
||||
ssrCssVars: sfc.cssVars,
|
||||
vapor,
|
||||
compilerOptions: {
|
||||
...(options.templateOptions &&
|
||||
options.templateOptions.compilerOptions),
|
||||
|
@ -903,7 +911,7 @@ export function compileScript(
|
|||
// avoid duplicated unref import
|
||||
// as this may get injected by the render function preamble OR the
|
||||
// css vars codegen
|
||||
if (ast && ast.helpers.has(UNREF)) {
|
||||
if (helpers && helpers.has(UNREF)) {
|
||||
ctx.helperImports.delete('unref')
|
||||
}
|
||||
returned = code
|
||||
|
@ -923,7 +931,11 @@ export function compileScript(
|
|||
`\n}\n\n`,
|
||||
)
|
||||
} else {
|
||||
ctx.s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
|
||||
ctx.s.appendRight(
|
||||
endOffset,
|
||||
// vapor mode generates its own return when inlined
|
||||
`\n${vapor && !ssr ? `` : `return `}${returned}\n}\n\n`,
|
||||
)
|
||||
}
|
||||
|
||||
// 10. finalize default export
|
||||
|
@ -972,13 +984,17 @@ export function compileScript(
|
|||
ctx.s.prependLeft(
|
||||
startOffset,
|
||||
`\n${genDefaultAs} /*@__PURE__*/${ctx.helper(
|
||||
`defineComponent`,
|
||||
vapor && !ssr ? `defineVaporComponent` : `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__, { ... })
|
||||
|
@ -1247,40 +1263,3 @@ function canNeverBeRef(node: Node, userReactiveImport?: string): boolean {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
type CodegenResult,
|
||||
type BaseCodegenResult,
|
||||
type CompilerError,
|
||||
type CompilerOptions,
|
||||
type ElementNode,
|
||||
|
@ -24,24 +24,29 @@ import {
|
|||
} 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): CodegenResult
|
||||
compile(
|
||||
source: string | RootNode,
|
||||
options: CompilerOptions,
|
||||
): BaseCodegenResult
|
||||
parse(template: string, options: ParserOptions): RootNode
|
||||
}
|
||||
|
||||
export interface SFCTemplateCompileResults {
|
||||
code: string
|
||||
ast?: RootNode
|
||||
ast?: unknown
|
||||
preamble?: string
|
||||
source: string
|
||||
tips: string[]
|
||||
errors: (string | CompilerError)[]
|
||||
map?: RawSourceMap
|
||||
helpers?: Set<string | symbol>
|
||||
}
|
||||
|
||||
export interface SFCTemplateCompileOptions {
|
||||
|
@ -52,6 +57,7 @@ export interface SFCTemplateCompileOptions {
|
|||
scoped?: boolean
|
||||
slotted?: boolean
|
||||
isProd?: boolean
|
||||
vapor?: boolean
|
||||
ssr?: boolean
|
||||
ssrCssVars?: string[]
|
||||
inMap?: RawSourceMap
|
||||
|
@ -168,6 +174,7 @@ function doCompileTemplate({
|
|||
source,
|
||||
ast: inAST,
|
||||
ssr = false,
|
||||
vapor = false,
|
||||
ssrCssVars,
|
||||
isProd = false,
|
||||
compiler,
|
||||
|
@ -202,7 +209,11 @@ function doCompileTemplate({
|
|||
const shortId = id.replace(/^data-v-/, '')
|
||||
const longId = `data-v-${shortId}`
|
||||
|
||||
const defaultCompiler = ssr ? (CompilerSSR as TemplateCompiler) : CompilerDOM
|
||||
const defaultCompiler = ssr
|
||||
? (CompilerSSR as TemplateCompiler)
|
||||
: vapor
|
||||
? (CompilerVapor as TemplateCompiler)
|
||||
: CompilerDOM
|
||||
compiler = compiler || defaultCompiler
|
||||
|
||||
if (compiler !== defaultCompiler) {
|
||||
|
@ -227,25 +238,30 @@ function doCompileTemplate({
|
|||
inAST = createRoot(template.children, inAST.source)
|
||||
}
|
||||
|
||||
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),
|
||||
})
|
||||
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),
|
||||
},
|
||||
)
|
||||
|
||||
// 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
|
||||
|
@ -271,7 +287,16 @@ function doCompileTemplate({
|
|||
return msg
|
||||
})
|
||||
|
||||
return { code, ast, preamble, source, errors, tips, map }
|
||||
return {
|
||||
code,
|
||||
ast,
|
||||
preamble,
|
||||
source,
|
||||
errors,
|
||||
tips,
|
||||
map,
|
||||
helpers,
|
||||
}
|
||||
}
|
||||
|
||||
function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap {
|
||||
|
|
|
@ -84,6 +84,8 @@ export interface SFCDescriptor {
|
|||
*/
|
||||
slotted: boolean
|
||||
|
||||
vapor: boolean
|
||||
|
||||
/**
|
||||
* compare with an existing descriptor to determine whether HMR should perform
|
||||
* a reload vs. re-render.
|
||||
|
@ -137,6 +139,7 @@ export function parse(
|
|||
customBlocks: [],
|
||||
cssVars: [],
|
||||
slotted: false,
|
||||
vapor: false,
|
||||
shouldForceReload: prevImports => hmrShouldReload(prevImports, descriptor),
|
||||
}
|
||||
|
||||
|
@ -159,8 +162,9 @@ export function parse(
|
|||
ignoreEmpty &&
|
||||
node.tag !== 'template' &&
|
||||
isEmpty(node) &&
|
||||
!hasSrc(node)
|
||||
!hasAttr(node, 'src')
|
||||
) {
|
||||
descriptor.vapor ||= hasAttr(node, 'vapor')
|
||||
return
|
||||
}
|
||||
switch (node.tag) {
|
||||
|
@ -171,6 +175,7 @@ export function parse(
|
|||
source,
|
||||
false,
|
||||
) as SFCTemplateBlock)
|
||||
descriptor.vapor ||= !!templateBlock.attrs.vapor
|
||||
|
||||
if (!templateBlock.attrs.src) {
|
||||
templateBlock.ast = createRoot(node.children, source)
|
||||
|
@ -195,7 +200,8 @@ export function parse(
|
|||
break
|
||||
case 'script':
|
||||
const scriptBlock = createBlock(node, source, pad) as SFCScriptBlock
|
||||
const isSetup = !!scriptBlock.attrs.setup
|
||||
descriptor.vapor ||= !!scriptBlock.attrs.vapor
|
||||
const isSetup = !!(scriptBlock.attrs.setup || scriptBlock.attrs.vapor)
|
||||
if (isSetup && !descriptor.scriptSetup) {
|
||||
descriptor.scriptSetup = scriptBlock
|
||||
break
|
||||
|
@ -404,13 +410,8 @@ function padContent(
|
|||
}
|
||||
}
|
||||
|
||||
function hasSrc(node: ElementNode) {
|
||||
return node.props.some(p => {
|
||||
if (p.type !== NodeTypes.ATTRIBUTE) {
|
||||
return false
|
||||
}
|
||||
return p.name === 'src'
|
||||
})
|
||||
function hasAttr(node: ElementNode, name: string) {
|
||||
return node.props.some(p => p.type === NodeTypes.ATTRIBUTE && p.name === name)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,6 +79,15 @@ export function processDefineProps(
|
|||
)
|
||||
}
|
||||
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
|
||||
|
@ -190,10 +199,6 @@ export function extractRuntimeProps(
|
|||
|
||||
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 = `{
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
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.
|
|
@ -0,0 +1 @@
|
|||
# @vue/compiler-vapor
|
|
@ -0,0 +1,310 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @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')
|
||||
})
|
|
@ -0,0 +1,265 @@
|
|||
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))`,
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,3 @@
|
|||
// import { compile } from '../src/compile'
|
||||
|
||||
describe.todo('scopeId compiler support', () => {})
|
|
@ -0,0 +1,55 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,76 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,463 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,52 @@
|
|||
// 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
|
||||
}"
|
||||
`
|
|
@ -0,0 +1,163 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,85 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,23 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,658 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,159 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,34 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,162 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,242 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,472 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,104 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,12 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,341 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,35 @@
|
|||
// 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
|
||||
}"
|
||||
`;
|
|
@ -0,0 +1,37 @@
|
|||
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 }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
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++)`)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,76 @@
|
|||
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()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,959 @@
|
|||
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')
|
||||
})
|
||||
})
|
|
@ -0,0 +1,280 @@
|
|||
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,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue