]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: add tests
authordaiwei <daiwei521@126.com>
Thu, 29 May 2025 13:45:00 +0000 (21:45 +0800)
committerdaiwei <daiwei521@126.com>
Thu, 29 May 2025 14:13:46 +0000 (22:13 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts
packages/compiler-vapor/src/transform.ts
packages/compiler-vapor/src/transforms/transformSlotOutlet.ts
packages/compiler-vapor/src/transforms/vSlot.ts
packages/runtime-vapor/__tests__/componentSlots.spec.ts

index 4ecd8c76a7ee1478cc5e059b289ef2bad056e103..d1d80d4d62099d7f75516b925ba239dcc28005d0 100644 (file)
@@ -103,6 +103,97 @@ export function render(_ctx) {
 }"
 `;
 
+exports[`compiler: transform slot > forwarded slots > <slot w/ nested component> 1`] = `
+"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _createForwardedSlot = _forwardedSlotCreator()
+  const _component_Comp = _resolveComponent("Comp")
+  const n2 = _createComponentWithFallback(_component_Comp, null, {
+    "default": () => {
+      const n1 = _createComponentWithFallback(_component_Comp, null, {
+        "default": () => {
+          const n0 = _createForwardedSlot("default", null)
+          return n0
+        }
+      })
+      return n1
+    }
+  }, true)
+  return n2
+}"
+`;
+
+exports[`compiler: transform slot > forwarded slots > <slot> tag only 1`] = `
+"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _createForwardedSlot = _forwardedSlotCreator()
+  const _component_Comp = _resolveComponent("Comp")
+  const n1 = _createComponentWithFallback(_component_Comp, null, {
+    "default": () => {
+      const n0 = _createForwardedSlot("default", null)
+      return n0
+    }
+  }, true)
+  return n1
+}"
+`;
+
+exports[`compiler: transform slot > forwarded slots > <slot> tag w/ template 1`] = `
+"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _createForwardedSlot = _forwardedSlotCreator()
+  const _component_Comp = _resolveComponent("Comp")
+  const n2 = _createComponentWithFallback(_component_Comp, null, {
+    "default": () => {
+      const n0 = _createForwardedSlot("default", null)
+      return n0
+    }
+  }, true)
+  return n2
+}"
+`;
+
+exports[`compiler: transform slot > forwarded slots > <slot> tag w/ v-for 1`] = `
+"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createFor as _createFor, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _createForwardedSlot = _forwardedSlotCreator()
+  const _component_Comp = _resolveComponent("Comp")
+  const n3 = _createComponentWithFallback(_component_Comp, null, {
+    "default": () => {
+      const n0 = _createFor(() => (_ctx.b), (_for_item0) => {
+        const n2 = _createForwardedSlot("default", null)
+        return n2
+      })
+      return n0
+    }
+  }, true)
+  return n3
+}"
+`;
+
+exports[`compiler: transform slot > forwarded slots > <slot> tag w/ v-if 1`] = `
+"import { forwardedSlotCreator as _forwardedSlotCreator, resolveComponent as _resolveComponent, createIf as _createIf, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _createForwardedSlot = _forwardedSlotCreator()
+  const _component_Comp = _resolveComponent("Comp")
+  const n3 = _createComponentWithFallback(_component_Comp, null, {
+    "default": () => {
+      const n0 = _createIf(() => (_ctx.ok), () => {
+        const n2 = _createForwardedSlot("default", null)
+        return n2
+      })
+      return n0
+    }
+  }, true)
+  return n3
+}"
+`;
+
 exports[`compiler: transform slot > implicit default slot 1`] = `
 "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
 const t0 = _template("<div></div>")
index 84ddb2e5d046d28ce3d5a36eb71fdb4720a92443..a7da3d542f71b724c6acdfe8e8bc59de4916da96 100644 (file)
@@ -409,6 +409,35 @@ describe('compiler: transform slot', () => {
     })
   })
 
+  describe('forwarded slots', () => {
+    test('<slot> tag only', () => {
+      const { code } = compileWithSlots(`<Comp><slot/></Comp>`)
+      expect(code).toMatchSnapshot()
+    })
+
+    test('<slot> tag w/ v-if', () => {
+      const { code } = compileWithSlots(`<Comp><slot v-if="ok"/></Comp>`)
+      expect(code).toMatchSnapshot()
+    })
+
+    test('<slot> tag w/ v-for', () => {
+      const { code } = compileWithSlots(`<Comp><slot v-for="a in b"/></Comp>`)
+      expect(code).toMatchSnapshot()
+    })
+
+    test('<slot> tag w/ template', () => {
+      const { code } = compileWithSlots(
+        `<Comp><template #default><slot/></template></Comp>`,
+      )
+      expect(code).toMatchSnapshot()
+    })
+
+    test('<slot w/ nested component>', () => {
+      const { code } = compileWithSlots(`<Comp><Comp><slot/></Comp></Comp>`)
+      expect(code).toMatchSnapshot()
+    })
+  })
+
   describe('errors', () => {
     test('error on extraneous children w/ named default slot', () => {
       const onError = vi.fn()
index 93488ae95a160e5d11efe9493131c7cb96698557..6d07ebcaf52dd2109ca5ef5e15424ebb35084ad2 100644 (file)
@@ -76,6 +76,7 @@ export class TransformContext<T extends AllNode = AllNode> {
 
   inVOnce: boolean = false
   inVFor: number = 0
+  inSlot: number = 0
 
   comment: CommentNode[] = []
   component: Set<string> = this.ir.component
index 159d70c3814b258a1dced5b335282480249550f9..a281c90a70d2e1939f46acca59439eefa931175c 100644 (file)
@@ -100,11 +100,14 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
   }
 
   return () => {
-    let forwarded = false
-    const slotNode = context.block.node
-    if (slotNode.type === NodeTypes.ELEMENT) {
-      forwarded = hasForwardedSlots(slotNode.children)
-    }
+    const {
+      block: { node: slotNode },
+      inSlot,
+    } = context
+    const forwarded =
+      inSlot !== 0 &&
+      slotNode.type === NodeTypes.ELEMENT &&
+      hasForwardedSlots(slotNode.children)
     if (forwarded) context.ir.hasForwardedSlot = true
 
     exitBlock && exitBlock()
@@ -141,7 +144,6 @@ function createFallback(
   return [fallback, exitBlock]
 }
 
-// TODO
 function hasForwardedSlots(children: TemplateChildNode[]): boolean {
   for (let i = 0; i < children.length; i++) {
     const child = children[i]
index d1bf1c6b05f54fd3344e2c12024361971a04785c..2e767cb41cd412792a2eb953b3d33ccd43b4c5de 100644 (file)
@@ -237,7 +237,14 @@ function createSlotBlock(
   const block: SlotBlockIRNode = newBlock(slotNode)
   block.props = dir && dir.exp
   const exitBlock = context.enterBlock(block)
-  return [block, exitBlock]
+  context.inSlot++
+  return [
+    block,
+    () => {
+      context.inSlot--
+      exitBlock()
+    },
+  ]
 }
 
 function isNonWhitespaceContent(node: TemplateChildNode): boolean {
index 58076fff9eea213c8180d87ef5ed089951560798..46bfc3d938d03bf265e6ee0a90cf1629d6494f33 100644 (file)
@@ -7,6 +7,7 @@ import {
   createSlot,
   createVaporApp,
   defineVaporComponent,
+  forwardedSlotCreator,
   insert,
   prepend,
   renderEffect,
@@ -15,7 +16,7 @@ import {
 import { currentInstance, nextTick, ref } from '@vue/runtime-dom'
 import { makeRender } from './_utils'
 import type { DynamicSlot } from '../src/componentSlots'
-import { setElementText } from '../src/dom/prop'
+import { setElementText, setText } from '../src/dom/prop'
 
 const define = makeRender<any>()
 
@@ -503,4 +504,55 @@ describe('component: slots', () => {
       expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
     })
   })
+
+  describe('forwarded slot', () => {
+    test('should work', async () => {
+      const Child = defineVaporComponent({
+        setup() {
+          return createSlot('foo', null)
+        },
+      })
+      const Parent = defineVaporComponent({
+        setup() {
+          const createForwardedSlot = forwardedSlotCreator()
+          const n2 = createComponent(
+            Child,
+            null,
+            {
+              foo: () => {
+                return createForwardedSlot('foo', null)
+              },
+            },
+            true,
+          )
+          return n2
+        },
+      })
+
+      const foo = ref('foo')
+      const { host } = define({
+        setup() {
+          const n2 = createComponent(
+            Parent,
+            null,
+            {
+              foo: () => {
+                const n0 = template(' ')() as any
+                renderEffect(() => setText(n0, foo.value))
+                return n0
+              },
+            },
+            true,
+          )
+          return n2
+        },
+      }).render()
+
+      expect(host.innerHTML).toBe('foo<!--slot--><!--slot-->')
+
+      foo.value = 'bar'
+      await nextTick()
+      expect(host.innerHTML).toBe('bar<!--slot--><!--slot-->')
+    })
+  })
 })