Skip to content

Commit f0a9e3d

Browse files
committed
test padding and source map for sfc-parser
1 parent 77151dc commit f0a9e3d

File tree

3 files changed

+63
-12
lines changed

3 files changed

+63
-12
lines changed

flow/compiler.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ declare type SFCBlock = {
153153
content: string,
154154
start?: number,
155155
end?: number,
156+
offset?: number,
156157
lang?: string,
157158
src?: string,
158159
scoped?: boolean,

src/compiler/parser/sfc-parser.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type Attribute = {
2222
*/
2323
export function parseComponent (
2424
content: string,
25-
options?: Object
25+
options?: Object = {}
2626
): SFCDescriptor {
2727
const sfc: SFCDescriptor = {
2828
template: null,
@@ -68,8 +68,8 @@ export function parseComponent (
6868

6969
function end () {
7070
depth--
71-
if (currentBlock && options && options.map) {
72-
addSourceMap(currentBlock, options.map)
71+
if (options.map && currentBlock && !currentBlock.src) {
72+
addSourceMap(currentBlock)
7373
}
7474
currentBlock = null
7575
}
@@ -81,34 +81,38 @@ export function parseComponent (
8181
text = deindent(text)
8282
// pad content so that linters and pre-processors can output correct
8383
// line numbers in errors and warnings
84-
if (currentBlock.type !== 'template' && options && options.pad) {
84+
if (currentBlock.type !== 'template' && options.pad) {
8585
text = padContent(currentBlock) + text
8686
}
8787
currentBlock.content = text
8888
}
8989
}
9090

9191
function padContent (block: SFCBlock) {
92-
const leadingContent = content.slice(0, block.start)
9392
const padChar = block.type === 'script' && !block.lang
9493
? '//\n'
9594
: '\n'
96-
return Array(leadingContent.split(splitRE).length).join(padChar)
95+
return Array(getPaddingOffset(block) + 1).join(padChar)
9796
}
9897

99-
function addSourceMap (block: SFCBlock, options: Object) {
100-
const filename = options.filename
98+
function getPaddingOffset (block: SFCBlock) {
99+
return content.slice(0, block.start).split(splitRE).length - 1
100+
}
101+
102+
function addSourceMap (block: SFCBlock) {
103+
const filename = options.map.filename
101104
if (!filename) {
102105
throw new Error('Should provide original filename in the map option.')
103106
}
107+
const offset = options.pad ? 0 : getPaddingOffset(block)
104108
const map = new SourceMapGenerator()
105109
map.setSourceContent(filename, content)
106110
block.content.split(splitRE).forEach((line, index) => {
107111
if (!emptyRE.test(line)) {
108112
map.addMapping({
109113
source: filename,
110114
original: {
111-
line: index + 1,
115+
line: index + 1 + offset,
112116
column: 0
113117
},
114118
generated: {

test/unit/modules/compiler/sfc-parser.spec.js

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { parseSFC } from 'compiler/parser/sfc-parser'
1+
import { parseComponent } from 'compiler/parser/sfc-parser'
2+
import { SourceMapConsumer } from 'source-map'
23

3-
describe('SFC parser', () => {
4+
describe('Single File Component parser', () => {
45
it('should parse', () => {
5-
const res = parseSFC(`
6+
const res = parseComponent(`
67
<template>
78
<div>hi</div>
89
</template>
@@ -28,4 +29,49 @@ describe('SFC parser', () => {
2829
expect(res.styles[1].content.trim()).toBe('h1\n color red\nh2\n color green')
2930
expect(res.script.content.trim()).toBe('export default {}')
3031
})
32+
33+
it('pad content', () => {
34+
const res = parseComponent(`
35+
<template>
36+
<div></div>
37+
</template>
38+
<script>
39+
export default {}
40+
</script>
41+
<style>
42+
h1 { color: red }
43+
</style>
44+
`.trim(), { pad: true })
45+
expect(res.script.content).toBe(Array(3 + 1).join('//\n') + '\nexport default {}\n')
46+
expect(res.styles[0].content).toBe(Array(6 + 1).join('\n') + '\nh1 { color: red }\n')
47+
})
48+
49+
it('source map', () => {
50+
const res = parseComponent(`
51+
<script>
52+
export default {}
53+
</script>
54+
<style>
55+
h1 { color: red }
56+
</style>
57+
`.trim(), {
58+
pad: true,
59+
map: {
60+
filename: 'test.vue'
61+
}
62+
})
63+
const scriptConsumer = new SourceMapConsumer(res.script.map)
64+
const scriptPos = scriptConsumer.originalPositionFor({
65+
line: 2,
66+
column: 1
67+
})
68+
expect(scriptPos.line).toBe(2)
69+
70+
const styleConsumer = new SourceMapConsumer(res.styles[0].map)
71+
const stylePos = styleConsumer.originalPositionFor({
72+
line: 5,
73+
column: 1
74+
})
75+
expect(stylePos.line).toBe(5)
76+
})
3177
})

0 commit comments

Comments
 (0)