From e7531d18df3527b647a9f9d3e1ea5017dcb6c483 Mon Sep 17 00:00:00 2001
From: Rizumu Ayaka
Date: Mon, 29 Apr 2024 23:14:03 +0800
Subject: [PATCH] feat(compiler-vapor): component with dynamic arguments
---
.../transformElement.spec.ts.snap | 29 ++++
.../__snapshots__/vModel.spec.ts.snap | 17 +--
.../transforms/transformElement.spec.ts | 48 +++++++
.../__tests__/transforms/vModel.spec.ts | 42 +++---
.../src/generators/component.ts | 126 ++++++++++--------
.../compiler-vapor/src/generators/prop.ts | 4 +-
packages/compiler-vapor/src/ir.ts | 11 +-
.../src/transforms/transformElement.ts | 9 +-
8 files changed, 194 insertions(+), 92 deletions(-)
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..cdd5790b5 100644
--- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
@@ -179,6 +179,35 @@ export function render(_ctx) {
}"
`;
+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
+}"
+`;
+
exports[`compiler: element transform > invalid html nesting 1`] = `
"import { insert as _insert, template as _template } from 'vue/vapor';
const t0 = _template("123
")
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..911ed1486 100644
--- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap
@@ -62,14 +62,15 @@ 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)
+ })], true)
return n0
}"
`;
@@ -79,10 +80,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),
+ const n0 = _createComponent(_component_Comp, [() => ({
+ [_ctx.arg]: _ctx.foo,
["onUpdate:" + _ctx.arg]: () => $event => (_ctx.foo = $event)
- }], true)
+ })], 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..fcadd9447 100644
--- a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts
+++ b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts
@@ -691,6 +691,54 @@ 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: [
+ {
+ key: { content: 'foo-bar' },
+ values: [{ content: 'bar' }],
+ },
+ {
+ 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: [
+ {
+ key: { content: 'foo-bar' },
+ values: [{ content: 'bar' }],
+ handler: true,
+ },
+ {
+ 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..63e7137da 100644
--- a/packages/compiler-vapor/src/generators/component.ts
+++ b/packages/compiler-vapor/src/generators/component.ts
@@ -1,6 +1,6 @@
import { camelize, extend, isArray } from '@vue/shared'
import type { CodegenContext } from '../generate'
-import type { CreateComponentIRNode, IRProp } from '../ir'
+import type { CreateComponentIRNode, IRProp, IRProps } from '../ir'
import {
type CodeFragment,
NEWLINE,
@@ -21,11 +21,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 +49,83 @@ 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 ('key' in props)
+ expr = genMulti(
+ SEGMENTS_OBJECT_NEWLINE,
+ genProp(props, context, false),
+ )
+ 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, ...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: IRProp[],
+ context: CodegenContext,
+): CodeFragment[] {
+ return genMulti(
+ SEGMENTS_OBJECT_NEWLINE,
+ ...props.map(prop => genProp(prop, context, true)),
+ )
+}
+
+function genProp(prop: IRProp, context: CodegenContext, isStaticArg: boolean) {
+ return [
+ ...genPropKey(prop, context),
+ ': ',
+ ...(prop.handler
+ ? genEventHandler(context, prop.values[0])
+ : isStaticArg
+ ? ['() => (', ...genExpression(prop.values[0], context), ')']
+ : genExpression(prop.values[0], context)),
+ ...(prop.model
+ ? [...genModelEvent(prop, context), ...genModelModifiers(prop, context)]
+ : []),
+ ]
+}
- 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 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)
- return [',', NEWLINE, ...name, ': ', ...handler]
- }
+ return [',', NEWLINE, ...name, ': ', ...handler]
+}
- function genModelModifiers(prop: IRProp): CodeFragment[] {
- const { key, modelModifiers } = prop
- if (!modelModifiers || !modelModifiers.length) return []
+function genModelModifiers(
+ prop: IRProp,
+ context: CodegenContext,
+): CodeFragment[] {
+ const { key, modelModifiers } = prop
+ if (!modelModifiers || !modelModifiers.length) return []
- const modifiersKey = key.isStatic
- ? key.content === 'modelValue'
- ? [`modelModifiers`]
- : [`${key.content}Modifiers`]
- : ['[', ...genExpression(key, context), ' + "Modifiers"]']
+ const modifiersKey = key.isStatic
+ ? key.content === 'modelValue'
+ ? [`modelModifiers`]
+ : [`${key.content}Modifiers`]
+ : ['[', ...genExpression(key, context), ' + "Modifiers"]']
- const modifiersVal = genDirectiveModifiers(modelModifiers)
- return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`]
- }
- }
+ 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..c91510f23 100644
--- a/packages/compiler-vapor/src/generators/prop.ts
+++ b/packages/compiler-vapor/src/generators/prop.ts
@@ -73,7 +73,9 @@ export function genDynamicProps(
props =>
Array.isArray(props)
? genLiteralObjectProps(props, context) // static and dynamic arg props
- : genExpression(props.value, context), // v-bind=""
+ : 'key' in props
+ ? genLiteralObjectProps([props], context) // dynamic arg props
+ : genExpression(props.value, context), // v-bind=""
),
),
]
diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts
index e5ba223d7..457b646b0 100644
--- a/packages/compiler-vapor/src/ir.ts
+++ b/packages/compiler-vapor/src/ir.ts
@@ -83,12 +83,11 @@ export interface ForIRNode extends BaseIRNode {
export interface IRProp extends Omit {
values: SimpleExpressionNode[]
}
-export type IRProps =
- | IRProp[]
- | {
- value: SimpleExpressionNode
- handler?: boolean
- }
+export interface IRDynamicProps {
+ value: SimpleExpressionNode
+ handler?: boolean
+}
+export type IRProps = IRProp[] | IRProp | IRDynamicProps
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..a741b6b14 100644
--- a/packages/compiler-vapor/src/transforms/transformElement.ts
+++ b/packages/compiler-vapor/src/transforms/transformElement.ts
@@ -241,8 +241,15 @@ 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(normalizeIRProp(result))
+ } else {
+ // other static props
+ results.push(result)
+ }
}
}