Skip to content

Commit 2b0def3

Browse files
LittleSoundsxzz
andauthored
feat(compiler-vapor): slot outlet (#182)
Co-authored-by: 三咲智子 Kevin Deng <[email protected]>
1 parent bfb5250 commit 2b0def3

File tree

11 files changed

+585
-6
lines changed

11 files changed

+585
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`compiler: transform <slot> outlets > default slot outlet 1`] = `
4+
"import { createSlot as _createSlot } from 'vue/vapor';
5+
6+
export function render(_ctx) {
7+
const n0 = _createSlot("default", null)
8+
return n0
9+
}"
10+
`;
11+
12+
exports[`compiler: transform <slot> outlets > default slot outlet with fallback 1`] = `
13+
"import { createSlot as _createSlot, template as _template } from 'vue/vapor';
14+
const t0 = _template("<div></div>")
15+
16+
export function render(_ctx) {
17+
const n0 = _createSlot("default", null, () => {
18+
const n2 = t0()
19+
return n2
20+
})
21+
return n0
22+
}"
23+
`;
24+
25+
exports[`compiler: transform <slot> outlets > default slot outlet with props 1`] = `
26+
"import { createSlot as _createSlot } from 'vue/vapor';
27+
28+
export function render(_ctx) {
29+
const n0 = _createSlot("default", [
30+
{
31+
foo: () => ("bar"),
32+
baz: () => (_ctx.qux),
33+
fooBar: () => (_ctx.foo-_ctx.bar)
34+
}
35+
])
36+
return n0
37+
}"
38+
`;
39+
40+
exports[`compiler: transform <slot> outlets > dynamically named slot outlet 1`] = `
41+
"import { createSlot as _createSlot } from 'vue/vapor';
42+
43+
export function render(_ctx) {
44+
const n0 = _createSlot(() => (_ctx.foo + _ctx.bar), null)
45+
return n0
46+
}"
47+
`;
48+
49+
exports[`compiler: transform <slot> outlets > dynamically named slot outlet with v-bind shorthand 1`] = `
50+
"import { createSlot as _createSlot } from 'vue/vapor';
51+
52+
export function render(_ctx) {
53+
const n0 = _createSlot(() => (_ctx.name), null)
54+
return n0
55+
}"
56+
`;
57+
58+
exports[`compiler: transform <slot> outlets > error on unexpected custom directive on <slot> 1`] = `
59+
"import { createSlot as _createSlot } from 'vue/vapor';
60+
61+
export function render(_ctx) {
62+
const n0 = _createSlot("default", null)
63+
return n0
64+
}"
65+
`;
66+
67+
exports[`compiler: transform <slot> outlets > error on unexpected custom directive with v-show on <slot> 1`] = `
68+
"import { createSlot as _createSlot } from 'vue/vapor';
69+
70+
export function render(_ctx) {
71+
const n0 = _createSlot("default", null)
72+
return n0
73+
}"
74+
`;
75+
76+
exports[`compiler: transform <slot> outlets > named slot outlet with fallback 1`] = `
77+
"import { createSlot as _createSlot, template as _template } from 'vue/vapor';
78+
const t0 = _template("<div></div>")
79+
80+
export function render(_ctx) {
81+
const n0 = _createSlot("foo", null, () => {
82+
const n2 = t0()
83+
return n2
84+
})
85+
return n0
86+
}"
87+
`;
88+
89+
exports[`compiler: transform <slot> outlets > statically named slot outlet 1`] = `
90+
"import { createSlot as _createSlot } from 'vue/vapor';
91+
92+
export function render(_ctx) {
93+
const n0 = _createSlot("foo", null)
94+
return n0
95+
}"
96+
`;
97+
98+
exports[`compiler: transform <slot> outlets > statically named slot outlet with props 1`] = `
99+
"import { createSlot as _createSlot } from 'vue/vapor';
100+
101+
export function render(_ctx) {
102+
const n0 = _createSlot("foo", [
103+
{
104+
foo: () => ("bar"),
105+
baz: () => (_ctx.qux)
106+
}
107+
])
108+
return n0
109+
}"
110+
`;
111+
112+
exports[`compiler: transform <slot> outlets > statically named slot outlet with v-bind="obj" 1`] = `
113+
"import { createSlot as _createSlot } from 'vue/vapor';
114+
115+
export function render(_ctx) {
116+
const n0 = _createSlot("foo", [
117+
{ foo: () => ("bar") },
118+
() => (_ctx.obj),
119+
{ baz: () => (_ctx.qux) }
120+
])
121+
return n0
122+
}"
123+
`;
124+
125+
exports[`compiler: transform <slot> outlets > statically named slot outlet with v-on 1`] = `
126+
"import { createSlot as _createSlot, toHandlers as _toHandlers } from 'vue/vapor';
127+
128+
export function render(_ctx) {
129+
const n0 = _createSlot("default", [
130+
{ onClick: () => _ctx.foo },
131+
() => (_toHandlers(_ctx.bar)),
132+
{ baz: () => (_ctx.qux) }
133+
])
134+
return n0
135+
}"
136+
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
import { ErrorCodes, NodeTypes } from '@vue/compiler-core'
2+
import {
3+
IRNodeTypes,
4+
transformChildren,
5+
transformElement,
6+
transformSlotOutlet,
7+
transformText,
8+
transformVBind,
9+
transformVOn,
10+
transformVShow,
11+
} from '../../src'
12+
import { makeCompile } from './_utils'
13+
14+
const compileWithSlotsOutlet = makeCompile({
15+
nodeTransforms: [
16+
transformText,
17+
transformSlotOutlet,
18+
transformElement,
19+
transformChildren,
20+
],
21+
directiveTransforms: {
22+
bind: transformVBind,
23+
on: transformVOn,
24+
show: transformVShow,
25+
},
26+
})
27+
28+
describe('compiler: transform <slot> outlets', () => {
29+
test('default slot outlet', () => {
30+
const { ir, code, vaporHelpers } = compileWithSlotsOutlet(`<slot />`)
31+
expect(code).toMatchSnapshot()
32+
expect(vaporHelpers).toContain('createSlot')
33+
expect(ir.block.effect).toEqual([])
34+
expect(ir.block.operation).toMatchObject([
35+
{
36+
type: IRNodeTypes.SLOT_OUTLET_NODE,
37+
id: 0,
38+
name: {
39+
type: NodeTypes.SIMPLE_EXPRESSION,
40+
content: 'default',
41+
isStatic: true,
42+
},
43+
props: [],
44+
fallback: undefined,
45+
},
46+
])
47+
})
48+
49+
test('statically named slot outlet', () => {
50+
const { ir, code } = compileWithSlotsOutlet(`<slot name="foo" />`)
51+
expect(code).toMatchSnapshot()
52+
expect(ir.block.operation).toMatchObject([
53+
{
54+
type: IRNodeTypes.SLOT_OUTLET_NODE,
55+
id: 0,
56+
name: {
57+
type: NodeTypes.SIMPLE_EXPRESSION,
58+
content: 'foo',
59+
isStatic: true,
60+
},
61+
},
62+
])
63+
})
64+
65+
test('dynamically named slot outlet', () => {
66+
const { ir, code } = compileWithSlotsOutlet(`<slot :name="foo + bar" />`)
67+
expect(code).toMatchSnapshot()
68+
expect(ir.block.operation).toMatchObject([
69+
{
70+
type: IRNodeTypes.SLOT_OUTLET_NODE,
71+
id: 0,
72+
name: {
73+
type: NodeTypes.SIMPLE_EXPRESSION,
74+
content: 'foo + bar',
75+
isStatic: false,
76+
},
77+
},
78+
])
79+
})
80+
81+
test('dynamically named slot outlet with v-bind shorthand', () => {
82+
const { ir, code } = compileWithSlotsOutlet(`<slot :name />`)
83+
expect(code).toMatchSnapshot()
84+
expect(ir.block.operation).toMatchObject([
85+
{
86+
type: IRNodeTypes.SLOT_OUTLET_NODE,
87+
id: 0,
88+
name: {
89+
type: NodeTypes.SIMPLE_EXPRESSION,
90+
content: 'name',
91+
isStatic: false,
92+
},
93+
},
94+
])
95+
})
96+
97+
test('default slot outlet with props', () => {
98+
const { ir, code } = compileWithSlotsOutlet(
99+
`<slot foo="bar" :baz="qux" :foo-bar="foo-bar" />`,
100+
)
101+
expect(code).toMatchSnapshot()
102+
expect(ir.block.operation).toMatchObject([
103+
{
104+
type: IRNodeTypes.SLOT_OUTLET_NODE,
105+
name: { content: 'default' },
106+
props: [
107+
[
108+
{ key: { content: 'foo' }, values: [{ content: 'bar' }] },
109+
{ key: { content: 'baz' }, values: [{ content: 'qux' }] },
110+
{ key: { content: 'fooBar' }, values: [{ content: 'foo-bar' }] },
111+
],
112+
],
113+
},
114+
])
115+
})
116+
117+
test('statically named slot outlet with props', () => {
118+
const { ir, code } = compileWithSlotsOutlet(
119+
`<slot name="foo" foo="bar" :baz="qux" />`,
120+
)
121+
expect(code).toMatchSnapshot()
122+
expect(ir.block.operation).toMatchObject([
123+
{
124+
type: IRNodeTypes.SLOT_OUTLET_NODE,
125+
name: { content: 'foo' },
126+
props: [
127+
[
128+
{ key: { content: 'foo' }, values: [{ content: 'bar' }] },
129+
{ key: { content: 'baz' }, values: [{ content: 'qux' }] },
130+
],
131+
],
132+
},
133+
])
134+
})
135+
136+
test('statically named slot outlet with v-bind="obj"', () => {
137+
const { ir, code } = compileWithSlotsOutlet(
138+
`<slot name="foo" foo="bar" v-bind="obj" :baz="qux" />`,
139+
)
140+
expect(code).toMatchSnapshot()
141+
expect(ir.block.operation).toMatchObject([
142+
{
143+
type: IRNodeTypes.SLOT_OUTLET_NODE,
144+
name: { content: 'foo' },
145+
props: [
146+
[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }],
147+
{ value: { content: 'obj', isStatic: false } },
148+
[{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
149+
],
150+
},
151+
])
152+
})
153+
154+
test('statically named slot outlet with v-on', () => {
155+
const { ir, code } = compileWithSlotsOutlet(
156+
`<slot @click="foo" v-on="bar" :baz="qux" />`,
157+
)
158+
expect(code).toMatchSnapshot()
159+
expect(ir.block.operation).toMatchObject([
160+
{
161+
type: IRNodeTypes.SLOT_OUTLET_NODE,
162+
props: [
163+
[{ key: { content: 'click' }, values: [{ content: 'foo' }] }],
164+
{ value: { content: 'bar' }, handler: true },
165+
[{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
166+
],
167+
},
168+
])
169+
})
170+
171+
test('default slot outlet with fallback', () => {
172+
const { ir, code } = compileWithSlotsOutlet(`<slot><div/></slot>`)
173+
expect(code).toMatchSnapshot()
174+
expect(ir.template[0]).toMatchObject('<div></div>')
175+
expect(ir.block.operation).toMatchObject([
176+
{
177+
type: IRNodeTypes.SLOT_OUTLET_NODE,
178+
id: 0,
179+
name: { content: 'default' },
180+
fallback: {
181+
type: IRNodeTypes.BLOCK,
182+
dynamic: {
183+
children: [{ template: 0, id: 2 }],
184+
},
185+
returns: [2],
186+
},
187+
},
188+
])
189+
})
190+
191+
test('named slot outlet with fallback', () => {
192+
const { ir, code } = compileWithSlotsOutlet(
193+
`<slot name="foo"><div/></slot>`,
194+
)
195+
expect(code).toMatchSnapshot()
196+
expect(ir.template[0]).toMatchObject('<div></div>')
197+
expect(ir.block.operation).toMatchObject([
198+
{
199+
type: IRNodeTypes.SLOT_OUTLET_NODE,
200+
id: 0,
201+
name: { content: 'foo' },
202+
fallback: {
203+
type: IRNodeTypes.BLOCK,
204+
dynamic: {
205+
children: [{ template: 0, id: 2 }],
206+
},
207+
returns: [2],
208+
},
209+
},
210+
])
211+
})
212+
213+
test('error on unexpected custom directive on <slot>', () => {
214+
const onError = vi.fn()
215+
const source = `<slot v-foo />`
216+
const index = source.indexOf('v-foo')
217+
const { code } = compileWithSlotsOutlet(source, { onError })
218+
expect(code).toMatchSnapshot()
219+
expect(onError.mock.calls[0][0]).toMatchObject({
220+
code: ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
221+
loc: {
222+
start: {
223+
offset: index,
224+
line: 1,
225+
column: index + 1,
226+
},
227+
end: {
228+
offset: index + 5,
229+
line: 1,
230+
column: index + 6,
231+
},
232+
},
233+
})
234+
})
235+
236+
test('error on unexpected custom directive with v-show on <slot>', () => {
237+
const onError = vi.fn()
238+
const source = `<slot v-show="ok" />`
239+
const index = source.indexOf('v-show="ok"')
240+
const { code } = compileWithSlotsOutlet(source, { onError })
241+
expect(code).toMatchSnapshot()
242+
expect(onError.mock.calls[0][0]).toMatchObject({
243+
code: ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
244+
loc: {
245+
start: {
246+
offset: index,
247+
line: 1,
248+
column: index + 1,
249+
},
250+
end: {
251+
offset: index + 11,
252+
line: 1,
253+
column: index + 12,
254+
},
255+
},
256+
})
257+
})
258+
})

0 commit comments

Comments
 (0)