expect(result.errors.length).toBe(0)
})
+test('preprocess pug with indents and blank lines', () => {
+ const template = parse(
+ `
+<template lang="pug">
+ body
+ h1 The next line contains four spaces.
+
+ div.container
+ p The next line is empty.
+ p This is the last line.
+</template>
+`,
+ { filename: 'example.vue', sourceMap: true }
+ ).descriptor.template as SFCTemplateBlock
+
+ const result = compile({
+ filename: 'example.vue',
+ source: template.content,
+ preprocessLang: template.lang
+ })
+
+ expect(result.errors.length).toBe(0)
+ expect(result.source).toBe(
+ '<body><h1>The next line contains four spaces.</h1><div class="container"><p>The next line is empty.</p></div><p>This is the last line.</p></body>'
+ )
+})
+
test('warn missing preprocessor', () => {
const template = parse(`<template lang="unknownLang">hi</template>\n`, {
filename: 'example.vue',
})
})
+ test('template block with lang + indent', () => {
+ // Padding determines how many blank lines will there be before the style block
+ const padding = Math.round(Math.random() * 10)
+ const template = parse(
+ `${'\n'.repeat(padding)}<template lang="pug">
+ h1 foo
+ div bar
+ span baz
+</template>\n`
+ ).descriptor.template!
+
+ expect(template.map).not.toBeUndefined()
+
+ const consumer = new SourceMapConsumer(template.map!)
+ consumer.eachMapping(mapping => {
+ expect(mapping.originalLine - mapping.generatedLine).toBe(padding)
+ expect(mapping.originalColumn - mapping.generatedColumn).toBe(2)
+ })
+ })
+
test('custom block', () => {
const padding = Math.round(Math.random() * 10)
const custom = parse(
}
}
+ // dedent pug/jade templates
+ let templateColumnOffset = 0
+ if (
+ descriptor.template &&
+ (descriptor.template.lang === 'pug' || descriptor.template.lang === 'jade')
+ ) {
+ ;[descriptor.template.content, templateColumnOffset] = dedent(
+ descriptor.template.content
+ )
+ }
+
if (sourceMap) {
- const genMap = (block: SFCBlock | null) => {
+ const genMap = (block: SFCBlock | null, columnOffset = 0) => {
if (block && !block.src) {
block.map = generateSourceMap(
filename,
source,
block.content,
sourceRoot,
- !pad || block.type === 'template' ? block.loc.start.line - 1 : 0
+ !pad || block.type === 'template' ? block.loc.start.line - 1 : 0,
+ columnOffset
)
}
}
- genMap(descriptor.template)
+ genMap(descriptor.template, templateColumnOffset)
genMap(descriptor.script)
descriptor.styles.forEach(genMap)
descriptor.customBlocks.forEach(genMap)
source: string,
generated: string,
sourceRoot: string,
- lineOffset: number
+ lineOffset: number,
+ columnOffset: number
): RawSourceMap {
const map = new SourceMapGenerator({
file: filename.replace(/\\/g, '/'),
source: filename,
original: {
line: originalLine,
- column: i
+ column: i + columnOffset
},
generated: {
line: generatedLine,
return false
}
+
+/**
+ * Dedent a string.
+ *
+ * This removes any whitespace that is common to all lines in the string from
+ * each line in the string.
+ */
+function dedent(s: string): [string, number] {
+ const lines = s.split('\n')
+ const minIndent = lines.reduce(function (minIndent, line) {
+ if (line.trim() === '') {
+ return minIndent
+ }
+ const indent = line.match(/^\s*/)?.[0]?.length || 0
+ return Math.min(indent, minIndent)
+ }, Infinity)
+ if (minIndent === 0) {
+ return [s, minIndent]
+ }
+ return [
+ lines
+ .map(function (line) {
+ return line.slice(minIndent)
+ })
+ .join('\n'),
+ minIndent
+ ]
+}