Selaa lähdekoodia

refactor: general destructuring function (#221)

Rizumu Ayaka 2 vuotta sitten
vanhempi
commit
b2259a5f92

+ 9 - 18
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap

@@ -1,18 +1,15 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`compiler: v-for > array de-structured value 1`] = `
-"import { renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor';
+"import { renderEffect as _renderEffect, setText as _setText, withDestructure as _withDestructure, createFor as _createFor, template as _template } from 'vue/vapor';
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
-  const n0 = _createFor(() => (_ctx.list), (_ctx0) => {
+  const n0 = _createFor(() => (_ctx.list), _withDestructure((_state, [[id, ...other], index] = _state) => [id, other, index], (_ctx0) => {
     const n2 = t0()
     _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2]))
     return n2
-  }, ([id, ...other], index) => (id), null, null, false, _state => {
-    const [[id, ...other], index] = _state
-    return [id, other, index]
-  })
+  }), ([id, ...other], index) => (id))
   return n0
 }"
 `;
@@ -69,35 +66,29 @@ export function render(_ctx) {
 `;
 
 exports[`compiler: v-for > object de-structured value 1`] = `
-"import { renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor';
+"import { renderEffect as _renderEffect, setText as _setText, withDestructure as _withDestructure, createFor as _createFor, template as _template } from 'vue/vapor';
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
-  const n0 = _createFor(() => (_ctx.list), (_ctx0) => {
+  const n0 = _createFor(() => (_ctx.list), _withDestructure((_state, [{ id, ...other }, index] = _state) => [id, other, index], (_ctx0) => {
     const n2 = t0()
     _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2]))
     return n2
-  }, ({ id, ...other }, index) => (id), null, null, false, _state => {
-    const [{ id, ...other }, index] = _state
-    return [id, other, index]
-  })
+  }), ({ id, ...other }, index) => (id))
   return n0
 }"
 `;
 
 exports[`compiler: v-for > v-for aliases w/ complex expressions 1`] = `
-"import { renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor';
+"import { renderEffect as _renderEffect, setText as _setText, withDestructure as _withDestructure, createFor as _createFor, template as _template } from 'vue/vapor';
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
-  const n0 = _createFor(() => (_ctx.list), (_ctx0) => {
+  const n0 = _createFor(() => (_ctx.list), _withDestructure((_state, [{ foo = bar, baz: [qux = quux] }] = _state) => [foo, qux], (_ctx0) => {
     const n2 = t0()
     _renderEffect(() => _setText(n2, _ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux))
     return n2
-  }, null, null, null, false, _state => {
-    const [{ foo = bar, baz: [qux = quux] }] = _state
-    return [foo, qux]
-  })
+  }))
   return n0
 }"
 `;

+ 9 - 3
packages/compiler-vapor/__tests__/transforms/vFor.spec.ts

@@ -129,7 +129,9 @@ describe('compiler: v-for', () => {
       `<div v-for="(  { id, ...other }, index) in list" :key="id">{{ id + other + index }}</div>`,
     )
     expect(code).matchSnapshot()
-    expect(code).contains(`return [id, other, index]`)
+    expect(code).contains(
+      `(_state, [{ id, ...other }, index] = _state) => [id, other, index]`,
+    )
     expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`)
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
@@ -162,7 +164,9 @@ describe('compiler: v-for', () => {
       `<div v-for="([id, ...other], index) in list" :key="id">{{ id + other + index }}</div>`,
     )
     expect(code).matchSnapshot()
-    expect(code).contains(`return [id, other, index]`)
+    expect(code).contains(
+      `(_state, [[id, ...other], index] = _state) => [id, other, index]`,
+    )
     expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`)
     expect(ir.block.operation[0]).toMatchObject({
       type: IRNodeTypes.FOR,
@@ -197,7 +201,9 @@ describe('compiler: v-for', () => {
       </div>`,
     )
     expect(code).matchSnapshot()
-    expect(code).contains(`return [foo, qux]`)
+    expect(code).contains(
+      `(_state, [{ foo = bar, baz: [qux = quux] }] = _state) => [foo, qux]`,
+    )
     expect(code).contains(
       `_ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux`,
     )

+ 11 - 17
packages/compiler-vapor/src/generators/for.ts

@@ -6,8 +6,6 @@ import type { ForIRNode } from '../ir'
 import {
   type CodeFragment,
   DELIMITERS_ARRAY,
-  INDENT_END,
-  INDENT_START,
   NEWLINE,
   genCall,
   genMulti,
@@ -51,7 +49,7 @@ export function genFor(
   if (rawKey) idMap[rawKey] = `${propsName}[${idsOfValue.size}]`
   if (rawIndex) idMap[rawIndex] = `${propsName}[${idsOfValue.size + 1}]`
 
-  const blockFn = context.withId(
+  let blockFn = context.withId(
     () => genBlock(render, context, [propsName]),
     idMap,
   )
@@ -77,31 +75,28 @@ export function genFor(
     ]
   }
 
-  let destructureAssignmentFn: CodeFragment[] | false = false
   if (isDestructureAssignment) {
     const idMap: Record<string, null> = {}
     idsOfValue.forEach(id => (idMap[id] = null))
     if (rawKey) idMap[rawKey] = null
     if (rawIndex) idMap[rawIndex] = null
-    destructureAssignmentFn = [
-      '_state => {',
-      INDENT_START,
-      NEWLINE,
-      'const ',
+    const destructureAssignmentFn: CodeFragment[] = [
+      '(_state, ',
       ...genMulti(
         DELIMITERS_ARRAY,
         rawValue ? rawValue : rawKey || rawIndex ? '_' : undefined,
         rawKey ? rawKey : rawIndex ? '__' : undefined,
         rawIndex,
       ),
-      ' = _state',
-      NEWLINE,
-      'return ',
+      ' = _state) => ',
       ...genMulti(DELIMITERS_ARRAY, ...idsOfValue, rawKey, rawIndex),
-      INDENT_END,
-      NEWLINE,
-      '}',
     ]
+
+    blockFn = genCall(
+      vaporHelper('withDestructure'),
+      destructureAssignmentFn,
+      blockFn,
+    )
   }
 
   return [
@@ -114,8 +109,7 @@ export function genFor(
       getKeyFn,
       false, // todo: getMemo
       false, // todo: hydrationNode
-      (once && 'true') || (destructureAssignmentFn && 'false'),
-      destructureAssignmentFn,
+      once && 'true',
     ),
   ]
 }

+ 18 - 18
packages/runtime-vapor/__tests__/for.spec.ts

@@ -7,6 +7,7 @@ import {
   renderEffect,
   shallowRef,
   template,
+  withDestructure,
   withDirectives,
 } from '../src'
 import { makeRender } from './_utils'
@@ -318,25 +319,24 @@ describe('createFor', () => {
     const { host } = define(() => {
       const n1 = createFor(
         () => list.value,
-        state => {
-          const span = document.createElement('li')
-          renderEffect(() => {
-            const [name, key, index] = state
-            span.innerHTML = `${key}. ${name}`
-
-            // index should be undefined if source is not an object
-            expect(index).toBe(undefined)
-          })
-          return span
-        },
+        withDestructure(
+          state => {
+            const [{ name }, key, index] = state
+            return [name, key, index]
+          },
+          state => {
+            const span = document.createElement('li')
+            renderEffect(() => {
+              const [name, key, index] = state
+              span.innerHTML = `${key}. ${name}`
+
+              // index should be undefined if source is not an object
+              expect(index).toBe(undefined)
+            })
+            return span
+          },
+        ),
         item => item.name,
-        undefined,
-        undefined,
-        false,
-        state => {
-          const [{ name }, key, index] = state
-          return [name, key, index]
-        },
       )
       return n1
     }).render()

+ 1 - 7
packages/runtime-vapor/src/apiCreateFor.ts

@@ -26,7 +26,6 @@ import {
   invokeWithUpdate,
 } from './directivesChildFragment'
 import type { DynamicSlot } from './componentSlots'
-import { destructuring } from './destructuring'
 
 interface ForBlock extends Fragment {
   scope: BlockEffectScope
@@ -49,7 +48,6 @@ export const createFor = (
   getMemo?: (item: any, key: any, index?: number) => any[],
   hydrationNode?: Node,
   once?: boolean,
-  assignment?: (state: any[]) => any[],
 ): Fragment => {
   let isMounted = false
   let oldBlocks: ForBlock[] = []
@@ -283,11 +281,7 @@ export const createFor = (
       memo: getMemo && getMemo(item, key, index),
       [fragmentKey]: true,
     })
-    const proxyState = proxyRefs(state)
-    const itemCtx = assignment
-      ? destructuring(scope, proxyState, assignment)
-      : proxyState
-    block.nodes = scope.run(() => renderItem(itemCtx))!
+    block.nodes = scope.run(() => renderItem(proxyRefs(state)))!
 
     invokeWithMount(scope, () => {
       // TODO v-memo

+ 19 - 0
packages/runtime-vapor/src/destructure.ts

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

+ 0 - 20
packages/runtime-vapor/src/destructuring.ts

@@ -1,20 +0,0 @@
-import { type EffectScope, shallowReactive } from '@vue/reactivity'
-import { renderEffect } from './renderEffect'
-
-export function destructuring(
-  scope: EffectScope,
-  state: any,
-  fn: (state: any) => any[],
-) {
-  const list = shallowReactive<any[]>([])
-  scope.run(() => {
-    renderEffect(() => {
-      const res = fn(state)
-      const len = res.length
-      for (let i = 0; i < len; i++) {
-        list[i] = res[i]
-      }
-    })
-  })
-  return list
-}

+ 2 - 0
packages/runtime-vapor/src/index.ts

@@ -135,6 +135,8 @@ export { createComponent } from './apiCreateComponent'
 export { resolveComponent, resolveDirective } from './helpers/resolveAssets'
 export { toHandlers } from './helpers/toHandlers'
 
+export { withDestructure } from './destructure'
+
 // **Internal** DOM-only runtime directive helpers
 export {
   vModelText,