feat(compiler-core): whitespace handling strategy
This commit is contained in:
parent
7b37f78dc9
commit
dee3d6ab8b
@ -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', () => {
|
it('should remove whitespaces at start/end inside an element', () => {
|
||||||
const ast = baseParse(`<div> <span/> </div>`)
|
const ast = parse(`<div> <span/> </div>`)
|
||||||
expect((ast.children[0] as ElementNode).children.length).toBe(1)
|
expect((ast.children[0] as ElementNode).children.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should remove whitespaces w/ newline between elements', () => {
|
it('should remove whitespaces w/ newline between elements', () => {
|
||||||
const ast = baseParse(`<div/> \n <div/> \n <div/>`)
|
const ast = parse(`<div/> \n <div/> \n <div/>`)
|
||||||
expect(ast.children.length).toBe(3)
|
expect(ast.children.length).toBe(3)
|
||||||
expect(ast.children.every(c => c.type === NodeTypes.ELEMENT)).toBe(true)
|
expect(ast.children.every(c => c.type === NodeTypes.ELEMENT)).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should remove whitespaces adjacent to comments', () => {
|
it('should remove whitespaces adjacent to comments', () => {
|
||||||
const ast = baseParse(`<div/> \n <!--foo--> <div/>`)
|
const ast = parse(`<div/> \n <!--foo--> <div/>`)
|
||||||
expect(ast.children.length).toBe(3)
|
expect(ast.children.length).toBe(3)
|
||||||
expect(ast.children[0].type).toBe(NodeTypes.ELEMENT)
|
expect(ast.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
expect(ast.children[1].type).toBe(NodeTypes.COMMENT)
|
expect(ast.children[1].type).toBe(NodeTypes.COMMENT)
|
||||||
@ -1757,7 +1763,7 @@ foo
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should remove whitespaces w/ newline between comments and elements', () => {
|
it('should remove whitespaces w/ newline between comments and elements', () => {
|
||||||
const ast = baseParse(`<div/> \n <!--foo--> \n <div/>`)
|
const ast = parse(`<div/> \n <!--foo--> \n <div/>`)
|
||||||
expect(ast.children.length).toBe(3)
|
expect(ast.children.length).toBe(3)
|
||||||
expect(ast.children[0].type).toBe(NodeTypes.ELEMENT)
|
expect(ast.children[0].type).toBe(NodeTypes.ELEMENT)
|
||||||
expect(ast.children[1].type).toBe(NodeTypes.COMMENT)
|
expect(ast.children[1].type).toBe(NodeTypes.COMMENT)
|
||||||
@ -1765,7 +1771,7 @@ foo
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should NOT remove whitespaces w/ newline between interpolations', () => {
|
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.length).toBe(3)
|
||||||
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({
|
||||||
@ -1776,7 +1782,7 @@ foo
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should NOT remove whitespaces w/o newline between elements', () => {
|
it('should NOT remove whitespaces w/o newline between elements', () => {
|
||||||
const ast = baseParse(`<div/> <div/> <div/>`)
|
const ast = parse(`<div/> <div/> <div/>`)
|
||||||
expect(ast.children.length).toBe(5)
|
expect(ast.children.length).toBe(5)
|
||||||
expect(ast.children.map(c => c.type)).toMatchObject([
|
expect(ast.children.map(c => c.type)).toMatchObject([
|
||||||
NodeTypes.ELEMENT,
|
NodeTypes.ELEMENT,
|
||||||
@ -1788,7 +1794,7 @@ foo
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should condense consecutive whitespaces in text', () => {
|
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 `)
|
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(`<div> <span/> </div>`)
|
||||||
|
expect((ast.children[0] as ElementNode).children.length).toBe(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should preserve whitespaces w/ newline between elements', () => {
|
||||||
|
const ast = parse(`<div/> \n <div/> \n <div/>`)
|
||||||
|
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(`<div/> \n <!--foo--> <div/>`)
|
||||||
|
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(`<div/> \n <!--foo--> \n <div/>`)
|
||||||
|
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(`<div/> <div/> <div/>`)
|
||||||
|
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', () => {
|
describe('Errors', () => {
|
||||||
const patterns: {
|
const patterns: {
|
||||||
[key: string]: Array<{
|
[key: string]: Array<{
|
||||||
|
@ -52,6 +52,10 @@ export interface ParserOptions
|
|||||||
* @default ['{{', '}}']
|
* @default ['{{', '}}']
|
||||||
*/
|
*/
|
||||||
delimiters?: [string, string]
|
delimiters?: [string, string]
|
||||||
|
/**
|
||||||
|
* Whitespace handling strategy
|
||||||
|
*/
|
||||||
|
whitespace?: 'preserve' | 'condense'
|
||||||
/**
|
/**
|
||||||
* Only needed for DOM compilers
|
* Only needed for DOM compilers
|
||||||
*/
|
*/
|
||||||
|
@ -65,6 +65,7 @@ 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,
|
||||||
@ -219,10 +220,9 @@ function parseChildren(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whitespace management for more efficient output
|
// Whitespace handling strategy like v2
|
||||||
// (same as v2 whitespace: 'condense')
|
|
||||||
let removedWhitespace = false
|
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++) {
|
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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user