diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
index 0fcf9b1e1..ed6a96272 100644
--- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
@@ -100,9 +100,9 @@ exports[`compiler: element transform > component > should wrap as function if v-
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [{
- onBar: () => $event => (_ctx.handleBar($event))
- }], true)
+ const n0 = _createComponent(_component_Foo, [
+ { onBar: () => $event => (_ctx.handleBar($event)) }
+ ], true)
return n0
}"
`;
@@ -112,10 +112,12 @@ exports[`compiler: element transform > component > static props 1`] = `
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [{
- id: () => ("foo"),
- class: () => ("bar")
- }], true)
+ const n0 = _createComponent(_component_Foo, [
+ {
+ id: () => ("foo"),
+ class: () => ("bar")
+ }
+ ], true)
return n0
}"
`;
@@ -125,7 +127,9 @@ exports[`compiler: element transform > component > v-bind="obj" 1`] = `
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [() => (_ctx.obj)], true)
+ const n0 = _createComponent(_component_Foo, [
+ () => (_ctx.obj)
+ ], true)
return n0
}"
`;
@@ -135,9 +139,10 @@ exports[`compiler: element transform > component > v-bind="obj" after static pro
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [{
- id: () => ("foo")
- }, () => (_ctx.obj)], true)
+ const n0 = _createComponent(_component_Foo, [
+ { id: () => ("foo") },
+ () => (_ctx.obj)
+ ], true)
return n0
}"
`;
@@ -147,9 +152,10 @@ exports[`compiler: element transform > component > v-bind="obj" before static pr
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [() => (_ctx.obj), {
- id: () => ("foo")
- }], true)
+ const n0 = _createComponent(_component_Foo, [
+ () => (_ctx.obj),
+ { id: () => ("foo") }
+ ], true)
return n0
}"
`;
@@ -159,11 +165,11 @@ exports[`compiler: element transform > component > v-bind="obj" between static p
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [{
- id: () => ("foo")
- }, () => (_ctx.obj), {
- class: () => ("bar")
- }], true)
+ const n0 = _createComponent(_component_Foo, [
+ { id: () => ("foo") },
+ () => (_ctx.obj),
+ { class: () => ("bar") }
+ ], true)
return n0
}"
`;
@@ -174,7 +180,36 @@ import { resolveComponent as _resolveComponent, createComponent as _createCompon
export function render(_ctx) {
const _component_Foo = _resolveComponent("Foo")
- const n0 = _createComponent(_component_Foo, [() => (_toHandlers(_ctx.obj))], true)
+ const n0 = _createComponent(_component_Foo, [
+ () => (_toHandlers(_ctx.obj))
+ ], true)
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > component with dynamic event arguments 1`] = `
+"import { toHandlerKey as _toHandlerKey } from 'vue';
+import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
+
+export function render(_ctx) {
+ const _component_Foo = _resolveComponent("Foo")
+ const n0 = _createComponent(_component_Foo, [
+ () => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar }),
+ () => ({ [_toHandlerKey(_ctx.baz)]: () => _ctx.qux })
+ ], true)
+ return n0
+}"
+`;
+
+exports[`compiler: element transform > component with dynamic prop arguments 1`] = `
+"import { resolveComponent as _resolveComponent, createComponent as _createComponent } from 'vue/vapor';
+
+export function render(_ctx) {
+ const _component_Foo = _resolveComponent("Foo")
+ const n0 = _createComponent(_component_Foo, [
+ () => ({ [_ctx.foo-_ctx.bar]: _ctx.bar }),
+ () => ({ [_ctx.baz]: _ctx.qux })
+ ], true)
return n0
}"
`;
diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap
index a8764d6e1..5f44f54cf 100644
--- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap
@@ -5,11 +5,11 @@ exports[`compiler: vModel transform > component > v-model for component should g
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [{
- modelValue: () => (_ctx.foo),
+ const n0 = _createComponent(_component_Comp, [
+ { modelValue: () => (_ctx.foo),
"onUpdate:modelValue": () => $event => (_ctx.foo = $event),
- modelModifiers: () => ({ trim: true, "bar-baz": true })
- }], true)
+ modelModifiers: () => ({ trim: true, "bar-baz": true }) }
+ ], true)
return n0
}"
`;
@@ -19,10 +19,10 @@ exports[`compiler: vModel transform > component > v-model for component should w
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [{
- modelValue: () => (_ctx.foo),
- "onUpdate:modelValue": () => $event => (_ctx.foo = $event)
- }], true)
+ const n0 = _createComponent(_component_Comp, [
+ { modelValue: () => (_ctx.foo),
+ "onUpdate:modelValue": () => $event => (_ctx.foo = $event) }
+ ], true)
return n0
}"
`;
@@ -32,14 +32,16 @@ exports[`compiler: vModel transform > component > v-model with arguments for com
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [{
- foo: () => (_ctx.foo),
- "onUpdate:foo": () => $event => (_ctx.foo = $event),
- fooModifiers: () => ({ trim: true }),
- bar: () => (_ctx.bar),
- "onUpdate:bar": () => $event => (_ctx.bar = $event),
- barModifiers: () => ({ number: true })
- }], true)
+ const n0 = _createComponent(_component_Comp, [
+ {
+ foo: () => (_ctx.foo),
+ "onUpdate:foo": () => $event => (_ctx.foo = $event),
+ fooModifiers: () => ({ trim: true }),
+ bar: () => (_ctx.bar),
+ "onUpdate:bar": () => $event => (_ctx.bar = $event),
+ barModifiers: () => ({ number: true })
+ }
+ ], true)
return n0
}"
`;
@@ -49,10 +51,10 @@ exports[`compiler: vModel transform > component > v-model with arguments for com
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [{
- bar: () => (_ctx.foo),
- "onUpdate:bar": () => $event => (_ctx.foo = $event)
- }], true)
+ const n0 = _createComponent(_component_Comp, [
+ { bar: () => (_ctx.foo),
+ "onUpdate:bar": () => $event => (_ctx.foo = $event) }
+ ], true)
return n0
}"
`;
@@ -62,14 +64,14 @@ exports[`compiler: vModel transform > component > v-model with dynamic arguments
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [{
- [_ctx.foo]: () => (_ctx.foo),
+ const n0 = _createComponent(_component_Comp, [
+ () => ({ [_ctx.foo]: _ctx.foo,
["onUpdate:" + _ctx.foo]: () => $event => (_ctx.foo = $event),
- [_ctx.foo + "Modifiers"]: () => ({ trim: true }),
- [_ctx.bar]: () => (_ctx.bar),
+ [_ctx.foo + "Modifiers"]: () => ({ trim: true }) }),
+ () => ({ [_ctx.bar]: _ctx.bar,
["onUpdate:" + _ctx.bar]: () => $event => (_ctx.bar = $event),
- [_ctx.bar + "Modifiers"]: () => ({ number: true })
- }], true)
+ [_ctx.bar + "Modifiers"]: () => ({ number: true }) })
+ ], true)
return n0
}"
`;
@@ -79,10 +81,10 @@ exports[`compiler: vModel transform > component > v-model with dynamic arguments
export function render(_ctx) {
const _component_Comp = _resolveComponent("Comp")
- const n0 = _createComponent(_component_Comp, [{
- [_ctx.arg]: () => (_ctx.foo),
- ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event)
- }], true)
+ const n0 = _createComponent(_component_Comp, [
+ () => ({ [_ctx.arg]: _ctx.foo,
+ ["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event) })
+ ], true)
return n0
}"
`;
diff --git a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts
index 2fa5245a9..4bf38ba3e 100644
--- a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts
+++ b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts
@@ -1,5 +1,6 @@
import { makeCompile } from './_utils'
import {
+ IRDynamicPropsKind,
IRNodeTypes,
transformChildren,
transformElement,
@@ -198,10 +199,12 @@ describe('compiler: element transform', () => {
)
expect(code).toMatchSnapshot()
- expect(code).contains('_createComponent(_component_Foo, [{')
- expect(code).contains(' id: () => ("foo")')
- expect(code).contains(' class: () => ("bar")')
- expect(code).contains('}], true)')
+ expect(code).contains(`[
+ {
+ id: () => ("foo"),
+ class: () => ("bar")
+ }
+ ]`)
expect(ir.block.operation).toMatchObject([
{
@@ -248,12 +251,19 @@ describe('compiler: element transform', () => {
test('v-bind="obj"', () => {
const { code, ir } = compileWithElementTransform(``)
expect(code).toMatchSnapshot()
- expect(code).contains('[() => (_ctx.obj)]')
+ expect(code).contains(`[
+ () => (_ctx.obj)
+ ]`)
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
- props: [{ value: { content: 'obj', isStatic: false } }],
+ props: [
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj', isStatic: false },
+ },
+ ],
},
])
})
@@ -263,15 +273,20 @@ describe('compiler: element transform', () => {
``,
)
expect(code).toMatchSnapshot()
- expect(code).contains('id: () => ("foo")')
- expect(code).contains('}, () => (_ctx.obj)]')
+ expect(code).contains(`[
+ { id: () => ("foo") },
+ () => (_ctx.obj)
+ ]`)
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
props: [
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- { value: { content: 'obj' } },
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
],
},
])
@@ -282,14 +297,19 @@ describe('compiler: element transform', () => {
``,
)
expect(code).toMatchSnapshot()
- expect(code).contains('[() => (_ctx.obj), {')
- expect(code).contains('id: () => ("foo")')
+ expect(code).contains(`[
+ () => (_ctx.obj),
+ { id: () => ("foo") }
+ ]`)
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
props: [
- { value: { content: 'obj' } },
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
],
},
@@ -301,16 +321,21 @@ describe('compiler: element transform', () => {
``,
)
expect(code).toMatchSnapshot()
- expect(code).contains('id: () => ("foo")')
- expect(code).contains('}, () => (_ctx.obj), {')
- expect(code).contains('class: () => ("bar")')
+ expect(code).contains(`[
+ { id: () => ("foo") },
+ () => (_ctx.obj),
+ { class: () => ("bar") }
+ ]`)
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
props: [
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- { value: { content: 'obj' } },
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
[{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
],
},
@@ -356,12 +381,20 @@ describe('compiler: element transform', () => {
test('v-on="obj"', () => {
const { code, ir } = compileWithElementTransform(``)
expect(code).toMatchSnapshot()
- expect(code).contains('[() => (_toHandlers(_ctx.obj))]')
+ expect(code).contains(`[
+ () => (_toHandlers(_ctx.obj))
+ ]`)
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Foo',
- props: [{ value: { content: 'obj' }, handler: true }],
+ props: [
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ handler: true,
+ },
+ ],
},
])
})
@@ -432,6 +465,7 @@ describe('compiler: element transform', () => {
element: 0,
props: [
{
+ kind: IRDynamicPropsKind.EXPRESSION,
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'obj',
@@ -467,6 +501,7 @@ describe('compiler: element transform', () => {
props: [
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
{
+ kind: IRDynamicPropsKind.EXPRESSION,
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'obj',
@@ -494,7 +529,10 @@ describe('compiler: element transform', () => {
type: IRNodeTypes.SET_DYNAMIC_PROPS,
element: 0,
props: [
- { value: { content: 'obj' } },
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
],
},
@@ -518,7 +556,10 @@ describe('compiler: element transform', () => {
element: 0,
props: [
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- { value: { content: 'obj' } },
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
[{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
],
},
@@ -691,6 +732,58 @@ describe('compiler: element transform', () => {
expect(code).contains('_setDynamicEvents(n0, _ctx.obj)')
})
+ test('component with dynamic prop arguments', () => {
+ const { code, ir } = compileWithElementTransform(
+ ``,
+ )
+ expect(code).toMatchSnapshot()
+ expect(ir.block.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(
+ ``,
+ )
+ expect(code).toMatchSnapshot()
+ expect(ir.block.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('invalid html nesting', () => {
const { code, ir } = compileWithElementTransform(
`
123
diff --git a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts
index 80a22c880..921145643 100644
--- a/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts
+++ b/packages/compiler-vapor/__tests__/transforms/vModel.spec.ts
@@ -259,7 +259,7 @@ describe('compiler: vModel transform', () => {
const { code, ir } = compileWithVModel('')
expect(code).toMatchSnapshot()
expect(code).contains(
- `[_ctx.arg]: () => (_ctx.foo),
+ `[_ctx.arg]: _ctx.foo,
["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event)`,
)
expect(ir.block.operation).toMatchObject([
@@ -267,14 +267,12 @@ describe('compiler: vModel transform', () => {
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Comp',
props: [
- [
- {
- key: { content: 'arg', isStatic: false },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: [],
- },
- ],
+ {
+ key: { content: 'arg', isStatic: false },
+ values: [{ content: 'foo', isStatic: false }],
+ model: true,
+ modelModifiers: [],
+ },
],
},
])
@@ -349,20 +347,18 @@ describe('compiler: vModel transform', () => {
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Comp',
props: [
- [
- {
- key: { content: 'foo', isStatic: false },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: ['trim'],
- },
- {
- key: { content: 'bar', isStatic: false },
- values: [{ content: 'bar', isStatic: false }],
- model: true,
- modelModifiers: ['number'],
- },
- ],
+ {
+ key: { content: 'foo', isStatic: false },
+ values: [{ content: 'foo', isStatic: false }],
+ model: true,
+ modelModifiers: ['trim'],
+ },
+ {
+ key: { content: 'bar', isStatic: false },
+ values: [{ content: 'bar', isStatic: false }],
+ model: true,
+ modelModifiers: ['number'],
+ },
],
},
])
diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts
index 5f3d060b8..fba45ab1e 100644
--- a/packages/compiler-vapor/src/generators/component.ts
+++ b/packages/compiler-vapor/src/generators/component.ts
@@ -1,10 +1,17 @@
import { camelize, extend, isArray } from '@vue/shared'
import type { CodegenContext } from '../generate'
-import type { CreateComponentIRNode, IRProp } from '../ir'
+import {
+ type CreateComponentIRNode,
+ IRDynamicPropsKind,
+ type IRProp,
+ type IRProps,
+ type IRPropsStatic,
+} from '../ir'
import {
type CodeFragment,
NEWLINE,
- SEGMENTS_ARRAY,
+ SEGMENTS_ARRAY_NEWLINE,
+ SEGMENTS_OBJECT,
SEGMENTS_OBJECT_NEWLINE,
genCall,
genMulti,
@@ -21,11 +28,11 @@ export function genCreateComponent(
oper: CreateComponentIRNode,
context: CodegenContext,
): CodeFragment[] {
- const { helper, vaporHelper } = context
+ const { vaporHelper } = context
const tag = genTag()
const isRoot = oper.root
- const rawProps = genRawProps()
+ const rawProps = genRawProps(oper.props, context)
return [
NEWLINE,
@@ -49,63 +56,80 @@ export function genCreateComponent(
)
}
}
+}
- function genRawProps() {
- const props = oper.props
- .map(props => {
- if (isArray(props)) {
- if (!props.length) return
- return genStaticProps(props)
- } else {
- let expr = genExpression(props.value, context)
- if (props.handler) expr = genCall(helper('toHandlers'), expr)
- return ['() => (', ...expr, ')']
+export function genRawProps(props: IRProps[], context: CodegenContext) {
+ const frag = props
+ .map(props => {
+ if (isArray(props)) {
+ if (!props.length) return
+ return genStaticProps(props, context)
+ } else {
+ let expr: CodeFragment[]
+ if (props.kind === IRDynamicPropsKind.ATTRIBUTE)
+ expr = genMulti(SEGMENTS_OBJECT, genProp(props, context))
+ else {
+ expr = genExpression(props.value, context)
+ if (props.handler) expr = genCall(context.helper('toHandlers'), expr)
}
- })
- .filter(Boolean)
- if (props.length) {
- return genMulti(SEGMENTS_ARRAY, ...props)
- }
+ return ['() => (', ...expr, ')']
+ }
+ })
+ .filter(
+ Boolean as any as (v: CodeFragment[] | undefined) => v is CodeFragment[],
+ )
+ if (frag.length) {
+ return genMulti(SEGMENTS_ARRAY_NEWLINE, ...frag)
}
+}
- function genStaticProps(props: IRProp[]) {
- return genMulti(
- SEGMENTS_OBJECT_NEWLINE,
- ...props.map(prop => {
- return [
- ...genPropKey(prop, context),
- ': ',
- ...(prop.handler
- ? genEventHandler(context, prop.values[0])
- : ['() => (', ...genExpression(prop.values[0], context), ')']),
- ...(prop.model
- ? [...genModelEvent(prop), ...genModelModifiers(prop)]
- : []),
- ]
- }),
- )
+function genStaticProps(
+ props: IRPropsStatic,
+ context: CodegenContext,
+): CodeFragment[] {
+ return genMulti(
+ props.length > 1 ? SEGMENTS_OBJECT_NEWLINE : SEGMENTS_OBJECT,
+ ...props.map(prop => genProp(prop, context, true)),
+ )
+}
- function genModelEvent(prop: IRProp): CodeFragment[] {
- const name = prop.key.isStatic
- ? [JSON.stringify(`onUpdate:${camelize(prop.key.content)}`)]
- : ['["onUpdate:" + ', ...genExpression(prop.key, context), ']']
- const handler = genModelHandler(prop.values[0], context)
+function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
+ return [
+ ...genPropKey(prop, context),
+ ': ',
+ ...(prop.handler
+ ? genEventHandler(context, prop.values[0])
+ : isStatic
+ ? ['() => (', ...genExpression(prop.values[0], context), ')']
+ : genExpression(prop.values[0], context)),
+ ...(prop.model
+ ? [...genModelEvent(prop, context), ...genModelModifiers(prop, context)]
+ : []),
+ ]
+}
- return [',', NEWLINE, ...name, ': ', ...handler]
- }
+function genModelEvent(prop: IRProp, context: CodegenContext): CodeFragment[] {
+ const name = prop.key.isStatic
+ ? [JSON.stringify(`onUpdate:${camelize(prop.key.content)}`)]
+ : ['["onUpdate:" + ', ...genExpression(prop.key, context), ']']
+ const handler = genModelHandler(prop.values[0], context)
- function genModelModifiers(prop: IRProp): CodeFragment[] {
- const { key, modelModifiers } = prop
- if (!modelModifiers || !modelModifiers.length) return []
+ return [',', NEWLINE, ...name, ': ', ...handler]
+}
- const modifiersKey = key.isStatic
- ? key.content === 'modelValue'
- ? [`modelModifiers`]
- : [`${key.content}Modifiers`]
- : ['[', ...genExpression(key, context), ' + "Modifiers"]']
+function genModelModifiers(
+ prop: IRProp,
+ context: CodegenContext,
+): CodeFragment[] {
+ const { key, modelModifiers } = prop
+ if (!modelModifiers || !modelModifiers.length) return []
- const modifiersVal = genDirectiveModifiers(modelModifiers)
- return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`]
- }
- }
+ const modifiersKey = key.isStatic
+ ? key.content === 'modelValue'
+ ? [`modelModifiers`]
+ : [`${key.content}Modifiers`]
+ : ['[', ...genExpression(key, context), ' + "Modifiers"]']
+
+ const modifiersVal = genDirectiveModifiers(modelModifiers)
+ return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`]
}
diff --git a/packages/compiler-vapor/src/generators/prop.ts b/packages/compiler-vapor/src/generators/prop.ts
index 1f31e4ceb..861397c9a 100644
--- a/packages/compiler-vapor/src/generators/prop.ts
+++ b/packages/compiler-vapor/src/generators/prop.ts
@@ -4,11 +4,12 @@ import {
isSimpleIdentifier,
} from '@vue/compiler-core'
import type { CodegenContext } from '../generate'
-import type {
- IRProp,
- SetDynamicPropsIRNode,
- SetPropIRNode,
- VaporHelper,
+import {
+ IRDynamicPropsKind,
+ type IRProp,
+ type SetDynamicPropsIRNode,
+ type SetPropIRNode,
+ type VaporHelper,
} from '../ir'
import { genExpression } from './expression'
import {
@@ -73,7 +74,9 @@ export function genDynamicProps(
props =>
Array.isArray(props)
? genLiteralObjectProps(props, context) // static and dynamic arg props
- : genExpression(props.value, context), // v-bind=""
+ : props.kind === IRDynamicPropsKind.ATTRIBUTE
+ ? genLiteralObjectProps([props], context) // dynamic arg props
+ : genExpression(props.value, context), // v-bind=""
),
),
]
diff --git a/packages/compiler-vapor/src/generators/utils.ts b/packages/compiler-vapor/src/generators/utils.ts
index c2e71630a..9a31bc6cb 100644
--- a/packages/compiler-vapor/src/generators/utils.ts
+++ b/packages/compiler-vapor/src/generators/utils.ts
@@ -57,6 +57,11 @@ export function genMulti(
}
}
export const SEGMENTS_ARRAY: Segments = ['[', ']', ', ']
+export const SEGMENTS_ARRAY_NEWLINE: Segments = [
+ ['[', INDENT_START, NEWLINE],
+ [INDENT_END, NEWLINE, ']'],
+ [', ', NEWLINE],
+]
export const SEGMENTS_OBJECT: Segments = ['{ ', ' }', ', ']
export const SEGMENTS_OBJECT_NEWLINE: Segments = [
['{', INDENT_START, NEWLINE],
diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts
index e5ba223d7..408e37557 100644
--- a/packages/compiler-vapor/src/ir.ts
+++ b/packages/compiler-vapor/src/ir.ts
@@ -83,12 +83,25 @@ export interface ForIRNode extends BaseIRNode {
export interface IRProp extends Omit {
values: SimpleExpressionNode[]
}
+
+export enum IRDynamicPropsKind {
+ EXPRESSION, // v-bind="value"
+ ATTRIBUTE, // v-bind:[foo]="value"
+}
+
+export type IRPropsStatic = IRProp[]
+export interface IRPropsDynamicExpression {
+ kind: IRDynamicPropsKind.EXPRESSION
+ value: SimpleExpressionNode
+ handler?: boolean
+}
+export interface IRPropsDynamicAttribute extends IRProp {
+ kind: IRDynamicPropsKind.ATTRIBUTE
+}
export type IRProps =
- | IRProp[]
- | {
- value: SimpleExpressionNode
- handler?: boolean
- }
+ | IRPropsStatic
+ | IRPropsDynamicAttribute
+ | IRPropsDynamicExpression
export interface SetPropIRNode extends BaseIRNode {
type: IRNodeTypes.SET_PROP
diff --git a/packages/compiler-vapor/src/transforms/transformElement.ts b/packages/compiler-vapor/src/transforms/transformElement.ts
index e0ce97b35..b7de58506 100644
--- a/packages/compiler-vapor/src/transforms/transformElement.ts
+++ b/packages/compiler-vapor/src/transforms/transformElement.ts
@@ -24,9 +24,11 @@ import type {
} from '../transform'
import {
DynamicFlag,
+ IRDynamicPropsKind,
IRNodeTypes,
type IRProp,
type IRProps,
+ type IRPropsDynamicAttribute,
type VaporDirectiveNode,
} from '../ir'
import { EMPTY_EXPRESSION } from './utils'
@@ -205,7 +207,10 @@ function buildProps(
if (prop.exp) {
dynamicExpr.push(prop.exp)
pushMergeArg()
- dynamicArgs.push({ value: prop.exp })
+ dynamicArgs.push({
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: prop.exp,
+ })
} else {
context.options.onError(
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, prop.loc),
@@ -218,7 +223,11 @@ function buildProps(
if (isComponent) {
dynamicExpr.push(prop.exp)
pushMergeArg()
- dynamicArgs.push({ value: prop.exp, handler: true })
+ dynamicArgs.push({
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: prop.exp,
+ handler: true,
+ })
} else {
context.registerEffect(
[prop.exp],
@@ -241,8 +250,19 @@ function buildProps(
const result = transformProp(prop, node, context)
if (result) {
- results.push(result)
dynamicExpr.push(result.key, result.value)
+ if (isComponent && !result.key.isStatic) {
+ // v-bind:[name]="value" or v-on:[name]="value"
+ pushMergeArg()
+ dynamicArgs.push(
+ extend(resolveDirectiveResult(result), {
+ kind: IRDynamicPropsKind.ATTRIBUTE,
+ }) as IRPropsDynamicAttribute,
+ )
+ } else {
+ // other static props
+ results.push(result)
+ }
}
}
@@ -297,7 +317,7 @@ function dedupeProperties(results: DirectiveTransformResult[]): IRProp[] {
const deduped: IRProp[] = []
for (const result of results) {
- const prop = normalizeIRProp(result)
+ const prop = resolveDirectiveResult(result)
// dynamic keys are always allowed
if (!prop.key.isStatic) {
deduped.push(prop)
@@ -307,7 +327,7 @@ function dedupeProperties(results: DirectiveTransformResult[]): IRProp[] {
const existing = knownProps.get(name)
if (existing) {
if (name === 'style' || name === 'class') {
- mergeAsArray(existing, prop)
+ mergePropValues(existing, prop)
}
// unexpected duplicate, should have emitted error during parse
} else {
@@ -318,11 +338,14 @@ function dedupeProperties(results: DirectiveTransformResult[]): IRProp[] {
return deduped
}
-function normalizeIRProp(prop: DirectiveTransformResult): IRProp {
- return extend({}, prop, { value: undefined, values: [prop.value] })
+function resolveDirectiveResult(prop: DirectiveTransformResult): IRProp {
+ return extend({}, prop, {
+ value: undefined,
+ values: [prop.value],
+ })
}
-function mergeAsArray(existing: IRProp, incoming: IRProp) {
+function mergePropValues(existing: IRProp, incoming: IRProp) {
const newValues = incoming.values
existing.values.push(...newValues)
}