|
|
@@ -7,6 +7,7 @@ import {
|
|
|
SourceLocation
|
|
|
} from '@vue/compiler-core'
|
|
|
import { RawSourceMap } from 'source-map'
|
|
|
+import { generateCodeFrame } from '@vue/shared'
|
|
|
|
|
|
export interface SFCParseOptions {
|
|
|
needMap?: boolean
|
|
|
@@ -78,14 +79,14 @@ export function parse(
|
|
|
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':
|
|
|
@@ -105,6 +106,24 @@ export function parse(
|
|
|
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
|