Skip to content

Commit f183394

Browse files
committed
feat: error on unexpected custom directive on <slot>
1 parent 831b818 commit f183394

File tree

3 files changed

+56
-7
lines changed

3 files changed

+56
-7
lines changed

packages/compiler-vapor/__tests__/transforms/__snapshots__/transformSlotOutlet.spec.ts.snap

+9
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ export function render(_ctx) {
5353
}"
5454
`;
5555
56+
exports[`compiler: transform <slot> outlets > error on unexpected custom directive on <slot> 1`] = `
57+
"import { createSlot as _createSlot } from 'vue/vapor';
58+
59+
export function render(_ctx) {
60+
const n0 = _createSlot("default", null)
61+
return n0
62+
}"
63+
`;
64+
5665
exports[`compiler: transform <slot> outlets > named slot outlet with fallback 1`] = `
5766
"import { createSlot as _createSlot, template as _template } from 'vue/vapor';
5867
const t0 = _template("<div></div>")

packages/compiler-vapor/__tests__/transforms/transformSlotOutlet.spec.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NodeTypes } from '@vue/compiler-core'
1+
import { ErrorCodes, NodeTypes } from '@vue/compiler-core'
22
import {
33
IRNodeTypes,
44
transformChildren,
@@ -208,5 +208,26 @@ describe('compiler: transform <slot> outlets', () => {
208208
])
209209
})
210210

211-
test.todo('error on unexpected custom directive on <slot>')
211+
test('error on unexpected custom directive on <slot>', () => {
212+
const onError = vi.fn()
213+
const source = `<slot v-foo />`
214+
const index = source.indexOf('v-foo')
215+
const { code } = compileWithSlotsOutlet(source, { onError })
216+
expect(code).toMatchSnapshot()
217+
expect(onError.mock.calls[0][0]).toMatchObject({
218+
code: ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
219+
loc: {
220+
start: {
221+
offset: index,
222+
line: 1,
223+
column: index + 1,
224+
},
225+
end: {
226+
offset: index + 5,
227+
line: 1,
228+
column: index + 6,
229+
},
230+
},
231+
})
232+
})
212233
})

packages/compiler-vapor/src/transforms/transformSlotOutlet.ts

+24-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import {
2+
type AttributeNode,
3+
type DirectiveNode,
24
type ElementNode,
35
ElementTypes,
6+
ErrorCodes,
47
NodeTypes,
58
type SimpleExpressionNode,
9+
createCompilerError,
610
createSimpleExpression,
711
isStaticArgOf,
812
isStaticExp,
@@ -16,7 +20,7 @@ import {
1620
type IRProps,
1721
type VaporDirectiveNode,
1822
} from '../ir'
19-
import { camelize, extend } from '@vue/shared'
23+
import { camelize, extend, isBuiltInDirective } from '@vue/shared'
2024
import { genDefaultDynamic } from './utils'
2125
import { buildProps } from './transformElement'
2226

@@ -33,7 +37,8 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
3337
)
3438

3539
let name: SimpleExpressionNode | undefined
36-
const nonNameProps = []
40+
const nonNameProps: (AttributeNode | DirectiveNode)[] = []
41+
const customDirectives: DirectiveNode[] = []
3742
for (const p of props) {
3843
if (p.type === NodeTypes.ATTRIBUTE) {
3944
if (p.value) {
@@ -58,13 +63,27 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
5863
name.ast = null
5964
}
6065
} else {
61-
if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {
62-
p.arg.content = camelize(p.arg.content)
66+
if (!isBuiltInDirective(p.name)) {
67+
customDirectives.push(p)
68+
} else {
69+
if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {
70+
p.arg.content = camelize(p.arg.content)
71+
}
72+
nonNameProps.push(p)
6373
}
64-
nonNameProps.push(p)
6574
}
6675
}
6776
}
77+
78+
if (customDirectives.length) {
79+
context.options.onError(
80+
createCompilerError(
81+
ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
82+
customDirectives[0].loc,
83+
),
84+
)
85+
}
86+
6887
name ||= createSimpleExpression('default', true)
6988
let irProps: IRProps[] = []
7089
if (nonNameProps.length > 0) {

0 commit comments

Comments
 (0)