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