mirror of https://github.com/vuejs/core.git
feat(compiler-vapor): component with dynamic arguments (#192)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
parent
6f7d219654
commit
8dea04bd7f
|
@ -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
|
||||
}"
|
||||
`;
|
||||
|
|
|
@ -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
|
||||
}"
|
||||
`;
|
||||
|
|
|
@ -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(`<Foo v-bind="obj" />`)
|
||||
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', () => {
|
|||
`<Foo id="foo" v-bind="obj" />`,
|
||||
)
|
||||
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', () => {
|
|||
`<Foo v-bind="obj" id="foo" />`,
|
||||
)
|
||||
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', () => {
|
|||
`<Foo id="foo" v-bind="obj" class="bar" />`,
|
||||
)
|
||||
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(`<Foo v-on="obj" />`)
|
||||
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(
|
||||
`<Foo :[foo-bar]="bar" :[baz]="qux" />`,
|
||||
)
|
||||
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(
|
||||
`<Foo @[foo-bar]="bar" @[baz]="qux" />`,
|
||||
)
|
||||
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(
|
||||
`<p><div>123</div></p>
|
||||
|
|
|
@ -259,7 +259,7 @@ describe('compiler: vModel transform', () => {
|
|||
const { code, ir } = compileWithVModel('<Comp v-model:[arg]="foo" />')
|
||||
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'],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
: []),
|
||||
]
|
||||
}),
|
||||
return ['() => (', ...expr, ')']
|
||||
}
|
||||
})
|
||||
.filter(
|
||||
Boolean as any as (v: CodeFragment[] | undefined) => v is CodeFragment[],
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
return [',', NEWLINE, ...name, ': ', ...handler]
|
||||
}
|
||||
|
||||
function genModelModifiers(prop: IRProp): 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 modifiersVal = genDirectiveModifiers(modelModifiers)
|
||||
return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`]
|
||||
}
|
||||
if (frag.length) {
|
||||
return genMulti(SEGMENTS_ARRAY_NEWLINE, ...frag)
|
||||
}
|
||||
}
|
||||
|
||||
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 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)]
|
||||
: []),
|
||||
]
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
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 modifiersVal = genDirectiveModifiers(modelModifiers)
|
||||
return [',', NEWLINE, ...modifiersKey, `: () => ({ ${modifiersVal} })`]
|
||||
}
|
||||
|
|
|
@ -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=""
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -83,12 +83,25 @@ export interface ForIRNode extends BaseIRNode {
|
|||
export interface IRProp extends Omit<DirectiveTransformResult, 'value'> {
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue