mirror of https://github.com/vuejs/core.git
Merge 9759be0451
into 56be3dd4db
This commit is contained in:
commit
ba95fdca8d
|
@ -3453,4 +3453,96 @@ describe('compiler: parse', () => {
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('vue specific errors', () => {
|
||||
test('error when v-slot used on non-root level <template>', () => {
|
||||
const onError = vi.fn()
|
||||
|
||||
baseParse(
|
||||
`<Bar><template><template #header> Header </template></template></Bar>`,
|
||||
{ onError },
|
||||
)
|
||||
|
||||
expect(onError.mock.calls[0]).toMatchObject([
|
||||
{
|
||||
code: ErrorCodes.X_SLOT_TEMPLATE_NOT_ROOT,
|
||||
loc: {
|
||||
start: { column: 16, line: 1, offset: 15 },
|
||||
end: { column: 53, line: 1, offset: 52 },
|
||||
source: '<template #header> Header </template>',
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('error when v-slot used on non-root level <template> with v-if', () => {
|
||||
const onError = vi.fn()
|
||||
|
||||
baseParse(
|
||||
`<Bar><template v-if="true"><template #header> Header </template></template></Bar>`,
|
||||
{ onError },
|
||||
)
|
||||
|
||||
expect(onError.mock.calls[0]).toMatchObject([
|
||||
{
|
||||
code: ErrorCodes.X_SLOT_TEMPLATE_NOT_ROOT,
|
||||
loc: {
|
||||
start: { column: 28, line: 1, offset: 27 },
|
||||
end: { column: 65, line: 1, offset: 64 },
|
||||
source: '<template #header> Header </template>',
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('error when v-slot used on non-root level <template> together with v-if', () => {
|
||||
const onError = vi.fn()
|
||||
|
||||
baseParse(
|
||||
` <div><template v-if="true"><template v-if="true" #item> Header </template></template></div>`,
|
||||
{ onError },
|
||||
)
|
||||
|
||||
expect(onError.mock.calls[0]).toMatchObject([
|
||||
{
|
||||
code: ErrorCodes.X_SLOT_TEMPLATE_NOT_ROOT,
|
||||
loc: {
|
||||
start: { column: 30, line: 1, offset: 29 },
|
||||
end: { column: 77, line: 1, offset: 76 },
|
||||
source: '<template v-if="true" #item> Header </template>',
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('error when v-slot used on non-root level <template> inside dynamic component', () => {
|
||||
const onError = vi.fn()
|
||||
|
||||
baseParse(
|
||||
`<component is="MyComp"><template><template #item>bar</template></template></component>`,
|
||||
{ onError },
|
||||
)
|
||||
|
||||
expect(onError.mock.calls[0]).toMatchObject([
|
||||
{
|
||||
code: ErrorCodes.X_SLOT_TEMPLATE_NOT_ROOT,
|
||||
loc: {
|
||||
start: { column: 34, line: 1, offset: 33 },
|
||||
end: { column: 64, line: 1, offset: 63 },
|
||||
source: '<template #item>bar</template>',
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('shouldnt error when v-slot used on non-root level <template> inside dynamic component with casting', () => {
|
||||
const onError = vi.fn()
|
||||
|
||||
baseParse(`<div is="vue:MyComp"><template #item>bar</template></div>`, {
|
||||
onError,
|
||||
})
|
||||
|
||||
expect(onError.mock.calls[0]).toEqual(undefined)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -69,6 +69,7 @@ export enum ErrorCodes {
|
|||
X_MISSING_INTERPOLATION_END,
|
||||
X_MISSING_DIRECTIVE_NAME,
|
||||
X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END,
|
||||
X_SLOT_TEMPLATE_NOT_ROOT,
|
||||
|
||||
// transform errors
|
||||
X_V_IF_NO_EXPRESSION,
|
||||
|
@ -151,6 +152,9 @@ export const errorMessages: Record<ErrorCodes, string> = {
|
|||
'End bracket for dynamic directive argument was not found. ' +
|
||||
'Note that dynamic directive argument cannot contain spaces.',
|
||||
[ErrorCodes.X_MISSING_DIRECTIVE_NAME]: 'Legal directive name was expected.',
|
||||
[ErrorCodes.X_SLOT_TEMPLATE_NOT_ROOT]:
|
||||
`<template v-slot> can only appear at the root level inside ` +
|
||||
`the receiving component`,
|
||||
|
||||
// transform errors
|
||||
[ErrorCodes.X_V_IF_NO_EXPRESSION]: `v-if/v-else-if is missing expression.`,
|
||||
|
|
|
@ -763,13 +763,26 @@ function backTrack(index: number, c: number) {
|
|||
}
|
||||
|
||||
const specialTemplateDir = new Set(['if', 'else', 'else-if', 'for', 'slot'])
|
||||
function isFragmentTemplate({ tag, props }: ElementNode): boolean {
|
||||
function isFragmentTemplate({ tag, props, loc }: ElementNode): boolean {
|
||||
if (tag === 'template') {
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
if (
|
||||
props[i].type === NodeTypes.DIRECTIVE &&
|
||||
specialTemplateDir.has((props[i] as DirectiveNode).name)
|
||||
) {
|
||||
if (
|
||||
stack[0] &&
|
||||
'tagType' in stack[0] &&
|
||||
!isComponent(stack[0]) &&
|
||||
props.find(p => p.name === 'slot')
|
||||
) {
|
||||
currentOptions.onError(
|
||||
createCompilerError(
|
||||
ErrorCodes.X_SLOT_TEMPLATE_NOT_ROOT,
|
||||
getLoc(loc.start.offset, loc.end.offset),
|
||||
),
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export function createDOMCompilerError(
|
|||
}
|
||||
|
||||
export enum DOMErrorCodes {
|
||||
X_V_HTML_NO_EXPRESSION = 53 /* ErrorCodes.__EXTEND_POINT__ */,
|
||||
X_V_HTML_NO_EXPRESSION = 54 /* ErrorCodes.__EXTEND_POINT__ */,
|
||||
X_V_HTML_WITH_CHILDREN,
|
||||
X_V_TEXT_NO_EXPRESSION,
|
||||
X_V_TEXT_WITH_CHILDREN,
|
||||
|
|
Loading…
Reference in New Issue