wip(vapor): support rest elements in v-for destructure
This commit is contained in:
parent
5d88c53cd3
commit
95cf749f8b
|
@ -1,5 +1,19 @@
|
|||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`compiler: v-for > array de-structured value (with rest) 1`] = `
|
||||
"import { setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div></div>", true)
|
||||
|
||||
export function render(_ctx) {
|
||||
const n0 = _createFor(() => (_ctx.list), (_ctx0) => {
|
||||
const n2 = t0()
|
||||
_renderEffect(() => _setText(n2, _ctx0[0].value[0] + _ctx0[0].value.slice(1) + _ctx0[1].value))
|
||||
return n2
|
||||
}, ([id, ...other], index) => (id))
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > array de-structured value 1`] = `
|
||||
"import { setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div></div>", true)
|
||||
|
@ -30,20 +44,6 @@ export function render(_ctx) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > function params w/ prefixIdentifiers: false 1`] = `
|
||||
"import { setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div></div>", true)
|
||||
|
||||
export function render(_ctx) {
|
||||
const n0 = _createFor(() => (items), ([item, __, k]) => {
|
||||
const n2 = t0()
|
||||
_renderEffect(() => _setText(n2, item))
|
||||
return n2
|
||||
}, (item, __, k) => (k))
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > multi effect 1`] = `
|
||||
"import { setProp as _setProp, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div></div>", true)
|
||||
|
@ -82,13 +82,13 @@ export function render(_ctx) {
|
|||
`;
|
||||
|
||||
exports[`compiler: v-for > object de-structured value (with rest) 1`] = `
|
||||
"import { setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
|
||||
"import { getRestElement as _getRestElement, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div></div>", true)
|
||||
|
||||
export function render(_ctx) {
|
||||
const n0 = _createFor(() => (_ctx.list), (_ctx0) => {
|
||||
const n2 = t0()
|
||||
_renderEffect(() => _setText(n2, _ctx0[0].value.id + _ctx0[0].value + _ctx0[1].value))
|
||||
_renderEffect(() => _setText(n2, _ctx0[0].value.id + _getRestElement(_ctx0[0].value, ["id"]) + _ctx0[1].value))
|
||||
return n2
|
||||
}, ({ id, ...other }, index) => (id))
|
||||
return n0
|
||||
|
@ -109,34 +109,6 @@ export function render(_ctx) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > object de-structured value 2`] = `
|
||||
"import { setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div></div>", true)
|
||||
|
||||
export function render(_ctx) {
|
||||
const n0 = _createFor(() => (_ctx.list), (_ctx0) => {
|
||||
const n2 = t0()
|
||||
_renderEffect(() => _setText(n2, _ctx0[0].value.id + _ctx0[0].value + _ctx0[1].value))
|
||||
return n2
|
||||
}, ({ id, ...other }, index) => (id))
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > v-for aliases w/ complex expressions 1`] = `
|
||||
"import { setText as _setText, renderEffect as _renderEffect, withDestructure as _withDestructure, createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div></div>", true)
|
||||
|
||||
export function render(_ctx) {
|
||||
const n0 = _createFor(() => (_ctx.list), _withDestructure(([{ foo = bar, baz: [qux = quux] }]) => [foo, qux], (_ctx0) => {
|
||||
const n2 = t0()
|
||||
_renderEffect(() => _setText(n2, _ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux))
|
||||
return n2
|
||||
}))
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-for > w/o value 1`] = `
|
||||
"import { createFor as _createFor, template as _template } from 'vue';
|
||||
const t0 = _template("<div>item</div>", true)
|
||||
|
|
|
@ -144,11 +144,12 @@ describe('compiler: v-for', () => {
|
|||
})
|
||||
})
|
||||
|
||||
test.todo('object de-structured value (with rest)', () => {
|
||||
test('object de-structured value (with rest)', () => {
|
||||
const { code, ir } = compileWithVFor(
|
||||
`<div v-for="( { id, ...other }, index) in list" :key="id">{{ id + other + index }}</div>`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(code).toContain('_getRestElement(_ctx0[0].value, ["id"])')
|
||||
expect(ir.block.operation[0]).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
source: {
|
||||
|
@ -206,11 +207,12 @@ describe('compiler: v-for', () => {
|
|||
})
|
||||
})
|
||||
|
||||
test.todo('array de-structured value (with rest)', () => {
|
||||
test('array de-structured value (with rest)', () => {
|
||||
const { code, ir } = compileWithVFor(
|
||||
`<div v-for="([id, ...other], index) in list" :key="id">{{ id + other + index }}</div>`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(code).toContain('_ctx0[0].value.slice(1)')
|
||||
expect(ir.block.operation[0]).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
source: {
|
||||
|
|
|
@ -31,13 +31,20 @@ export function genFor(
|
|||
const idMap: Record<string, string | SimpleExpressionNode | null> = {}
|
||||
|
||||
idToPathMap.forEach((pathInfo, id) => {
|
||||
const path = `${propsName}[0].value${pathInfo ? pathInfo.path : ''}`
|
||||
if (pathInfo && pathInfo.dynamic) {
|
||||
const node = (idMap[id] = createSimpleExpression(path))
|
||||
const plugins = context.options.expressionPlugins
|
||||
node.ast = parseExpression(`(${path})`, {
|
||||
plugins: plugins ? [...plugins, 'typescript'] : ['typescript'],
|
||||
})
|
||||
let path = `${propsName}[0].value${pathInfo ? pathInfo.path : ''}`
|
||||
if (pathInfo) {
|
||||
if (pathInfo.helper) {
|
||||
path = `${pathInfo.helper}(${path}, ${pathInfo.helperArgs})`
|
||||
}
|
||||
if (pathInfo.dynamic) {
|
||||
const node = (idMap[id] = createSimpleExpression(path))
|
||||
const plugins = context.options.expressionPlugins
|
||||
node.ast = parseExpression(`(${path})`, {
|
||||
plugins: plugins ? [...plugins, 'typescript'] : ['typescript'],
|
||||
})
|
||||
} else {
|
||||
idMap[id] = path
|
||||
}
|
||||
} else {
|
||||
idMap[id] = path
|
||||
}
|
||||
|
@ -68,7 +75,15 @@ export function genFor(
|
|||
// construct a id -> accessor path map.
|
||||
// e.g. `{ x: { y: [z] }}` -> `Map{ 'z' => '.x.y[0]' }`
|
||||
function parseValueDestructure() {
|
||||
const map = new Map<string, { path: string; dynamic: boolean } | null>()
|
||||
const map = new Map<
|
||||
string,
|
||||
{
|
||||
path: string
|
||||
dynamic: boolean
|
||||
helper?: string
|
||||
helperArgs?: string
|
||||
} | null
|
||||
>()
|
||||
if (value) {
|
||||
rawValue = value && value.content
|
||||
if (value.ast) {
|
||||
|
@ -78,32 +93,62 @@ export function genFor(
|
|||
if (isLocal) {
|
||||
let path = ''
|
||||
let isDynamic = false
|
||||
let helper
|
||||
let helperArgs
|
||||
for (let i = 0; i < parentStack.length; i++) {
|
||||
const parent = parentStack[i]
|
||||
const child = parentStack[i + 1] || id
|
||||
|
||||
if (
|
||||
parent.type === 'ObjectProperty' &&
|
||||
parent.value === child
|
||||
) {
|
||||
if (parent.computed && parent.key.type !== 'StringLiteral') {
|
||||
if (parent.key.type === 'StringLiteral') {
|
||||
path += `[${JSON.stringify(parent.key.value)}]`
|
||||
} else if (parent.computed) {
|
||||
isDynamic = true
|
||||
path += `[${value.content.slice(
|
||||
parent.key.start! - 1,
|
||||
parent.key.end! - 1,
|
||||
)}]`
|
||||
} else if (parent.key.type === 'StringLiteral') {
|
||||
path += `[${JSON.stringify(parent.key.value)}]`
|
||||
} else {
|
||||
// non-computed, can only be identifier
|
||||
path += `.${(parent.key as Identifier).name}`
|
||||
}
|
||||
} else if (parent.type === 'ArrayPattern') {
|
||||
const index = parent.elements.indexOf(child as any)
|
||||
path += `[${index}]`
|
||||
if (child.type === 'RestElement') {
|
||||
path += `.slice(${index})`
|
||||
} else {
|
||||
path += `[${index}]`
|
||||
}
|
||||
} else if (
|
||||
parent.type === 'ObjectPattern' &&
|
||||
child.type === 'RestElement'
|
||||
) {
|
||||
helper = context.helper('getRestElement')
|
||||
helperArgs =
|
||||
'[' +
|
||||
parent.properties
|
||||
.filter(p => p.type === 'ObjectProperty')
|
||||
.map(p => {
|
||||
if (p.key.type === 'StringLiteral') {
|
||||
return JSON.stringify(p.key.value)
|
||||
} else if (p.computed) {
|
||||
isDynamic = true
|
||||
return value.content.slice(
|
||||
p.key.start! - 1,
|
||||
p.key.end! - 1,
|
||||
)
|
||||
} else {
|
||||
return JSON.stringify((p.key as Identifier).name)
|
||||
}
|
||||
})
|
||||
.join(', ') +
|
||||
']'
|
||||
}
|
||||
// TODO handle rest spread
|
||||
}
|
||||
map.set(id.name, { path, dynamic: isDynamic })
|
||||
map.set(id.name, { path, dynamic: isDynamic, helper, helperArgs })
|
||||
}
|
||||
},
|
||||
true,
|
||||
|
@ -115,7 +160,6 @@ export function genFor(
|
|||
return map
|
||||
}
|
||||
|
||||
// TODO this should be looked at for destructure cases
|
||||
function genCallback(expr: SimpleExpressionNode | undefined) {
|
||||
if (!expr) return false
|
||||
const res = context.withId(
|
||||
|
|
|
@ -380,3 +380,12 @@ function normalizeAnchor(node: Block): Node {
|
|||
return normalizeAnchor(node.nodes!)
|
||||
}
|
||||
}
|
||||
|
||||
// runtime helper for rest element destructure
|
||||
export function getRestElement(val: any, keys: string[]): any {
|
||||
const res: any = {}
|
||||
for (const key in val) {
|
||||
if (!keys.includes(key)) res[key] = val[key]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -22,5 +22,5 @@ export {
|
|||
} from './dom/prop'
|
||||
export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
|
||||
export { createIf } from './apiCreateIf'
|
||||
export { createFor, createForSlots } from './apiCreateFor'
|
||||
export { createFor, createForSlots, getRestElement } from './apiCreateFor'
|
||||
export { createTemplateRefSetter } from './apiTemplateRef'
|
||||
|
|
Loading…
Reference in New Issue