diff --git a/packages/compiler-sfc/__tests__/compileScript.spec.ts b/packages/compiler-sfc/__tests__/compileScript.spec.ts index 11b5661c16c..73c6d316a40 100644 --- a/packages/compiler-sfc/__tests__/compileScript.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript.spec.ts @@ -1,5 +1,11 @@ import { BindingTypes } from '@vue/compiler-core' -import { assertCode, compileSFCScript as compile, mockId } from './utils' +import { + assertCode, + compileSFCScript as compile, + getPositionInCode, + mockId, +} from './utils' +import { type RawSourceMap, SourceMapConsumer } from 'source-map-js' describe('SFC compile + + ` + const { content, map } = compile(source, { inlineTemplate: true }) + expect(map).not.toBeUndefined() + const consumer = new SourceMapConsumer(map as RawSourceMap) + expect( + consumer.originalPositionFor(getPositionInCode(content, 'count')), + ).toMatchObject(getPositionInCode(source, `count`)) + expect( + consumer.originalPositionFor(getPositionInCode(content, 'Error')), + ).toMatchObject(getPositionInCode(source, `Error`)) + }) }) describe('with TypeScript', () => { diff --git a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts index 2ea1eb9d378..d4ddc763812 100644 --- a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts +++ b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts @@ -6,6 +6,7 @@ import { } from '../src/compileTemplate' import { type SFCTemplateBlock, parse } from '../src/parse' import { compileScript } from '../src' +import { getPositionInCode } from './utils' function compile(opts: Omit) { return compileTemplate({ @@ -482,36 +483,3 @@ test('non-identifier expression in legacy filter syntax', () => { babelParse(compilationResult.code, { sourceType: 'module' }) }).not.toThrow() }) - -interface Pos { - line: number - column: number - name?: string -} - -function getPositionInCode( - code: string, - token: string, - expectName: string | boolean = false, -): Pos { - const generatedOffset = code.indexOf(token) - let line = 1 - let lastNewLinePos = -1 - for (let i = 0; i < generatedOffset; i++) { - if (code.charCodeAt(i) === 10 /* newline char code */) { - line++ - lastNewLinePos = i - } - } - const res: Pos = { - line, - column: - lastNewLinePos === -1 - ? generatedOffset - : generatedOffset - lastNewLinePos - 1, - } - if (expectName) { - res.name = typeof expectName === 'string' ? expectName : token - } - return res -} diff --git a/packages/compiler-sfc/__tests__/utils.ts b/packages/compiler-sfc/__tests__/utils.ts index 5a58a6b58ae..b5cfc9606d5 100644 --- a/packages/compiler-sfc/__tests__/utils.ts +++ b/packages/compiler-sfc/__tests__/utils.ts @@ -40,3 +40,36 @@ export function assertCode(code: string): void { } expect(code).toMatchSnapshot() } + +interface Pos { + line: number + column: number + name?: string +} + +export function getPositionInCode( + code: string, + token: string, + expectName: string | boolean = false, +): Pos { + const generatedOffset = code.indexOf(token) + let line = 1 + let lastNewLinePos = -1 + for (let i = 0; i < generatedOffset; i++) { + if (code.charCodeAt(i) === 10 /* newline char code */) { + line++ + lastNewLinePos = i + } + } + const res: Pos = { + line, + column: + lastNewLinePos === -1 + ? generatedOffset + : generatedOffset - lastNewLinePos - 1, + } + if (expectName) { + res.name = typeof expectName === 'string' ? expectName : token + } + return res +} diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index 8098b43ce45..67af92df5e7 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -23,7 +23,11 @@ import type { Statement, } from '@babel/types' import { walk } from 'estree-walker' -import type { RawSourceMap } from 'source-map-js' +import { + type RawSourceMap, + SourceMapConsumer, + SourceMapGenerator, +} from 'source-map-js' import { normalScriptDefaultVar, processNormalScript, @@ -32,7 +36,6 @@ import { CSS_VARS_HELPER, genCssVarsCode } from './style/cssVars' import { type SFCTemplateCompileOptions, compileTemplate, - mergeSourceMaps, } from './compileTemplate' import { warnOnce } from './warn' import { transformDestructuredProps } from './script/definePropsDestructure' @@ -1034,10 +1037,12 @@ export function compileScript( includeContent: true, }) as unknown as RawSourceMap) : undefined - if (map && templateMap) { + // merge source maps of the script setup and template in inline mode + if (templateMap && map) { const offset = content.indexOf(returned) - const lineOffset = content.slice(0, offset).split(/\r?\n/).length - 1 - map = mergeSourceMaps(map, templateMap, lineOffset) + const templateLineOffset = + content.slice(0, offset).split(/\r?\n/).length - 1 + map = mergeSourceMaps(map, templateMap, templateLineOffset) } return { ...scriptSetup, @@ -1301,3 +1306,42 @@ function isStaticNode(node: Node): boolean { } return false } + +export function mergeSourceMaps( + scriptMap: RawSourceMap, + templateMap: RawSourceMap, + templateLineOffset: number, +): RawSourceMap { + const generator = new SourceMapGenerator() + const addMapping = (map: RawSourceMap, lineOffset = 0) => { + const consumer = new SourceMapConsumer(map) + ;(consumer as any).sources.forEach((sourceFile: string) => { + ;(generator as any)._sources.add(sourceFile) + const sourceContent = consumer.sourceContentFor(sourceFile) + if (sourceContent != null) { + generator.setSourceContent(sourceFile, sourceContent) + } + }) + consumer.eachMapping(m => { + if (m.originalLine == null) return + generator.addMapping({ + generated: { + line: m.generatedLine + lineOffset, + column: m.generatedColumn, + }, + original: { + line: m.originalLine, + column: m.originalColumn, + }, + source: m.source, + name: m.name, + }) + }) + } + + addMapping(scriptMap) + addMapping(templateMap, templateLineOffset) + ;(generator as any)._sourceRoot = scriptMap.sourceRoot + ;(generator as any)._file = scriptMap.file + return (generator as any).toJSON() +} diff --git a/packages/compiler-sfc/src/compileTemplate.ts b/packages/compiler-sfc/src/compileTemplate.ts index 7c1d63ea1cb..322b1570e1a 100644 --- a/packages/compiler-sfc/src/compileTemplate.ts +++ b/packages/compiler-sfc/src/compileTemplate.ts @@ -327,51 +327,6 @@ function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap { return generator.toJSON() } -export function mergeSourceMaps( - scriptMap: RawSourceMap, - templateMap: RawSourceMap, - templateLineOffset: number, -): RawSourceMap { - if (!templateMap) return scriptMap - if (!scriptMap) return templateMap - - const mergedMapGenerator = new SourceMapGenerator() as any - const scriptConsumer = new SourceMapConsumer(scriptMap) - scriptConsumer.eachMapping(mapping => { - if (mapping.originalLine == null) return - mergedMapGenerator.addMapping({ - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn, - }, - original: { - line: mapping.originalLine, - column: mapping.originalColumn, - }, - source: mapping.source, - name: mapping.name, - }) - }) - - const templateConsumer = new SourceMapConsumer(templateMap) - templateConsumer.eachMapping(mapping => { - if (mapping.originalLine == null) return - mergedMapGenerator.addMapping({ - generated: { - line: mapping.generatedLine + templateLineOffset, - column: mapping.generatedColumn, - }, - original: { - line: mapping.originalLine, - column: mapping.originalColumn, - }, - source: mapping.source, - name: mapping.name, - }) - }) - return mergedMapGenerator.toJSON() -} - function patchErrors( errors: CompilerError[], source: string,