diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
index d67038943..93be46fc7 100644
--- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
@@ -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("
", 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("", 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("", 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("", 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("", 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("", 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("", 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("item
", true)
diff --git a/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts b/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
index e14380d76..59998d844 100644
--- a/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
+++ b/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
@@ -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(
`{{ id + other + index }}
`,
)
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(
`{{ id + other + index }}
`,
)
expect(code).matchSnapshot()
+ expect(code).toContain('_ctx0[0].value.slice(1)')
expect(ir.block.operation[0]).toMatchObject({
type: IRNodeTypes.FOR,
source: {
diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts
index af429c0e6..1d2b379e7 100644
--- a/packages/compiler-vapor/src/generators/for.ts
+++ b/packages/compiler-vapor/src/generators/for.ts
@@ -31,13 +31,20 @@ export function genFor(
const idMap: Record = {}
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()
+ 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(
diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts
index 2f27fe6b5..ceff76966 100644
--- a/packages/runtime-vapor/src/apiCreateFor.ts
+++ b/packages/runtime-vapor/src/apiCreateFor.ts
@@ -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
+}
diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts
index 4646f4ebe..8e4679a33 100644
--- a/packages/runtime-vapor/src/index.ts
+++ b/packages/runtime-vapor/src/index.ts
@@ -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'