mirror of https://github.com/vuejs/core.git
test: add transform test
This commit is contained in:
parent
e3b21b25b1
commit
5f769745fa
|
@ -1,6 +1,6 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`v-bind > .camel modifier 1`] = `
|
exports[`compiler: codegen v-bind > .camel modifier 1`] = `
|
||||||
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
|
@ -14,7 +14,7 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`v-bind > dynamic arg 1`] = `
|
exports[`compiler: codegen v-bind > dynamic arg 1`] = `
|
||||||
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
|
@ -28,7 +28,7 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`v-bind > no expression (shorthand) 1`] = `
|
exports[`compiler: codegen v-bind > no expression (shorthand) 1`] = `
|
||||||
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
|
@ -42,7 +42,7 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`v-bind > no expression 1`] = `
|
exports[`compiler: codegen v-bind > no expression 1`] = `
|
||||||
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
|
@ -56,7 +56,7 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`v-bind > should error if no expression 1`] = `
|
exports[`compiler: codegen v-bind > should error if no expression 1`] = `
|
||||||
"import { template as _template } from 'vue/vapor';
|
"import { template as _template } from 'vue/vapor';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
|
@ -66,7 +66,7 @@ export function render(_ctx) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`v-bind > simple expression 1`] = `
|
exports[`compiler: codegen v-bind > simple expression 1`] = `
|
||||||
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
|
|
|
@ -1,5 +1,34 @@
|
||||||
import { type RootNode, BindingTypes, ErrorCodes } from '@vue/compiler-dom'
|
import {
|
||||||
import { type CompilerOptions, compile as _compile } from '../../src'
|
type RootNode,
|
||||||
|
ErrorCodes,
|
||||||
|
NodeTypes,
|
||||||
|
BindingTypes,
|
||||||
|
} from '@vue/compiler-dom'
|
||||||
|
import {
|
||||||
|
type RootIRNode,
|
||||||
|
type CompilerOptions,
|
||||||
|
parse,
|
||||||
|
transform,
|
||||||
|
transformVBind,
|
||||||
|
transformElement,
|
||||||
|
IRNodeTypes,
|
||||||
|
compile as _compile,
|
||||||
|
} from '../../src'
|
||||||
|
|
||||||
|
function parseWithVBind(
|
||||||
|
template: string,
|
||||||
|
options: CompilerOptions = {},
|
||||||
|
): RootIRNode {
|
||||||
|
const ast = parse(template)
|
||||||
|
const ir = transform(ast, {
|
||||||
|
nodeTransforms: [transformElement],
|
||||||
|
directiveTransforms: {
|
||||||
|
bind: transformVBind,
|
||||||
|
},
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
return ir
|
||||||
|
}
|
||||||
|
|
||||||
function compile(template: string | RootNode, options: CompilerOptions = {}) {
|
function compile(template: string | RootNode, options: CompilerOptions = {}) {
|
||||||
let { code } = _compile(template, {
|
let { code } = _compile(template, {
|
||||||
|
@ -10,7 +39,189 @@ function compile(template: string | RootNode, options: CompilerOptions = {}) {
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('v-bind', () => {
|
describe('compiler: transform v-bind', () => {
|
||||||
|
test('basic', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:id="id"/>`)
|
||||||
|
|
||||||
|
expect(node.dynamic.children[0]).toMatchObject({
|
||||||
|
id: 1,
|
||||||
|
referenced: true,
|
||||||
|
})
|
||||||
|
expect(node.template[0]).toMatchObject({
|
||||||
|
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||||
|
template: '<div></div>',
|
||||||
|
})
|
||||||
|
expect(node.effect).lengthOf(1)
|
||||||
|
expect(node.effect[0].expressions).lengthOf(1)
|
||||||
|
expect(node.effect[0].operations).lengthOf(1)
|
||||||
|
expect(node.effect[0]).toMatchObject({
|
||||||
|
expressions: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'id',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
type: IRNodeTypes.SET_PROP,
|
||||||
|
element: 1,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'id',
|
||||||
|
isStatic: true,
|
||||||
|
loc: {
|
||||||
|
start: { line: 1, column: 13, offset: 12 },
|
||||||
|
end: { line: 1, column: 15, offset: 14 },
|
||||||
|
source: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'id',
|
||||||
|
isStatic: false,
|
||||||
|
loc: {
|
||||||
|
source: 'id',
|
||||||
|
start: { line: 1, column: 17, offset: 16 },
|
||||||
|
end: { line: 1, column: 19, offset: 18 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('no expression', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:id />`)
|
||||||
|
|
||||||
|
expect(node.effect[0].operations[0]).toMatchObject({
|
||||||
|
type: IRNodeTypes.SET_PROP,
|
||||||
|
key: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: true,
|
||||||
|
loc: {
|
||||||
|
start: { line: 1, column: 13, offset: 12 },
|
||||||
|
end: { line: 1, column: 15, offset: 14 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false,
|
||||||
|
loc: {
|
||||||
|
start: { line: 1, column: 13, offset: 12 },
|
||||||
|
end: { line: 1, column: 15, offset: 14 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('no expression (shorthand)', () => {
|
||||||
|
const node = parseWithVBind(`<div :id />`)
|
||||||
|
|
||||||
|
expect(node.effect[0].operations[0]).toMatchObject({
|
||||||
|
type: IRNodeTypes.SET_PROP,
|
||||||
|
key: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('dynamic arg', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
|
||||||
|
expect(node.effect[0].operations[0]).toMatchObject({
|
||||||
|
type: IRNodeTypes.SET_PROP,
|
||||||
|
element: 1,
|
||||||
|
key: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'id',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
|
content: 'id',
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should error if empty expression', () => {
|
||||||
|
const onError = vi.fn()
|
||||||
|
const node = parseWithVBind(`<div v-bind:arg="" />`, { onError })
|
||||||
|
expect(onError.mock.calls[0][0]).toMatchObject({
|
||||||
|
code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
|
||||||
|
loc: {
|
||||||
|
start: { line: 1, column: 6 },
|
||||||
|
end: { line: 1, column: 19 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(node.template[0]).toMatchObject({
|
||||||
|
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||||
|
template: '<div arg=""></div>',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test.fails('.camel modifier', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
|
||||||
|
expect(node.effect[0].operations[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: `fooBar`,
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test.fails('.camel modifier w/ no expression', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:foo-bar.camel />`)
|
||||||
|
expect(node.effect[0].operations[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: `fooBar`,
|
||||||
|
isStatic: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `fooBar`,
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test.fails('.camel modifier w/ dynamic arg', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:[foo].camel="id"/>`)
|
||||||
|
expect(node.effect[0].operations[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: `foo`,
|
||||||
|
isStatic: false,
|
||||||
|
somethingShouldBeTrue: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test.todo('.camel modifier w/ dynamic arg + prefixIdentifiers')
|
||||||
|
|
||||||
|
test.todo('.prop modifier')
|
||||||
|
test.todo('.prop modifier w/ no expression')
|
||||||
|
test.todo('.prop modifier w/ dynamic arg')
|
||||||
|
test.todo('.prop modifier w/ dynamic arg + prefixIdentifiers')
|
||||||
|
test.todo('.prop modifier (shorthand)')
|
||||||
|
test.todo('.prop modifier (shortband) w/ no expression')
|
||||||
|
test.todo('.attr modifier')
|
||||||
|
test.todo('.attr modifier w/ no expression')
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: combine with above
|
||||||
|
describe('compiler: codegen v-bind', () => {
|
||||||
test('simple expression', () => {
|
test('simple expression', () => {
|
||||||
const code = compile(`<div :id="id"></div>`, {
|
const code = compile(`<div :id="id"></div>`, {
|
||||||
bindingMetadata: {
|
bindingMetadata: {
|
||||||
|
|
|
@ -372,7 +372,7 @@ function genOperation(oper: OperationNode, context: CodegenContext) {
|
||||||
function genSetProp(oper: SetPropIRNode, context: CodegenContext) {
|
function genSetProp(oper: SetPropIRNode, context: CodegenContext) {
|
||||||
const { push, pushWithNewline, vaporHelper } = context
|
const { push, pushWithNewline, vaporHelper } = context
|
||||||
pushWithNewline(`${vaporHelper('setAttr')}(n${oper.element}, `)
|
pushWithNewline(`${vaporHelper('setAttr')}(n${oper.element}, `)
|
||||||
genExpression(oper.name, context)
|
genExpression(oper.key, context)
|
||||||
push(`, undefined, `)
|
push(`, undefined, `)
|
||||||
genExpression(oper.value, context)
|
genExpression(oper.value, context)
|
||||||
push(')')
|
push(')')
|
||||||
|
@ -437,7 +437,7 @@ function genSetEvent(oper: SetEventIRNode, context: CodegenContext) {
|
||||||
|
|
||||||
pushWithNewline(`${vaporHelper('on')}(n${oper.element}, `)
|
pushWithNewline(`${vaporHelper('on')}(n${oper.element}, `)
|
||||||
// second arg: event name
|
// second arg: event name
|
||||||
genExpression(oper.name, context)
|
genExpression(oper.key, context)
|
||||||
push(', ')
|
push(', ')
|
||||||
|
|
||||||
const { keys, nonKeys, options } = oper.modifiers
|
const { keys, nonKeys, options } = oper.modifiers
|
||||||
|
|
|
@ -4,3 +4,11 @@ export { generate } from './generate'
|
||||||
export { compile, type CompilerOptions } from './compile'
|
export { compile, type CompilerOptions } from './compile'
|
||||||
export * from './ir'
|
export * from './ir'
|
||||||
export * from './errors'
|
export * from './errors'
|
||||||
|
export { transformElement } from './transforms/transformElement'
|
||||||
|
export { transformInterpolation } from './transforms/transformInterpolation'
|
||||||
|
export { transformVBind } from './transforms/vBind'
|
||||||
|
export { transformVHtml } from './transforms/vHtml'
|
||||||
|
export { transformVOn } from './transforms/vOn'
|
||||||
|
export { transformOnce } from './transforms/vOnce'
|
||||||
|
export { transformVShow } from './transforms/vShow'
|
||||||
|
export { transformVText } from './transforms/vText'
|
||||||
|
|
|
@ -58,7 +58,7 @@ export interface FragmentFactoryIRNode extends BaseIRNode {
|
||||||
export interface SetPropIRNode extends BaseIRNode {
|
export interface SetPropIRNode extends BaseIRNode {
|
||||||
type: IRNodeTypes.SET_PROP
|
type: IRNodeTypes.SET_PROP
|
||||||
element: number
|
element: number
|
||||||
name: IRExpression
|
key: IRExpression
|
||||||
value: IRExpression
|
value: IRExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ export interface SetTextIRNode extends BaseIRNode {
|
||||||
export interface SetEventIRNode extends BaseIRNode {
|
export interface SetEventIRNode extends BaseIRNode {
|
||||||
type: IRNodeTypes.SET_EVENT
|
type: IRNodeTypes.SET_EVENT
|
||||||
element: number
|
element: number
|
||||||
name: IRExpression
|
key: IRExpression
|
||||||
value: IRExpression
|
value: IRExpression
|
||||||
modifiers: {
|
modifiers: {
|
||||||
// modifiers for addEventListener() options, e.g. .passive & .capture
|
// modifiers for addEventListener() options, e.g. .passive & .capture
|
||||||
|
|
|
@ -36,7 +36,7 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
|
||||||
type: IRNodeTypes.SET_PROP,
|
type: IRNodeTypes.SET_PROP,
|
||||||
loc: dir.loc,
|
loc: dir.loc,
|
||||||
element: context.reference(),
|
element: context.reference(),
|
||||||
name: arg,
|
key: arg,
|
||||||
value: exp,
|
value: exp,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -45,7 +45,7 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
|
||||||
type: IRNodeTypes.SET_EVENT,
|
type: IRNodeTypes.SET_EVENT,
|
||||||
loc,
|
loc,
|
||||||
element: context.reference(),
|
element: context.reference(),
|
||||||
name: createSimpleExpression(name, true, arg.loc),
|
key: createSimpleExpression(name, true, arg.loc),
|
||||||
value: exp,
|
value: exp,
|
||||||
modifiers: {
|
modifiers: {
|
||||||
keys: keyModifiers,
|
keys: keyModifiers,
|
||||||
|
|
Loading…
Reference in New Issue