mirror of https://github.com/vuejs/core.git
test: add all tests for `v-on` (#52)
This commit is contained in:
parent
2e25c22ddf
commit
42b913283b
|
@ -1,5 +1,31 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`v-on > case conversion for kebab-case events 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "fooBar", (...args) => (_ctx.onMount && _ctx.onMount(...args)))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > dynamic arg 1`] = `
|
||||||
|
"import { template as _template, children as _children, effect as _effect, on as _on } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_effect(() => {
|
||||||
|
_on(n1, _ctx.event, (...args) => (_ctx.handler && _ctx.handler(...args)))
|
||||||
|
})
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`v-on > event modifier 1`] = `
|
exports[`v-on > event modifier 1`] = `
|
||||||
"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers, withKeys as _withKeys } from 'vue/vapor';
|
"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers, withKeys as _withKeys } from 'vue/vapor';
|
||||||
|
|
||||||
|
@ -33,6 +59,131 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should not wrap keys guard if no key modifier is present 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "keyup", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["exact"]))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should support multiple events and modifiers options w/ prefixIdentifiers: true 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers, withKeys as _withKeys } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "click", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop"]))
|
||||||
|
_on(n1, "keyup", _withKeys((...args) => (_ctx.test && _ctx.test(...args)), ["enter"]))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should support multiple modifiers and event options w/ prefixIdentifiers: true 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "click", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop", "prevent"]), { capture: true, once: true })
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should transform click.middle 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "mouseup", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["middle"]))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should transform click.middle 2`] = `
|
||||||
|
"import { template as _template, children as _children, effect as _effect, on as _on, withModifiers as _withModifiers } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_effect(() => {
|
||||||
|
_on(n1, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["middle"]))
|
||||||
|
})
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should transform click.right 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "contextmenu", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["right"]))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should transform click.right 2`] = `
|
||||||
|
"import { template as _template, children as _children, effect as _effect, on as _on, withKeys as _withKeys, withModifiers as _withModifiers } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_effect(() => {
|
||||||
|
_on(n1, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), _withKeys(_withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["right"]), ["right"]))
|
||||||
|
})
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should wrap as function if expression is inline statement 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "click", (...args) => (_ctx.i++ && _ctx.i++(...args)))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should wrap keys guard for keyboard events or dynamic events 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on, withKeys as _withKeys, withModifiers as _withModifiers } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "keydown", _withKeys(_withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop", "ctrl"]), ["a"]), { capture: true })
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`v-on > should wrap keys guard for static key event w/ left/right modifiers 1`] = `
|
||||||
|
"import { template as _template, children as _children, on as _on, withKeys as _withKeys } from 'vue/vapor';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const t0 = _template("<div></div>")
|
||||||
|
const n0 = t0()
|
||||||
|
const { 0: [n1],} = _children(n0)
|
||||||
|
_on(n1, "keyup", _withKeys((...args) => (_ctx.test && _ctx.test(...args)), ["left"]))
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`v-on > simple expression 1`] = `
|
exports[`v-on > simple expression 1`] = `
|
||||||
"import { template as _template, children as _children, on as _on } from 'vue/vapor';
|
"import { template as _template, children as _children, on as _on } from 'vue/vapor';
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,9 @@ describe('v-html', () => {
|
||||||
expect(ir.vaporHelpers).contains('setHtml')
|
expect(ir.vaporHelpers).contains('setHtml')
|
||||||
expect(ir.helpers.size).toBe(0)
|
expect(ir.helpers.size).toBe(0)
|
||||||
|
|
||||||
|
// children should have been removed
|
||||||
|
expect(ir.template).toMatchObject([{ template: '<div></div>' }])
|
||||||
|
|
||||||
expect(ir.operation).toEqual([])
|
expect(ir.operation).toEqual([])
|
||||||
expect(ir.effect).toMatchObject([
|
expect(ir.effect).toMatchObject([
|
||||||
{
|
{
|
||||||
|
@ -109,6 +112,8 @@ describe('v-html', () => {
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(code).matchSnapshot()
|
expect(code).matchSnapshot()
|
||||||
|
// children should have been removed
|
||||||
|
expect(code).contains('template("<div></div>")')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should raise error if has no expression', () => {
|
test('should raise error if has no expression', () => {
|
||||||
|
|
|
@ -1,45 +1,72 @@
|
||||||
import { type RootNode, BindingTypes, ErrorCodes } from '@vue/compiler-dom'
|
import { BindingTypes, ErrorCodes, parse, NodeTypes } from '@vue/compiler-dom'
|
||||||
import { type CompilerOptions, compile as _compile } from '../../src'
|
import {
|
||||||
|
type CompilerOptions,
|
||||||
|
compile as _compile,
|
||||||
|
RootIRNode,
|
||||||
|
transform,
|
||||||
|
generate,
|
||||||
|
IRNodeTypes,
|
||||||
|
} from '../../src'
|
||||||
|
|
||||||
function compile(template: string | RootNode, options: CompilerOptions = {}) {
|
import { transformVOn } from '../../src/transforms/vOn'
|
||||||
let { code } = _compile(template, {
|
import { transformElement } from '../../src/transforms/transformElement'
|
||||||
...options,
|
|
||||||
mode: 'module',
|
function compileWithVOn(
|
||||||
|
template: string,
|
||||||
|
options: CompilerOptions = {},
|
||||||
|
): {
|
||||||
|
ir: RootIRNode
|
||||||
|
code: string
|
||||||
|
} {
|
||||||
|
const ast = parse(template, { prefixIdentifiers: true, ...options })
|
||||||
|
const ir = transform(ast, {
|
||||||
|
nodeTransforms: [transformElement],
|
||||||
|
directiveTransforms: {
|
||||||
|
on: transformVOn,
|
||||||
|
},
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
|
...options,
|
||||||
})
|
})
|
||||||
return code
|
const { code } = generate(ir, { prefixIdentifiers: true, ...options })
|
||||||
|
return { ir, code }
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('v-on', () => {
|
describe('v-on', () => {
|
||||||
test('simple expression', () => {
|
test('simple expression', () => {
|
||||||
const code = compile(`<div @click="handleClick"></div>`, {
|
const { code, ir } = compileWithVOn(`<div @click="handleClick"></div>`, {
|
||||||
bindingMetadata: {
|
bindingMetadata: {
|
||||||
handleClick: BindingTypes.SETUP_CONST,
|
handleClick: BindingTypes.SETUP_CONST,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
expect(ir.vaporHelpers).contains('on')
|
||||||
|
expect(ir.helpers.size).toBe(0)
|
||||||
|
expect(ir.effect).toEqual([])
|
||||||
|
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
element: 1,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'click',
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'handleClick',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
modifiers: { keys: [], nonKeys: [], options: [] },
|
||||||
|
keyOverride: undefined,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
expect(code).matchSnapshot()
|
expect(code).matchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should error if no expression AND no modifier', () => {
|
|
||||||
const onError = vi.fn()
|
|
||||||
compile(`<div v-on:click />`, { onError })
|
|
||||||
expect(onError.mock.calls[0][0]).toMatchObject({
|
|
||||||
code: ErrorCodes.X_V_ON_NO_EXPRESSION,
|
|
||||||
loc: {
|
|
||||||
start: {
|
|
||||||
line: 1,
|
|
||||||
column: 6,
|
|
||||||
},
|
|
||||||
end: {
|
|
||||||
line: 1,
|
|
||||||
column: 16,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('event modifier', () => {
|
test('event modifier', () => {
|
||||||
const code = compile(
|
const { code } = compileWithVOn(
|
||||||
`<a @click.stop="handleEvent"></a>
|
`<a @click.stop="handleEvent"></a>
|
||||||
<form @submit.prevent="handleEvent"></form>
|
<form @submit.prevent="handleEvent"></form>
|
||||||
<a @click.stop.prevent="handleEvent"></a>
|
<a @click.stop.prevent="handleEvent"></a>
|
||||||
|
@ -70,4 +97,364 @@ describe('v-on', () => {
|
||||||
)
|
)
|
||||||
expect(code).matchSnapshot()
|
expect(code).matchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('dynamic arg', () => {
|
||||||
|
const { code, ir } = compileWithVOn(`<div v-on:[event]="handler"/>`)
|
||||||
|
|
||||||
|
expect(ir.vaporHelpers).contains('on')
|
||||||
|
expect(ir.vaporHelpers).contains('effect')
|
||||||
|
expect(ir.helpers.size).toBe(0)
|
||||||
|
expect(ir.operation).toEqual([])
|
||||||
|
|
||||||
|
expect(ir.effect[0].operations[0]).toMatchObject({
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
element: 1,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'event',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'handler',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test.todo('dynamic arg with prefixing')
|
||||||
|
test.todo('dynamic arg with complex exp prefixing')
|
||||||
|
test.todo('should wrap as function if expression is inline statement')
|
||||||
|
test.todo('should handle multiple inline statement')
|
||||||
|
test.todo('should handle multi-line statement')
|
||||||
|
test.todo('inline statement w/ prefixIdentifiers: true')
|
||||||
|
test.todo('multiple inline statements w/ prefixIdentifiers: true')
|
||||||
|
test.todo(
|
||||||
|
'should NOT wrap as function if expression is already function expression',
|
||||||
|
)
|
||||||
|
test.todo(
|
||||||
|
'should NOT wrap as function if expression is already function expression (with Typescript)',
|
||||||
|
)
|
||||||
|
test.todo(
|
||||||
|
'should NOT wrap as function if expression is already function expression (with newlines)',
|
||||||
|
)
|
||||||
|
test.todo(
|
||||||
|
'should NOT wrap as function if expression is already function expression (with newlines + function keyword)',
|
||||||
|
)
|
||||||
|
test.todo(
|
||||||
|
'should NOT wrap as function if expression is complex member expression',
|
||||||
|
)
|
||||||
|
test.todo('complex member expression w/ prefixIdentifiers: true')
|
||||||
|
test.todo('function expression w/ prefixIdentifiers: true')
|
||||||
|
|
||||||
|
test('should error if no expression AND no modifier', () => {
|
||||||
|
const onError = vi.fn()
|
||||||
|
compileWithVOn(`<div v-on:click />`, { onError })
|
||||||
|
expect(onError.mock.calls[0][0]).toMatchObject({
|
||||||
|
code: ErrorCodes.X_V_ON_NO_EXPRESSION,
|
||||||
|
loc: {
|
||||||
|
start: {
|
||||||
|
line: 1,
|
||||||
|
column: 6,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: 1,
|
||||||
|
column: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should NOT error if no expression but has modifier', () => {
|
||||||
|
const onError = vi.fn()
|
||||||
|
compileWithVOn(`<div v-on:click.prevent />`, { onError })
|
||||||
|
expect(onError).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('case conversion for kebab-case events', () => {
|
||||||
|
const { ir, code } = compileWithVOn(`<div v-on:foo-bar="onMount"/>`)
|
||||||
|
|
||||||
|
expect(ir.vaporHelpers).contains('on')
|
||||||
|
expect(ir.helpers.size).toBe(0)
|
||||||
|
expect(ir.effect).toEqual([])
|
||||||
|
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
element: 1,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'fooBar',
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'onMount',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
expect(code).contains('fooBar')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('error for vnode hooks', () => {
|
||||||
|
const onError = vi.fn()
|
||||||
|
compileWithVOn(`<div v-on:vnode-mounted="onMount"/>`, { onError })
|
||||||
|
expect(onError.mock.calls[0][0]).toMatchObject({
|
||||||
|
code: ErrorCodes.X_VNODE_HOOKS,
|
||||||
|
loc: {
|
||||||
|
start: {
|
||||||
|
line: 1,
|
||||||
|
column: 11,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: 1,
|
||||||
|
column: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test.todo('vue: prefixed events')
|
||||||
|
|
||||||
|
test('should support multiple modifiers and event options w/ prefixIdentifiers: true', () => {
|
||||||
|
const { code, ir } = compileWithVOn(
|
||||||
|
`<div @click.stop.prevent.capture.once="test"/>`,
|
||||||
|
{
|
||||||
|
prefixIdentifiers: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(ir.vaporHelpers).contains('on')
|
||||||
|
expect(ir.vaporHelpers).contains('withModifiers')
|
||||||
|
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'test',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
modifiers: {
|
||||||
|
keys: [],
|
||||||
|
nonKeys: ['stop', 'prevent'],
|
||||||
|
options: ['capture', 'once'],
|
||||||
|
},
|
||||||
|
keyOverride: undefined,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
expect(code).contains('_withModifiers')
|
||||||
|
expect(code).contains('["stop", "prevent"]')
|
||||||
|
expect(code).contains('{ capture: true, once: true }')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should support multiple events and modifiers options w/ prefixIdentifiers: true', () => {
|
||||||
|
const { code, ir } = compileWithVOn(
|
||||||
|
`<div @click.stop="test" @keyup.enter="test" />`,
|
||||||
|
{
|
||||||
|
prefixIdentifiers: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'click',
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'test',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
modifiers: {
|
||||||
|
keys: [],
|
||||||
|
nonKeys: ['stop'],
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'keyup',
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'test',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
modifiers: {
|
||||||
|
keys: ['enter'],
|
||||||
|
nonKeys: [],
|
||||||
|
options: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
expect(code).contains(
|
||||||
|
'_on(n1, "click", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop"]))',
|
||||||
|
)
|
||||||
|
expect(code).contains(
|
||||||
|
'_on(n1, "keyup", _withKeys((...args) => (_ctx.test && _ctx.test(...args)), ["enter"]))',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should wrap keys guard for keyboard events or dynamic events', () => {
|
||||||
|
const { code, ir } = compileWithVOn(
|
||||||
|
`<div @keydown.stop.capture.ctrl.a="test"/>`,
|
||||||
|
{
|
||||||
|
prefixIdentifiers: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
element: 1,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'keydown',
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'test',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
modifiers: {
|
||||||
|
keys: ['a'],
|
||||||
|
nonKeys: ['stop', 'ctrl'],
|
||||||
|
options: ['capture'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should not wrap keys guard if no key modifier is present', () => {
|
||||||
|
const { code, ir } = compileWithVOn(`<div @keyup.exact="test"/>`, {
|
||||||
|
prefixIdentifiers: true,
|
||||||
|
})
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
modifiers: { nonKeys: ['exact'] },
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should wrap keys guard for static key event w/ left/right modifiers', () => {
|
||||||
|
const { code, ir } = compileWithVOn(`<div @keyup.left="test"/>`, {
|
||||||
|
prefixIdentifiers: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
modifiers: { keys: ['left'] },
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test.todo('should wrap both for dynamic key event w/ left/right modifiers')
|
||||||
|
|
||||||
|
test('should transform click.right', () => {
|
||||||
|
const { code, ir } = compileWithVOn(`<div @click.right="test"/>`)
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'contextmenu',
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
modifiers: { nonKeys: ['right'] },
|
||||||
|
keyOverride: undefined,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
expect(code).contains('"contextmenu"')
|
||||||
|
|
||||||
|
// dynamic
|
||||||
|
const { code: code2, ir: ir2 } = compileWithVOn(
|
||||||
|
`<div @[event].right="test"/>`,
|
||||||
|
)
|
||||||
|
expect(ir2.effect[0].operations).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'event',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
modifiers: { nonKeys: ['right'] },
|
||||||
|
keyOverride: ['click', 'contextmenu'],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code2).matchSnapshot()
|
||||||
|
expect(code2).contains(
|
||||||
|
'(_ctx.event) === "click" ? "contextmenu" : (_ctx.event)',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should transform click.middle', () => {
|
||||||
|
const { code, ir } = compileWithVOn(`<div @click.middle="test"/>`)
|
||||||
|
expect(ir.operation).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'mouseup',
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
modifiers: { nonKeys: ['middle'] },
|
||||||
|
keyOverride: undefined,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code).matchSnapshot()
|
||||||
|
expect(code).contains('"mouseup"')
|
||||||
|
|
||||||
|
// dynamic
|
||||||
|
const { code: code2, ir: ir2 } = compileWithVOn(
|
||||||
|
`<div @[event].middle="test"/>`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(ir2.effect[0].operations).toMatchObject([
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_EVENT,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'event',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
modifiers: { nonKeys: ['middle'] },
|
||||||
|
keyOverride: ['click', 'mouseup'],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(code2).matchSnapshot()
|
||||||
|
expect(code2).contains(
|
||||||
|
'(_ctx.event) === "click" ? "mouseup" : (_ctx.event)',
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
import { createCompilerError, ErrorCodes } from '@vue/compiler-core'
|
import {
|
||||||
|
createCompilerError,
|
||||||
|
ElementTypes,
|
||||||
|
ErrorCodes,
|
||||||
|
} from '@vue/compiler-core'
|
||||||
import type { DirectiveTransform } from '../transform'
|
import type { DirectiveTransform } from '../transform'
|
||||||
import { IRNodeTypes, KeyOverride } from '../ir'
|
import { IRNodeTypes, KeyOverride, SetEventIRNode } from '../ir'
|
||||||
import { resolveModifiers } from '@vue/compiler-dom'
|
import { resolveModifiers } from '@vue/compiler-dom'
|
||||||
|
import { camelize } from '@vue/shared'
|
||||||
|
|
||||||
export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
let { arg, exp, loc, modifiers } = dir
|
let { arg, exp, loc, modifiers } = dir
|
||||||
|
@ -16,6 +21,23 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg.isStatic) {
|
||||||
|
let rawName = arg.content
|
||||||
|
if (__DEV__ && rawName.startsWith('vnode')) {
|
||||||
|
context.options.onError(
|
||||||
|
createCompilerError(ErrorCodes.X_VNODE_HOOKS, arg.loc),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
node.tagType !== ElementTypes.ELEMENT ||
|
||||||
|
rawName.startsWith('vnode') ||
|
||||||
|
!/[A-Z]/.test(rawName)
|
||||||
|
) {
|
||||||
|
arg.content = camelize(arg.content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { keyModifiers, nonKeyModifiers, eventOptionModifiers } =
|
const { keyModifiers, nonKeyModifiers, eventOptionModifiers } =
|
||||||
resolveModifiers(
|
resolveModifiers(
|
||||||
arg.isStatic ? `on${arg.content}` : arg,
|
arg.isStatic ? `on${arg.content}` : arg,
|
||||||
|
@ -48,7 +70,7 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.registerOperation({
|
const operation: SetEventIRNode = {
|
||||||
type: IRNodeTypes.SET_EVENT,
|
type: IRNodeTypes.SET_EVENT,
|
||||||
loc,
|
loc,
|
||||||
element: context.reference(),
|
element: context.reference(),
|
||||||
|
@ -60,5 +82,11 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
options: eventOptionModifiers,
|
options: eventOptionModifiers,
|
||||||
},
|
},
|
||||||
keyOverride,
|
keyOverride,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if (arg.isStatic) {
|
||||||
|
context.registerOperation(operation)
|
||||||
|
} else {
|
||||||
|
context.registerEffect([arg], [operation])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue