SFC parseComponent pads complete content with spaces (#5059)

* SFC parseComponent pads content with spaces

when `{ pad: true }` is provided. That is, all content is converted to
spaces. Previously, each line was truncated to "//". The new padding
method works better with character-oriented tools that calculate
positions by distance from the beginning of the file instead of by line
number.

* Made parseComponent's pad support "line" | "space"

Also still supports true for backward compatibility. True is the same as
"line".
This commit is contained in:
Nathan Shively-Sanders 2017-03-05 12:36:39 -08:00 committed by Evan You
parent eb58694f6f
commit 2dc177ffb3
3 changed files with 39 additions and 12 deletions

View File

@ -85,4 +85,9 @@ Parse a SFC (single-file component, or `*.vue` file) into a descriptor (refer to
#### Options
- `pad`: with `{ pad: true }`, the extracted content for each block will be padded with newlines to ensure that the line numbers align with the original file. This is useful when you are piping the extracted content into other pre-processors, as you will get correct line numbers if there are any syntax errors.
#### `pad`
`pad` is useful when you are piping the extracted content into other pre-processors, as you will get correct line numbers or character indices if there are any syntax errors.
- with `{ pad: "line" }`, the extracted content for each block will be prefixed with one newline for each line in the leading content from the original file to ensure that the line numbers align with the original file.
- with `{ pad: "space" }`, the extracted content for each block will be prefixed with one space for each character in the leading content from the original file to ensure that the character count remains the same as the original file.

View File

@ -5,6 +5,7 @@ import { parseHTML } from 'compiler/parser/html-parser'
import { makeMap } from 'shared/util'
const splitRE = /\r?\n/g
const replaceRE = /./g
const isSpecialTag = makeMap('script,style,template', true)
type Attribute = {
@ -86,7 +87,7 @@ export function parseComponent (
// pad content so that linters and pre-processors can output correct
// line numbers in errors and warnings
if (currentBlock.type !== 'template' && options.pad) {
text = padContent(currentBlock) + text
text = padContent(currentBlock, options.pad) + text
}
currentBlock.content = text
currentBlock = null
@ -94,12 +95,16 @@ export function parseComponent (
depth--
}
function padContent (block: SFCBlock | SFCCustomBlock) {
const offset = content.slice(0, block.start).split(splitRE).length
const padChar = block.type === 'script' && !block.lang
? '//\n'
: '\n'
return Array(offset).join(padChar)
function padContent (block: SFCBlock | SFCCustomBlock, pad: true | "line" | "space") {
if (pad === 'space') {
return content.slice(0, block.start).replace(replaceRE, ' ')
} else {
const offset = content.slice(0, block.start).split(splitRE).length
const padChar = block.type === 'script' && !block.lang
? '//\n'
: '\n'
return Array(offset).join(padChar)
}
}
parseHTML(content, {

View File

@ -56,7 +56,7 @@ describe('Single File Component parser', () => {
})
it('pad content', () => {
const res = parseComponent(`
const content = `
<template>
<div></div>
</template>
@ -66,9 +66,26 @@ describe('Single File Component parser', () => {
<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')
`
const padDefault = parseComponent(content.trim(), { pad: true })
const padLine = parseComponent(content.trim(), { pad: 'line' })
const padSpace = parseComponent(content.trim(), { pad: 'space' })
expect(padDefault.script.content).toBe(Array(3 + 1).join('//\n') + '\nexport default {}\n')
expect(padDefault.styles[0].content).toBe(Array(6 + 1).join('\n') + '\nh1 { color: red }\n')
expect(padLine.script.content).toBe(Array(3 + 1).join('//\n') + '\nexport default {}\n')
expect(padLine.styles[0].content).toBe(Array(6 + 1).join('\n') + '\nh1 { color: red }\n')
expect(padSpace.script.content).toBe(`<template>
<div></div>
</template>
<script>`.replace(/./g, ' ') + '\nexport default {}\n')
expect(padSpace.styles[0].content).toBe(`<template>
<div></div>
</template>
<script>
export default {}
</script>
<style>`.replace(/./g, ' ') + '\nh1 { color: red }\n')
})
it('should handle template blocks with lang as special text', () => {