// 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';
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';
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';
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';
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';
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';
export function render(_ctx) {
-import { type RootNode, BindingTypes, ErrorCodes } from '@vue/compiler-dom'
-import { type CompilerOptions, compile as _compile } from '../../src'
+import {
+ 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 = {}) {
let { code } = _compile(template, {
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', () => {
const code = compile(`<div :id="id"></div>`, {
bindingMetadata: {