diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts
index 790123ac6..e0608fde4 100644
--- a/packages/compiler-core/__tests__/parse.spec.ts
+++ b/packages/compiler-core/__tests__/parse.spec.ts
@@ -1736,20 +1736,26 @@ foo
})
})
- describe('whitespace management', () => {
+ describe('whitespace management when adopting strategy condense', () => {
+ const parse = (content: string, options?: ParserOptions) =>
+ baseParse(content, {
+ whitespace: 'condense',
+ ...options
+ })
+
it('should remove whitespaces at start/end inside an element', () => {
- const ast = baseParse(`
`)
+ const ast = parse(`
`)
expect((ast.children[0] as ElementNode).children.length).toBe(1)
})
it('should remove whitespaces w/ newline between elements', () => {
- const ast = baseParse(` \n \n `)
+ const ast = parse(` \n \n `)
expect(ast.children.length).toBe(3)
expect(ast.children.every(c => c.type === NodeTypes.ELEMENT)).toBe(true)
})
it('should remove whitespaces adjacent to comments', () => {
- const ast = baseParse(` \n `)
+ const ast = parse(` \n `)
expect(ast.children.length).toBe(3)
expect(ast.children[0].type).toBe(NodeTypes.ELEMENT)
expect(ast.children[1].type).toBe(NodeTypes.COMMENT)
@@ -1757,7 +1763,7 @@ foo
})
it('should remove whitespaces w/ newline between comments and elements', () => {
- const ast = baseParse(` \n \n `)
+ const ast = parse(` \n \n `)
expect(ast.children.length).toBe(3)
expect(ast.children[0].type).toBe(NodeTypes.ELEMENT)
expect(ast.children[1].type).toBe(NodeTypes.COMMENT)
@@ -1765,7 +1771,7 @@ foo
})
it('should NOT remove whitespaces w/ newline between interpolations', () => {
- const ast = baseParse(`{{ foo }} \n {{ bar }}`)
+ const ast = parse(`{{ foo }} \n {{ bar }}`)
expect(ast.children.length).toBe(3)
expect(ast.children[0].type).toBe(NodeTypes.INTERPOLATION)
expect(ast.children[1]).toMatchObject({
@@ -1776,7 +1782,7 @@ foo
})
it('should NOT remove whitespaces w/o newline between elements', () => {
- const ast = baseParse(` `)
+ const ast = parse(` `)
expect(ast.children.length).toBe(5)
expect(ast.children.map(c => c.type)).toMatchObject([
NodeTypes.ELEMENT,
@@ -1788,7 +1794,7 @@ foo
})
it('should condense consecutive whitespaces in text', () => {
- const ast = baseParse(` foo \n bar baz `)
+ const ast = parse(` foo \n bar baz `)
expect((ast.children[0] as TextNode).content).toBe(` foo bar baz `)
})
@@ -1824,6 +1830,84 @@ foo
})
})
+ describe('whitespace management when adopting strategy preserve', () => {
+ const parse = (content: string, options?: ParserOptions) =>
+ baseParse(content, {
+ whitespace: 'preserve',
+ ...options
+ })
+
+ it('should preserve whitespaces at start/end inside an element', () => {
+ const ast = parse(`
`)
+ expect((ast.children[0] as ElementNode).children.length).toBe(3)
+ })
+
+ it('should preserve whitespaces w/ newline between elements', () => {
+ const ast = parse(` \n \n `)
+ expect(ast.children.length).toBe(5)
+ expect(ast.children.map(c => c.type)).toMatchObject([
+ NodeTypes.ELEMENT,
+ NodeTypes.TEXT,
+ NodeTypes.ELEMENT,
+ NodeTypes.TEXT,
+ NodeTypes.ELEMENT
+ ])
+ })
+
+ it('should preserve whitespaces adjacent to comments', () => {
+ const ast = parse(` \n `)
+ expect(ast.children.length).toBe(5)
+ expect(ast.children.map(c => c.type)).toMatchObject([
+ NodeTypes.ELEMENT,
+ NodeTypes.TEXT,
+ NodeTypes.COMMENT,
+ NodeTypes.TEXT,
+ NodeTypes.ELEMENT
+ ])
+ })
+
+ it('should preserve whitespaces w/ newline between comments and elements', () => {
+ const ast = parse(` \n \n `)
+ expect(ast.children.length).toBe(5)
+ expect(ast.children.map(c => c.type)).toMatchObject([
+ NodeTypes.ELEMENT,
+ NodeTypes.TEXT,
+ NodeTypes.COMMENT,
+ NodeTypes.TEXT,
+ NodeTypes.ELEMENT
+ ])
+ })
+
+ it('should preserve whitespaces w/ newline between interpolations', () => {
+ const ast = parse(`{{ foo }} \n {{ bar }}`)
+ expect(ast.children.length).toBe(3)
+ expect(ast.children[0].type).toBe(NodeTypes.INTERPOLATION)
+ expect(ast.children[1]).toMatchObject({
+ type: NodeTypes.TEXT,
+ content: ' \n '
+ })
+ expect(ast.children[2].type).toBe(NodeTypes.INTERPOLATION)
+ })
+
+ it('should preserve whitespaces w/o newline between elements', () => {
+ const ast = parse(` `)
+ expect(ast.children.length).toBe(5)
+ expect(ast.children.map(c => c.type)).toMatchObject([
+ NodeTypes.ELEMENT,
+ NodeTypes.TEXT,
+ NodeTypes.ELEMENT,
+ NodeTypes.TEXT,
+ NodeTypes.ELEMENT
+ ])
+ })
+
+ it('should preserve consecutive whitespaces in text', () => {
+ const content = ` foo \n bar baz `
+ const ast = parse(content)
+ expect((ast.children[0] as TextNode).content).toBe(content)
+ })
+ })
+
describe('Errors', () => {
const patterns: {
[key: string]: Array<{
diff --git a/packages/compiler-core/src/options.ts b/packages/compiler-core/src/options.ts
index 08cb12d89..a387c1678 100644
--- a/packages/compiler-core/src/options.ts
+++ b/packages/compiler-core/src/options.ts
@@ -52,6 +52,10 @@ export interface ParserOptions
* @default ['{{', '}}']
*/
delimiters?: [string, string]
+ /**
+ * Whitespace handling strategy
+ */
+ whitespace?: 'preserve' | 'condense'
/**
* Only needed for DOM compilers
*/
diff --git a/packages/compiler-core/src/parse.ts b/packages/compiler-core/src/parse.ts
index 6335df7a3..cb5f61831 100644
--- a/packages/compiler-core/src/parse.ts
+++ b/packages/compiler-core/src/parse.ts
@@ -65,6 +65,7 @@ const decodeMap: Record = {
export const defaultParserOptions: MergedParserOptions = {
delimiters: [`{{`, `}}`],
+ whitespace: 'condense',
getNamespace: () => Namespaces.HTML,
getTextMode: () => TextModes.DATA,
isVoidTag: NO,
@@ -219,10 +220,9 @@ function parseChildren(
}
}
- // Whitespace management for more efficient output
- // (same as v2 whitespace: 'condense')
+ // Whitespace handling strategy like v2
let removedWhitespace = false
- if (mode !== TextModes.RAWTEXT && mode !== TextModes.RCDATA) {
+ if (context.options.whitespace === 'condense' && mode !== TextModes.RAWTEXT && mode !== TextModes.RCDATA) {
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
if (!context.inPre && node.type === NodeTypes.TEXT) {