feat(sfc): accept inMap in compileTemplate()
This commit is contained in:
parent
02c6d5c4e3
commit
3a3a24d621
@ -145,7 +145,7 @@ export const errorMessages: { [code: number]: string } = {
|
||||
|
||||
// Vue-specific parse errors
|
||||
[ErrorCodes.X_INVALID_END_TAG]: 'Invalid end tag.',
|
||||
[ErrorCodes.X_MISSING_END_TAG]: 'End tag was not found.',
|
||||
[ErrorCodes.X_MISSING_END_TAG]: 'Element is missing end tag.',
|
||||
[ErrorCodes.X_MISSING_INTERPOLATION_END]:
|
||||
'Interpolation end sign was not found.',
|
||||
[ErrorCodes.X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END]:
|
||||
|
@ -372,7 +372,7 @@ function parseElement(
|
||||
if (startsWithEndTagOpen(context.source, element.tag)) {
|
||||
parseTag(context, TagType.End, parent)
|
||||
} else {
|
||||
emitError(context, ErrorCodes.X_MISSING_END_TAG)
|
||||
emitError(context, ErrorCodes.X_MISSING_END_TAG, 0, element.loc.start)
|
||||
if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {
|
||||
const first = children[0]
|
||||
if (first && startsWith(first.loc.source, '<!--')) {
|
||||
@ -963,9 +963,9 @@ function getNewPosition(
|
||||
function emitError(
|
||||
context: ParserContext,
|
||||
code: ErrorCodes,
|
||||
offset?: number
|
||||
offset?: number,
|
||||
loc: Position = getCursor(context)
|
||||
): void {
|
||||
const loc = getCursor(context)
|
||||
if (offset) {
|
||||
loc.offset += offset
|
||||
loc.column += offset
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
CompilerError,
|
||||
NodeTransform
|
||||
} from '@vue/compiler-core'
|
||||
import { RawSourceMap } from 'source-map'
|
||||
import { SourceMapConsumer, SourceMapGenerator, RawSourceMap } from 'source-map'
|
||||
import {
|
||||
transformAssetUrl,
|
||||
AssetURLOptions,
|
||||
@ -29,6 +29,7 @@ export interface SFCTemplateCompileResults {
|
||||
export interface SFCTemplateCompileOptions {
|
||||
source: string
|
||||
filename: string
|
||||
inMap?: RawSourceMap
|
||||
compiler?: TemplateCompiler
|
||||
compilerOptions?: CompilerOptions
|
||||
preprocessLang?: string
|
||||
@ -100,6 +101,7 @@ export function compileTemplate(
|
||||
|
||||
function doCompileTemplate({
|
||||
filename,
|
||||
inMap,
|
||||
source,
|
||||
compiler = require('@vue/compiler-dom'),
|
||||
compilerOptions = {},
|
||||
@ -117,7 +119,7 @@ function doCompileTemplate({
|
||||
nodeTransforms = [transformAssetUrl, transformSrcset]
|
||||
}
|
||||
|
||||
const { code, map } = compiler.compile(source, {
|
||||
let { code, map } = compiler.compile(source, {
|
||||
mode: 'module',
|
||||
prefixIdentifiers: true,
|
||||
hoistStatic: true,
|
||||
@ -128,5 +130,91 @@ function doCompileTemplate({
|
||||
sourceMap: true,
|
||||
onError: e => errors.push(e)
|
||||
})
|
||||
|
||||
// inMap should be the map produced by ./parse.ts which is a simple line-only
|
||||
// mapping. If it is present, we need to adjust the final map and errors to
|
||||
// reflect the original line numbers.
|
||||
if (inMap) {
|
||||
if (map) {
|
||||
map = mapLines(inMap, map)
|
||||
}
|
||||
if (errors.length) {
|
||||
patchErrors(errors, source, inMap)
|
||||
}
|
||||
}
|
||||
|
||||
return { code, source, errors, tips: [], map }
|
||||
}
|
||||
|
||||
function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap {
|
||||
if (!oldMap) return newMap
|
||||
if (!newMap) return oldMap
|
||||
|
||||
const oldMapConsumer = new SourceMapConsumer(oldMap)
|
||||
const newMapConsumer = new SourceMapConsumer(newMap)
|
||||
const mergedMapGenerator = new SourceMapGenerator()
|
||||
|
||||
newMapConsumer.eachMapping(m => {
|
||||
if (m.originalLine == null) {
|
||||
return
|
||||
}
|
||||
|
||||
const origPosInOldMap = oldMapConsumer.originalPositionFor({
|
||||
line: m.originalLine,
|
||||
column: m.originalColumn
|
||||
})
|
||||
|
||||
if (origPosInOldMap.source == null) {
|
||||
return
|
||||
}
|
||||
|
||||
mergedMapGenerator.addMapping({
|
||||
generated: {
|
||||
line: m.generatedLine,
|
||||
column: m.generatedColumn
|
||||
},
|
||||
original: {
|
||||
line: origPosInOldMap.line, // map line
|
||||
// use current column, since the oldMap produced by @vue/compiler-sfc
|
||||
// does not
|
||||
column: m.originalColumn
|
||||
},
|
||||
source: origPosInOldMap.source,
|
||||
name: origPosInOldMap.name
|
||||
})
|
||||
})
|
||||
|
||||
// source-map's type definition is incomplete
|
||||
const generator = mergedMapGenerator as any
|
||||
;(oldMapConsumer as any).sources.forEach((sourceFile: string) => {
|
||||
generator._sources.add(sourceFile)
|
||||
const sourceContent = oldMapConsumer.sourceContentFor(sourceFile)
|
||||
if (sourceContent != null) {
|
||||
mergedMapGenerator.setSourceContent(sourceFile, sourceContent)
|
||||
}
|
||||
})
|
||||
|
||||
generator._sourceRoot = oldMap.sourceRoot
|
||||
generator._file = oldMap.file
|
||||
return generator.toJSON()
|
||||
}
|
||||
|
||||
function patchErrors(
|
||||
errors: CompilerError[],
|
||||
source: string,
|
||||
inMap: RawSourceMap
|
||||
) {
|
||||
const originalSource = inMap.sourcesContent![0]
|
||||
const offset = originalSource.indexOf(source)
|
||||
const lineOffset = originalSource.slice(0, offset).split(/\r?\n/).length - 1
|
||||
errors.forEach(err => {
|
||||
if (err.loc) {
|
||||
err.loc.start.line += lineOffset
|
||||
err.loc.start.offset += offset
|
||||
if (err.loc.end !== err.loc.start) {
|
||||
err.loc.end.line += lineOffset
|
||||
err.loc.end.offset += offset
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user