Skip to content

Commit

Permalink
fix(compiler-sfc): deindent pug/jade templates
Browse files Browse the repository at this point in the history
close #3231
close #3842
close #7723
  • Loading branch information
yyx990803 committed Dec 1, 2023
1 parent 30d5d93 commit 6345197
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 5 deletions.
27 changes: 27 additions & 0 deletions packages/compiler-sfc/__tests__/compileTemplate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,33 @@ body
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',
Expand Down
20 changes: 20 additions & 0 deletions packages/compiler-sfc/__tests__/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ describe('compiler:sfc', () => {
})
})

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(
Expand Down
51 changes: 46 additions & 5 deletions packages/compiler-sfc/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,19 +253,31 @@ export function 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)
Expand Down Expand Up @@ -369,7 +381,8 @@ function generateSourceMap(
source: string,
generated: string,
sourceRoot: string,
lineOffset: number
lineOffset: number,
columnOffset: number
): RawSourceMap {
const map = new SourceMapGenerator({
file: filename.replace(/\\/g, '/'),
Expand All @@ -386,7 +399,7 @@ function generateSourceMap(
source: filename,
original: {
line: originalLine,
column: i
column: i + columnOffset
},
generated: {
line: generatedLine,
Expand Down Expand Up @@ -466,3 +479,31 @@ export function hmrShouldReload(

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
]
}

0 comments on commit 6345197

Please sign in to comment.