Просмотр исходного кода

test padding and source map for sfc-parser

Evan You 10 лет назад
Родитель
Сommit
f0a9e3d0f0
3 измененных файлов с 63 добавлено и 12 удалено
  1. 1 0
      flow/compiler.js
  2. 13 9
      src/compiler/parser/sfc-parser.js
  3. 49 3
      test/unit/modules/compiler/sfc-parser.spec.js

+ 1 - 0
flow/compiler.js

@@ -153,6 +153,7 @@ declare type SFCBlock = {
   content: string,
   start?: number,
   end?: number,
+  offset?: number,
   lang?: string,
   src?: string,
   scoped?: boolean,

+ 13 - 9
src/compiler/parser/sfc-parser.js

@@ -22,7 +22,7 @@ type Attribute = {
  */
 export function parseComponent (
   content: string,
-  options?: Object
+  options?: Object = {}
  ): SFCDescriptor {
   const sfc: SFCDescriptor = {
     template: null,
@@ -68,8 +68,8 @@ export function parseComponent (
 
   function end () {
     depth--
-    if (currentBlock && options && options.map) {
-      addSourceMap(currentBlock, options.map)
+    if (options.map && currentBlock && !currentBlock.src) {
+      addSourceMap(currentBlock)
     }
     currentBlock = null
   }
@@ -81,7 +81,7 @@ export function parseComponent (
       text = deindent(text)
       // pad content so that linters and pre-processors can output correct
       // line numbers in errors and warnings
-      if (currentBlock.type !== 'template' && options && options.pad) {
+      if (currentBlock.type !== 'template' && options.pad) {
         text = padContent(currentBlock) + text
       }
       currentBlock.content = text
@@ -89,18 +89,22 @@ export function parseComponent (
   }
 
   function padContent (block: SFCBlock) {
-    const leadingContent = content.slice(0, block.start)
     const padChar = block.type === 'script' && !block.lang
       ? '//\n'
       : '\n'
-    return Array(leadingContent.split(splitRE).length).join(padChar)
+    return Array(getPaddingOffset(block) + 1).join(padChar)
   }
 
-  function addSourceMap (block: SFCBlock, options: Object) {
-    const filename = options.filename
+  function getPaddingOffset (block: SFCBlock) {
+    return content.slice(0, block.start).split(splitRE).length - 1
+  }
+
+  function addSourceMap (block: SFCBlock) {
+    const filename = options.map.filename
     if (!filename) {
       throw new Error('Should provide original filename in the map option.')
     }
+    const offset = options.pad ? 0 : getPaddingOffset(block)
     const map = new SourceMapGenerator()
     map.setSourceContent(filename, content)
     block.content.split(splitRE).forEach((line, index) => {
@@ -108,7 +112,7 @@ export function parseComponent (
         map.addMapping({
           source: filename,
           original: {
-            line: index + 1,
+            line: index + 1 + offset,
             column: 0
           },
           generated: {

+ 49 - 3
test/unit/modules/compiler/sfc-parser.spec.js

@@ -1,8 +1,9 @@
-import { parseSFC } from 'compiler/parser/sfc-parser'
+import { parseComponent } from 'compiler/parser/sfc-parser'
+import { SourceMapConsumer } from 'source-map'
 
-describe('SFC parser', () => {
+describe('Single File Component parser', () => {
   it('should parse', () => {
-    const res = parseSFC(`
+    const res = parseComponent(`
       <template>
         <div>hi</div>
       </template>
@@ -28,4 +29,49 @@ describe('SFC parser', () => {
     expect(res.styles[1].content.trim()).toBe('h1\n  color red\nh2\n  color green')
     expect(res.script.content.trim()).toBe('export default {}')
   })
+
+  it('pad content', () => {
+    const res = parseComponent(`
+      <template>
+        <div></div>
+      </template>
+      <script>
+        export default {}
+      </script>
+      <style>
+        h1 { color: red }
+      </style>
+    `.trim(), { pad: true })
+    expect(res.script.content).toBe(Array(3 + 1).join('//\n') + '\nexport default {}\n')
+    expect(res.styles[0].content).toBe(Array(6 + 1).join('\n') + '\nh1 { color: red }\n')
+  })
+
+  it('source map', () => {
+    const res = parseComponent(`
+      <script>
+        export default {}
+      </script>
+      <style>
+        h1 { color: red }
+      </style>
+    `.trim(), {
+      pad: true,
+      map: {
+        filename: 'test.vue'
+      }
+    })
+    const scriptConsumer = new SourceMapConsumer(res.script.map)
+    const scriptPos = scriptConsumer.originalPositionFor({
+      line: 2,
+      column: 1
+    })
+    expect(scriptPos.line).toBe(2)
+
+    const styleConsumer = new SourceMapConsumer(res.styles[0].map)
+    const stylePos = styleConsumer.originalPositionFor({
+      line: 5,
+      column: 1
+    })
+    expect(stylePos.line).toBe(5)
+  })
 })