--- /dev/null
+import { parse } from '../src'
+import { mockWarn } from '@vue/runtime-test'
+
+describe('compiler:sfc', () => {
+ mockWarn()
+ describe('error', () => {
+ test('should only allow single template element', () => {
+ parse(`<template><div/></template><template><div/></template>`)
+ expect(
+ `Single file component can contain only one template element`
+ ).toHaveBeenWarned()
+ })
+
+ test('should only allow single script element', () => {
+ parse(`<script>console.log(1)</script><script>console.log(1)</script>`)
+ expect(
+ `Single file component can contain only one script element`
+ ).toHaveBeenWarned()
+ })
+ })
+})
SourceLocation
} from '@vue/compiler-core'
import { RawSourceMap } from 'source-map'
+import { generateCodeFrame } from '@vue/shared'
export interface SFCParseOptions {
needMap?: boolean
if (!sfc.template) {
sfc.template = createBlock(node) as SFCTemplateBlock
} else {
- // TODO warn duplicate template
+ warnDuplicateBlock(source, filename, node)
}
break
case 'script':
if (!sfc.script) {
sfc.script = createBlock(node) as SFCScriptBlock
} else {
- // TODO warn duplicate script
+ warnDuplicateBlock(source, filename, node)
}
break
case 'style':
return sfc
}
+function warnDuplicateBlock(
+ source: string,
+ filename: string,
+ node: ElementNode
+) {
+ const codeFrame = generateCodeFrame(
+ source,
+ node.loc.start.offset,
+ node.loc.end.offset
+ )
+ const location = `${filename}:${node.loc.start.line}:${node.loc.start.column}`
+ console.warn(
+ `Single file component can contain only one ${
+ node.tag
+ } element (${location}):\n\n${codeFrame}`
+ )
+}
+
function createBlock(node: ElementNode): SFCBlock {
const type = node.tag
const text = node.children[0] as TextNode