diff --git a/packages/vue-template-compiler/README.md b/packages/vue-template-compiler/README.md index ecdd055247d..87ef05be3e7 100644 --- a/packages/vue-template-compiler/README.md +++ b/packages/vue-template-compiler/README.md @@ -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. \ No newline at end of file diff --git a/src/sfc/parser.js b/src/sfc/parser.js index 4ac29d2d1df..643e55ca2ff 100644 --- a/src/sfc/parser.js +++ b/src/sfc/parser.js @@ -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, { diff --git a/test/unit/modules/sfc/sfc-parser.spec.js b/test/unit/modules/sfc/sfc-parser.spec.js index be3f518a584..dbe7e8a5333 100644 --- a/test/unit/modules/sfc/sfc-parser.spec.js +++ b/test/unit/modules/sfc/sfc-parser.spec.js @@ -56,7 +56,7 @@ describe('Single File Component parser', () => { }) it('pad content', () => { - const res = parseComponent(` + const content = ` @@ -66,9 +66,26 @@ describe('Single File Component parser', () => { - `.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(` + +