Skip to content

Commit

Permalink
fix(compiler-core): warn when slot used on non-root template
Browse files Browse the repository at this point in the history
Implements the warning from vue2 in vue3.

fixes #11521
  • Loading branch information
Disservin committed Aug 15, 2024
1 parent bdfdb9c commit cee2536
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 255 deletions.
214 changes: 0 additions & 214 deletions packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -496,220 +496,6 @@ exports[`compiler: parse > Edge Cases > valid html 1`] = `
}
`;
exports[`compiler: parse > Edge Cases > warn when v-slot used on non-root <template> 1`] = `
{
"cached": 0,
"children": [
{
"children": [
{
"children": [
{
"children": [
{
"content": " Header ",
"loc": {
"end": {
"column": 41,
"line": 4,
"offset": 93,
},
"source": " Header ",
"start": {
"column": 33,
"line": 4,
"offset": 85,
},
},
"type": 2,
},
],
"codegenNode": undefined,
"loc": {
"end": {
"column": 52,
"line": 4,
"offset": 104,
},
"source": "<template #header> Header </template>",
"start": {
"column": 15,
"line": 4,
"offset": 67,
},
},
"ns": 0,
"props": [
{
"arg": {
"constType": 3,
"content": "header",
"isStatic": true,
"loc": {
"end": {
"column": 32,
"line": 4,
"offset": 84,
},
"source": "header",
"start": {
"column": 26,
"line": 4,
"offset": 78,
},
},
"type": 4,
},
"exp": undefined,
"loc": {
"end": {
"column": 32,
"line": 4,
"offset": 84,
},
"source": "#header",
"start": {
"column": 25,
"line": 4,
"offset": 77,
},
},
"modifiers": [],
"name": "slot",
"rawName": "#header",
"type": 7,
},
],
"tag": "template",
"tagType": 3,
"type": 1,
},
],
"codegenNode": undefined,
"loc": {
"end": {
"column": 24,
"line": 5,
"offset": 128,
},
"source": "<template v-if="true">
<template #header> Header </template>
</template>",
"start": {
"column": 13,
"line": 3,
"offset": 30,
},
},
"ns": 0,
"props": [
{
"arg": undefined,
"exp": {
"constType": 0,
"content": "true",
"isStatic": false,
"loc": {
"end": {
"column": 33,
"line": 3,
"offset": 50,
},
"source": "true",
"start": {
"column": 29,
"line": 3,
"offset": 46,
},
},
"type": 4,
},
"loc": {
"end": {
"column": 34,
"line": 3,
"offset": 51,
},
"source": "v-if="true"",
"start": {
"column": 23,
"line": 3,
"offset": 40,
},
},
"modifiers": [],
"name": "if",
"rawName": "v-if",
"type": 7,
},
],
"tag": "template",
"tagType": 3,
"type": 1,
},
],
"codegenNode": undefined,
"loc": {
"end": {
"column": 18,
"line": 6,
"offset": 146,
},
"source": "<Comp>
<template v-if="true">
<template #header> Header </template>
</template>
</Comp>",
"start": {
"column": 11,
"line": 2,
"offset": 11,
},
},
"ns": 0,
"props": [],
"tag": "Comp",
"tagType": 1,
"type": 1,
},
],
"codegenNode": undefined,
"components": [],
"directives": [],
"helpers": Set {},
"hoists": [],
"imports": [],
"loc": {
"end": {
"column": 11,
"line": 7,
"offset": 157,
},
"source": "
<Comp>
<template v-if="true">
<template #header> Header </template>
</template>
</Comp>
",
"start": {
"column": 1,
"line": 1,
"offset": 0,
},
},
"source": "
<Comp>
<template v-if="true">
<template #header> Header </template>
</template>
</Comp>
",
"temps": 0,
"type": 0,
}
`;
exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[cdata]]></template> 1`] = `
{
"cached": 0,
Expand Down
36 changes: 0 additions & 36 deletions packages/compiler-core/__tests__/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1992,42 +1992,6 @@ describe('compiler: parse', () => {
expect(ast).toMatchSnapshot()
})

test('warn when v-slot used on non-root <template>', () => {
const source = `
<Comp>
<template v-if="true">
<template #header> Header </template>
</template>
</Comp>
`

expect(() => {
baseParse(source)
}).toThrow(
'<template v-slot> can only appear at the root level inside the receiving component',
)

const spy = vi.fn()
const ast = baseParse(source, {
onError: spy,
})

expect(spy.mock.calls).toMatchObject([
[
{
code: ErrorCodes.X_TEMPLATE_NOT_ROOT,
loc: {
start: { column: 15, line: 4, offset: 67 },
end: { column: 15, line: 4, offset: 67 },
source: '',
},
},
],
])

expect(ast).toMatchSnapshot()
})

test('parse with correct location info', () => {
const fooSrc = `foo\n is `
const barSrc = `{{ bar }}`
Expand Down
72 changes: 72 additions & 0 deletions packages/compiler-core/__tests__/transform.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { transformElement } from '../src/transforms/transformElement'
import { transformSlotOutlet } from '../src/transforms/transformSlotOutlet'
import { transformText } from '../src/transforms/transformText'
import { PatchFlags } from '@vue/shared'
import type { CompilerOptions } from '@vue/compiler-core'

describe('compiler: transform', () => {
test('context state', () => {
Expand Down Expand Up @@ -378,4 +379,75 @@ describe('compiler: transform', () => {
)
})
})

describe('errors', () => {
function transformWithCodegen(
template: string,
options: CompilerOptions = {},
) {
const ast = baseParse(template)
transform(ast, {
nodeTransforms: [
transformIf,
transformFor,
transformText,
transformSlotOutlet,
transformElement,
],
...options,
})
return ast
}

test('warn when v-slot used on non-root level <template>', () => {
const onError = vi.fn()

const ast = transformWithCodegen(
`
<template>
<Bar>
<template>
<template #header> Header </template>
</template>
</Bar>
</template>`,
{ onError },
)

expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_TEMPLATE_NOT_ROOT,
loc: (ast.children[0] as any).children[0].children[0].children[0].loc,
},
])
})

test('dont warn when v-slot used on root level <template>', () => {
const onError = vi.fn()

transformWithCodegen(
`<template>
<bar>
<template #header> Header </template>
</bar>
</template>`,
{ onError },
)

expect(onError.mock.calls).toEqual([])

Check failure on line 437 in packages/compiler-core/__tests__/transform.spec.ts

View workflow job for this annotation

GitHub Actions / test / unit-test

packages/compiler-core/__tests__/transform.spec.ts > compiler: transform > errors > dont warn when v-slot used on root level <template>

AssertionError: expected [ [ …(1) ], [ …(1) ] ] to deeply equal [] - Expected + Received - Array [] + Array [ + Array [ + [SyntaxError: <template v-slot> can only appear at the root level inside the receiving component], + ], + Array [ + [SyntaxError: <template v-slot> can only appear at the root level inside the receiving component], + ], + ] ❯ packages/compiler-core/__tests__/transform.spec.ts:437:34

Check failure on line 437 in packages/compiler-core/__tests__/transform.spec.ts

View workflow job for this annotation

GitHub Actions / test / unit-test-windows

packages/compiler-core/__tests__/transform.spec.ts > compiler: transform > errors > dont warn when v-slot used on root level <template>

AssertionError: expected [ [ …(1) ], [ …(1) ] ] to deeply equal [] - Expected + Received - Array [] + Array [ + Array [ + [SyntaxError: <template v-slot> can only appear at the root level inside the receiving component], + ], + Array [ + [SyntaxError: <template v-slot> can only appear at the root level inside the receiving component], + ], + ] ❯ packages/compiler-core/__tests__/transform.spec.ts:437:34
})

test('dont warn when v-slot used on root level <template> inside custom component', () => {
const onError = vi.fn()

transformWithCodegen(
`<template>
<div is="vue:customComp"><template v-slot="slotProps"></template></div>
</template>`,
{ onError },
)

expect(onError.mock.calls).toEqual([])
})
})
})
2 changes: 1 addition & 1 deletion packages/compiler-core/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export enum ErrorCodes {
X_MISSING_INTERPOLATION_END,
X_MISSING_DIRECTIVE_NAME,
X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END,
X_TEMPLATE_NOT_ROOT,

// transform errors
X_V_IF_NO_EXPRESSION,
Expand All @@ -91,6 +90,7 @@ export enum ErrorCodes {
X_V_MODEL_ON_PROPS,
X_INVALID_EXPRESSION,
X_KEEP_ALIVE_INVALID_CHILDREN,
X_TEMPLATE_NOT_ROOT,

// generic errors
X_PREFIX_ID_NOT_SUPPORTED,
Expand Down
3 changes: 0 additions & 3 deletions packages/compiler-core/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -759,9 +759,6 @@ function isFragmentTemplate(
props[i].type === NodeTypes.DIRECTIVE &&
specialTemplateDir.has((props[i] as DirectiveNode).name)
) {
if (props[i].name === 'slot' && parent && !isComponent(parent)) {
emitError(ErrorCodes.X_TEMPLATE_NOT_ROOT, loc.start.offset)
}
return true
}
}
Expand Down
Loading

0 comments on commit cee2536

Please sign in to comment.