From 65118327ff9f506d241959d96e1e57871a6427d7 Mon Sep 17 00:00:00 2001
From: likui <2218301630@qq.com>
Date: Fri, 29 Nov 2019 04:21:02 +0800
Subject: [PATCH] feat(compiler-sfc): gen source map for style and script block
(#497)
---
packages/compiler-sfc/__tests__/parse.spec.ts | 13 ++++
packages/compiler-sfc/src/parse.ts | 70 ++++++++++++++++++-
2 files changed, 80 insertions(+), 3 deletions(-)
diff --git a/packages/compiler-sfc/__tests__/parse.spec.ts b/packages/compiler-sfc/__tests__/parse.spec.ts
index 0a3cc45770..75ed119686 100644
--- a/packages/compiler-sfc/__tests__/parse.spec.ts
+++ b/packages/compiler-sfc/__tests__/parse.spec.ts
@@ -4,6 +4,19 @@ import { mockWarn } from '@vue/runtime-test'
describe('compiler:sfc', () => {
mockWarn()
+ describe('source map', () => {
+ test('style block', () => {
+ const style = parse(`\n`)
+ .styles[0]
+ expect(style.map).not.toBeUndefined()
+ })
+
+ test('script block', () => {
+ const script = parse(`\n`).script
+ expect(script!.map).not.toBeUndefined()
+ })
+ })
+
test('should ignore nodes with no content', () => {
expect(parse(``).template).toBe(null)
expect(parse(``).script).toBe(null)
diff --git a/packages/compiler-sfc/src/parse.ts b/packages/compiler-sfc/src/parse.ts
index 8ad603e6c2..bb82d8a440 100644
--- a/packages/compiler-sfc/src/parse.ts
+++ b/packages/compiler-sfc/src/parse.ts
@@ -6,7 +6,7 @@ import {
ElementNode,
SourceLocation
} from '@vue/compiler-core'
-import { RawSourceMap } from 'source-map'
+import { RawSourceMap, SourceMapGenerator } from 'source-map'
import LRUCache from 'lru-cache'
import { generateCodeFrame } from '@vue/shared'
@@ -14,6 +14,7 @@ export interface SFCParseOptions {
needMap?: boolean
filename?: string
sourceRoot?: string
+ pad?: 'line' | 'space'
}
export interface SFCBlock {
@@ -56,7 +57,8 @@ export function parse(
{
needMap = true,
filename = 'component.vue',
- sourceRoot = ''
+ sourceRoot = '',
+ pad = 'line'
}: SFCParseOptions = {}
): SFCDescriptor {
const sourceKey = source + needMap + filename + sourceRoot
@@ -109,7 +111,28 @@ export function parse(
})
if (needMap) {
- // TODO source map
+ if (sfc.script && !sfc.script.src) {
+ sfc.script.map = generateSourceMap(
+ filename,
+ source,
+ sfc.script.content,
+ sourceRoot,
+ pad
+ )
+ }
+ if (sfc.styles) {
+ sfc.styles.forEach(style => {
+ if (!style.src) {
+ style.map = generateSourceMap(
+ filename,
+ source,
+ style.content,
+ sourceRoot,
+ pad
+ )
+ }
+ })
+ }
}
sourceToSFC.set(sourceKey, sfc)
@@ -164,3 +187,44 @@ function createBlock(node: ElementNode): SFCBlock {
})
return block
}
+
+const splitRE = /\r?\n/g
+const emptyRE = /^(?:\/\/)?\s*$/
+
+function generateSourceMap(
+ filename: string,
+ source: string,
+ generated: string,
+ sourceRoot: string,
+ pad?: 'line' | 'space'
+): RawSourceMap {
+ const map = new SourceMapGenerator({
+ file: filename.replace(/\\/g, '/'),
+ sourceRoot: sourceRoot.replace(/\\/g, '/')
+ })
+ let offset = 0
+ if (!pad) {
+ offset =
+ source
+ .split(generated)
+ .shift()!
+ .split(splitRE).length - 1
+ }
+ map.setSourceContent(filename, source)
+ generated.split(splitRE).forEach((line, index) => {
+ if (!emptyRE.test(line)) {
+ map.addMapping({
+ source: filename,
+ original: {
+ line: index + 1 + offset,
+ column: 0
+ },
+ generated: {
+ line: index + 1,
+ column: 0
+ }
+ })
+ }
+ })
+ return JSON.parse(map.toString())
+}
--
2.47.3