refactor(compiler): improve whitespace: 'preserve' behavior from #1600

- discard leading/ending whitespace inside an element
- condense preserved whitesapce into single space
This commit is contained in:
Evan You 2021-04-26 10:49:21 -04:00
parent dee3d6ab8b
commit b047a0864c
2 changed files with 19 additions and 17 deletions

View File

@ -1837,9 +1837,9 @@ foo
...options
})
it('should preserve whitespaces at start/end inside an element', () => {
it('should still remove whitespaces at start/end inside an element', () => {
const ast = parse(`<div> <span/> </div>`)
expect((ast.children[0] as ElementNode).children.length).toBe(3)
expect((ast.children[0] as ElementNode).children.length).toBe(1)
})
it('should preserve whitespaces w/ newline between elements', () => {
@ -1884,7 +1884,7 @@ foo
expect(ast.children[0].type).toBe(NodeTypes.INTERPOLATION)
expect(ast.children[1]).toMatchObject({
type: NodeTypes.TEXT,
content: ' \n '
content: ' '
})
expect(ast.children[2].type).toBe(NodeTypes.INTERPOLATION)
})

View File

@ -38,6 +38,7 @@ import {
} from './compat/compatConfig'
type OptionalOptions =
| 'whitespace'
| 'isNativeTag'
| 'isBuiltInComponent'
| keyof CompilerCompatOptions
@ -65,7 +66,6 @@ const decodeMap: Record<string, string> = {
export const defaultParserOptions: MergedParserOptions = {
delimiters: [`{{`, `}}`],
whitespace: 'condense',
getNamespace: () => Namespaces.HTML,
getTextMode: () => TextModes.DATA,
isVoidTag: NO,
@ -222,35 +222,37 @@ function parseChildren(
// Whitespace handling strategy like v2
let removedWhitespace = false
if (context.options.whitespace === 'condense' && mode !== TextModes.RAWTEXT && mode !== TextModes.RCDATA) {
if (mode !== TextModes.RAWTEXT && mode !== TextModes.RCDATA) {
const preserve = context.options.whitespace === 'preserve'
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if (!context.inPre && node.type === NodeTypes.TEXT) {
if (!/[^\t\r\n\f ]/.test(node.content)) {
const prev = nodes[i - 1]
const next = nodes[i + 1]
// If:
// Remove if:
// - the whitespace is the first or last node, or:
// - the whitespace is adjacent to a comment, or:
// - the whitespace is between two elements AND contains newline
// Then the whitespace is ignored.
// - (condense mode) the whitespace is adjacent to a comment, or:
// - (condense mode) the whitespace is between two elements AND contains newline
if (
!prev ||
!next ||
prev.type === NodeTypes.COMMENT ||
next.type === NodeTypes.COMMENT ||
(prev.type === NodeTypes.ELEMENT &&
next.type === NodeTypes.ELEMENT &&
/[\r\n]/.test(node.content))
(!preserve &&
(prev.type === NodeTypes.COMMENT ||
next.type === NodeTypes.COMMENT ||
(prev.type === NodeTypes.ELEMENT &&
next.type === NodeTypes.ELEMENT &&
/[\r\n]/.test(node.content))))
) {
removedWhitespace = true
nodes[i] = null as any
} else {
// Otherwise, condensed consecutive whitespace inside the text
// down to a single space
// Otherwise, the whitespace is condensed into a single space
node.content = ' '
}
} else {
} else if (!preserve) {
// in condense mode, consecutive whitespaces in text are condensed
// down to a single space.
node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ')
}
}