fix(vapor): destructure in `v-for`

This commit is contained in:
三咲智子 Kevin Deng 2024-11-16 06:33:38 +08:00
parent 0c7817ceed
commit 81b3d36304
No known key found for this signature in database
5 changed files with 48 additions and 18 deletions

View File

@ -7,7 +7,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) { export function render(_ctx) {
const n0 = _createFor(() => (_ctx.list), _withDestructure(([[id, ...other], index]) => [id, other, index], (_ctx0) => { const n0 = _createFor(() => (_ctx.list), _withDestructure(([[id, ...other], index]) => [id, other, index], (_ctx0) => {
const n2 = t0() const n2 = t0()
_renderEffect(() => _setText(n2, _ctx0[0].value + _ctx0[1].value + _ctx0[2].value)) _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2]))
return n2 return n2
}), ([id, ...other], index) => (id)) }), ([id, ...other], index) => (id))
return n0 return n0
@ -87,7 +87,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) { export function render(_ctx) {
const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ id, ...other }, index]) => [id, other, index], (_ctx0) => { const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ id, ...other }, index]) => [id, other, index], (_ctx0) => {
const n2 = t0() const n2 = t0()
_renderEffect(() => _setText(n2, _ctx0[0].value + _ctx0[1].value + _ctx0[2].value)) _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2]))
return n2 return n2
}), ({ id, ...other }, index) => (id)) }), ({ id, ...other }, index) => (id))
return n0 return n0
@ -101,7 +101,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) { export function render(_ctx) {
const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ foo = bar, baz: [qux = quux] }]) => [foo, qux], (_ctx0) => { const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ foo = bar, baz: [qux = quux] }]) => [foo, qux], (_ctx0) => {
const n2 = t0() const n2 = t0()
_renderEffect(() => _setText(n2, _ctx0[0].value + _ctx.bar + _ctx.baz + _ctx0[1].value + _ctx.quux)) _renderEffect(() => _setText(n2, _ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux))
return n2 return n2
})) }))
return n0 return n0

View File

@ -130,7 +130,7 @@ describe('compiler: v-for', () => {
) )
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains(`([{ id, ...other }, index]) => [id, other, index]`) expect(code).contains(`([{ id, ...other }, index]) => [id, other, index]`)
expect(code).contains(`_ctx0[0].value + _ctx0[1].value + _ctx0[2].value`) expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`)
expect(ir.block.operation[0]).toMatchObject({ expect(ir.block.operation[0]).toMatchObject({
type: IRNodeTypes.FOR, type: IRNodeTypes.FOR,
source: { source: {
@ -163,7 +163,7 @@ describe('compiler: v-for', () => {
) )
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains(`([[id, ...other], index]) => [id, other, index]`) expect(code).contains(`([[id, ...other], index]) => [id, other, index]`)
expect(code).contains(`_ctx0[0].value + _ctx0[1].value + _ctx0[2]`) expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`)
expect(ir.block.operation[0]).toMatchObject({ expect(ir.block.operation[0]).toMatchObject({
type: IRNodeTypes.FOR, type: IRNodeTypes.FOR,
source: { source: {
@ -199,7 +199,7 @@ describe('compiler: v-for', () => {
expect(code).matchSnapshot() expect(code).matchSnapshot()
expect(code).contains(`([{ foo = bar, baz: [qux = quux] }]) => [foo, qux]`) expect(code).contains(`([{ foo = bar, baz: [qux = quux] }]) => [foo, qux]`)
expect(code).contains( expect(code).contains(
`_ctx0[0].value + _ctx.bar + _ctx.baz + _ctx0[1].value + _ctx.quux`, `_ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux`,
) )
expect(ir.block.operation[0]).toMatchObject({ expect(ir.block.operation[0]).toMatchObject({
type: IRNodeTypes.FOR, type: IRNodeTypes.FOR,

View File

@ -29,7 +29,7 @@ export function genFor(
container, container,
} = oper } = oper
let isDestructureAssignment = false let isDestructure = false
let rawValue: string | null = null let rawValue: string | null = null
const rawKey = key && key.content const rawKey = key && key.content
const rawIndex = index && index.content const rawIndex = index && index.content
@ -39,7 +39,7 @@ export function genFor(
let blockFn = genBlockFn() let blockFn = genBlockFn()
const simpleIdMap: Record<string, null> = genSimpleIdMap() const simpleIdMap: Record<string, null> = genSimpleIdMap()
if (isDestructureAssignment) { if (isDestructure) {
const idMap: Record<string, null> = {} const idMap: Record<string, null> = {}
idsInValue.forEach(id => (idMap[id] = null)) idsInValue.forEach(id => (idMap[id] = null))
if (rawKey) idMap[rawKey] = null if (rawKey) idMap[rawKey] = null
@ -82,7 +82,7 @@ export function genFor(
const idsInValue = new Set<string>() const idsInValue = new Set<string>()
if (value) { if (value) {
rawValue = value && value.content rawValue = value && value.content
if ((isDestructureAssignment = !!value.ast)) { if ((isDestructure = !!value.ast)) {
walkIdentifiers( walkIdentifiers(
value.ast, value.ast,
(id, _, __, ___, isLocal) => { (id, _, __, ___, isLocal) => {
@ -103,12 +103,13 @@ export function genFor(
const idMap: Record<string, string | null> = {} const idMap: Record<string, string | null> = {}
if (context.options.prefixIdentifiers) { if (context.options.prefixIdentifiers) {
propsName = `_ctx${depth}` propsName = `_ctx${depth}`
let suffix = isDestructure ? '' : '.value'
Array.from(idsInValue).forEach( Array.from(idsInValue).forEach(
(id, idIndex) => (idMap[id] = `${propsName}[${idIndex}].value`), (id, idIndex) => (idMap[id] = `${propsName}[${idIndex}]${suffix}`),
) )
if (rawKey) idMap[rawKey] = `${propsName}[${idsInValue.size}].value` if (rawKey) idMap[rawKey] = `${propsName}[${idsInValue.size}]${suffix}`
if (rawIndex) if (rawIndex)
idMap[rawIndex] = `${propsName}[${idsInValue.size + 1}].value` idMap[rawIndex] = `${propsName}[${idsInValue.size + 1}]${suffix}`
} else { } else {
propsName = `[${[rawValue || ((rawKey || rawIndex) && '_'), rawKey || (rawIndex && '__'), rawIndex].filter(Boolean).join(', ')}]` propsName = `[${[rawValue || ((rawKey || rawIndex) && '_'), rawKey || (rawIndex && '__'), rawIndex].filter(Boolean).join(', ')}]`
} }

View File

@ -4,7 +4,9 @@ import {
ref, ref,
renderEffect, renderEffect,
shallowRef, shallowRef,
template,
triggerRef, triggerRef,
withDestructure,
} from '../src' } from '../src'
import { makeRender } from './_utils' import { makeRender } from './_utils'
@ -579,4 +581,27 @@ describe('createFor', () => {
await nextTick() await nextTick()
expectCalledTimesToBe('Clear rows', 1, 0, 0, 0) expectCalledTimesToBe('Clear rows', 1, 0, 0, 0)
}) })
test('withDestructure', () => {
const list = ref([{ name: 'a' }, { name: 'b' }, { name: 'c' }])
const { host } = define(() => {
const n1 = createFor(
() => list.value,
withDestructure(
([{ name }, index]) => [name, index],
ctx => {
const span = template(`<li>${ctx[1]}. ${ctx[0]}</li>`)()
return span
},
),
item => item.name,
)
return n1
}).render()
expect(host.innerHTML).toBe(
'<li>0. a</li><li>1. b</li><li>2. c</li><!--for-->',
)
})
}) })

View File

@ -1,14 +1,18 @@
import { shallowReactive } from '@vue/reactivity' import {
type ShallowUnwrapRef,
proxyRefs,
shallowReactive,
} from '@vue/reactivity'
import { renderEffect } from './renderEffect' import { renderEffect } from './renderEffect'
export function withDestructure<P extends any[], R>( export function withDestructure<T extends any[], R>(
assign: (...args: P) => any[], assign: (data: ShallowUnwrapRef<T>) => any[],
block: (ctx: any[]) => R, block: (ctx: any[]) => R,
): (...args: P) => R { ): (data: T) => R {
return (...args: P) => { return (data: T) => {
const ctx = shallowReactive<any[]>([]) const ctx = shallowReactive<any[]>([])
renderEffect(() => { renderEffect(() => {
const res = assign(...args) const res = assign(proxyRefs(data))
const len = res.length const len = res.length
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
ctx[i] = res[i] ctx[i] = res[i]