|
8 | 8 | } from '@vue/compiler-core'
|
9 | 9 | import * as CompilerDOM from '@vue/compiler-dom'
|
10 | 10 | import { RawSourceMap, SourceMapGenerator } from 'source-map'
|
11 |
| -import { generateCodeFrame } from '@vue/shared' |
12 | 11 | import { TemplateCompiler } from './compileTemplate'
|
13 | 12 | import { compileScript, SFCScriptCompileOptions } from './compileScript'
|
14 | 13 |
|
@@ -61,7 +60,7 @@ export interface SFCDescriptor {
|
61 | 60 |
|
62 | 61 | export interface SFCParseResult {
|
63 | 62 | descriptor: SFCDescriptor
|
64 |
| - errors: CompilerError[] |
| 63 | + errors: (CompilerError | SyntaxError)[] |
65 | 64 | }
|
66 | 65 |
|
67 | 66 | const SFC_CACHE_MAX_SIZE = 500
|
@@ -102,7 +101,7 @@ export function parse(
|
102 | 101 | customBlocks: []
|
103 | 102 | }
|
104 | 103 |
|
105 |
| - const errors: CompilerError[] = [] |
| 104 | + const errors: (CompilerError | SyntaxError)[] = [] |
106 | 105 | const ast = compiler.parse(source, {
|
107 | 106 | // there are no components at SFC parsing level
|
108 | 107 | isNativeTag: () => true,
|
@@ -148,21 +147,30 @@ export function parse(
|
148 | 147 | false
|
149 | 148 | ) as SFCTemplateBlock
|
150 | 149 | } else {
|
151 |
| - warnDuplicateBlock(source, filename, node) |
| 150 | + errors.push(createDuplicateBlockError(node)) |
152 | 151 | }
|
153 | 152 | break
|
154 | 153 | case 'script':
|
155 | 154 | const block = createBlock(node, source, pad) as SFCScriptBlock
|
156 | 155 | const isSetup = !!block.attrs.setup
|
157 | 156 | if (isSetup && !descriptor.scriptSetup) {
|
| 157 | + if (block.src) { |
| 158 | + errors.push( |
| 159 | + new SyntaxError( |
| 160 | + `<script setup> cannot be used with the "src" attribute since ` + |
| 161 | + `its syntax will be ambiguous outside of the component.` |
| 162 | + ) |
| 163 | + ) |
| 164 | + break |
| 165 | + } |
158 | 166 | descriptor.scriptSetup = block
|
159 | 167 | break
|
160 | 168 | }
|
161 | 169 | if (!isSetup && !descriptor.script) {
|
162 | 170 | descriptor.script = block
|
163 | 171 | break
|
164 | 172 | }
|
165 |
| - warnDuplicateBlock(source, filename, node, isSetup) |
| 173 | + errors.push(createDuplicateBlockError(node, isSetup)) |
166 | 174 | break
|
167 | 175 | case 'style':
|
168 | 176 | descriptor.styles.push(createBlock(node, source, pad) as SFCStyleBlock)
|
@@ -208,23 +216,17 @@ export function parse(
|
208 | 216 | return result
|
209 | 217 | }
|
210 | 218 |
|
211 |
| -function warnDuplicateBlock( |
212 |
| - source: string, |
213 |
| - filename: string, |
| 219 | +function createDuplicateBlockError( |
214 | 220 | node: ElementNode,
|
215 | 221 | isScriptSetup = false
|
216 |
| -) { |
217 |
| - const codeFrame = generateCodeFrame( |
218 |
| - source, |
219 |
| - node.loc.start.offset, |
220 |
| - node.loc.end.offset |
221 |
| - ) |
222 |
| - const location = `${filename}:${node.loc.start.line}:${node.loc.start.column}` |
223 |
| - console.warn( |
| 222 | +): CompilerError { |
| 223 | + const err = new SyntaxError( |
224 | 224 | `Single file component can contain only one <${node.tag}${
|
225 | 225 | isScriptSetup ? ` setup` : ``
|
226 |
| - }> element (${location}):\n\n${codeFrame}` |
227 |
| - ) |
| 226 | + }> element` |
| 227 | + ) as CompilerError |
| 228 | + err.loc = node.loc |
| 229 | + return err |
228 | 230 | }
|
229 | 231 |
|
230 | 232 | function createBlock(
|
|
0 commit comments