id: \\"foo\\",
class: bar.baz
}, [
- _createVNode(_Text, null, _toString(world.burn()), 1 /* TEXT */),
+ _createVNode(_Text, null, _toString(world.burn()) + \\" \\", 1 /* TEXT */),
(_openBlock(), ok
? _createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: _createBlock(_Fragment, { key: 1 }, [\\"no\\"])),
id: \\"foo\\",
class: _ctx.bar.baz
}, [
- createVNode(Text, null, toString(_ctx.world.burn()), 1 /* TEXT */),
+ createVNode(Text, null, toString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */),
(openBlock(), (_ctx.ok)
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: createBlock(Fragment, { key: 1 }, [\\"no\\"])),
id: \\"foo\\",
class: _ctx.bar.baz
}, [
- createVNode(Text, null, toString(_ctx.world.burn()), 1 /* TEXT */),
+ createVNode(Text, null, toString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */),
(openBlock(), (_ctx.ok)
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: createBlock(Fragment, { key: 1 }, [\\"no\\"])),
"type": 6,
"value": Object {
"content": "c",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 23,
"type": 6,
"value": Object {
"content": "&#a;",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 22,
"type": 6,
"value": Object {
"content": "ÿ",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "&#xg;",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 23,
"children": Array [
Object {
"content": "c",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 16,
"children": Array [
Object {
"content": "&#a;",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 15,
"children": Array [
Object {
"content": "ÿ",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 17,
"children": Array [
Object {
"content": "&#xg;",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 16,
"children": Array [
Object {
"content": "cdata",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 30,
"children": Array [
Object {
"content": "�",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 21,
"children": Array [
Object {
"content": "\ 3",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 18,
"children": Array [
Object {
"content": "\7f",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 17,
"type": 6,
"value": Object {
"content": "",
- "isEmpty": true,
"loc": Object {
"end": Object {
"column": 21,
"type": 6,
"value": Object {
"content": "",
- "isEmpty": true,
"loc": Object {
"end": Object {
"column": 27,
"children": Array [
Object {
"content": "<",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 12,
"children": Array [
Object {
"content": "</",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 13,
"children": Array [
Object {
"content": "cdata",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 30,
"children": Array [
Object {
"content": "<!--console.log('hello')",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 33,
"children": Array [
Object {
"content": "console.log('hello')",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 29,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 23,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 23,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 22,
"type": 6,
"value": Object {
"content": "abc",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 22,
"children": Array [
Object {
"content": "<�>",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 14,
"children": Array [
Object {
"content": "a < b",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 16,
"children": Array [
Object {
"content": "a ",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 13,
"type": 6,
"value": Object {
"content": "/",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 21,
"children": Array [
Object {
"content": "(",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 15,
"children": Array [
Object {
"content": "@",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 16,
"children": Array [
Object {
"content": "&",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 15,
"type": 6,
"value": Object {
"content": "foo",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "bar",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 12,
"type": 6,
"value": Object {
"content": "foo",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "bar",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 35,
"children": Array [
Object {
"content": "",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 20,
"children": Array [
Object {
"content": "",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 19,
"children": Array [
Object {
"content": "�",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 18,
"children": Array [
Object {
"content": "�",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 19,
"type": 6,
"value": Object {
"content": "",
- "isEmpty": true,
"loc": Object {
"end": Object {
"column": 23,
"type": 6,
"value": Object {
"content": "",
- "isEmpty": true,
"loc": Object {
"end": Object {
"column": 23,
"type": 6,
"value": Object {
"content": "",
- "isEmpty": true,
"loc": Object {
"end": Object {
"column": 23,
"type": 6,
"value": Object {
"content": "bar\\"",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "bar'",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "bar<div",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 27,
"type": 6,
"value": Object {
"content": "bar=baz",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 27,
"type": 6,
"value": Object {
"content": "bar\`",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"type": 6,
"value": Object {
"content": "bar",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 24,
"children": Array [
Object {
"content": "&unknown;",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 20,
"children": Array [
Object {
"content": "</div>",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 21,
"children": Array [
Object {
"content": "</div>",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 17,
"children": Array [
Object {
"content": "{{",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 3,
"children": Array [
Object {
"content": "{{ foo",
- "isEmpty": false,
"loc": Object {
"end": Object {
"column": 7,
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some text',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 9, line: 1, column: 10 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some text',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 9, line: 1, column: 10 },
expect(text1).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some ',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 5, line: 1, column: 6 },
expect(text2).toStrictEqual({
type: NodeTypes.TEXT,
content: ' text',
- isEmpty: false,
loc: {
start: { offset: 20, line: 1, column: 21 },
end: { offset: 25, line: 1, column: 26 },
expect(text1).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some ',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 5, line: 1, column: 6 },
expect(text2).toStrictEqual({
type: NodeTypes.TEXT,
content: ' text',
- isEmpty: false,
loc: {
start: { offset: 21, line: 1, column: 22 },
end: { offset: 26, line: 1, column: 27 },
expect(text1).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some ',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 5, line: 1, column: 6 },
expect(text2).toStrictEqual({
type: NodeTypes.TEXT,
content: ' text',
- isEmpty: false,
loc: {
start: { offset: 32, line: 1, column: 33 },
end: { offset: 37, line: 1, column: 38 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'a < b',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 5, line: 1, column: 6 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'a {{ b',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 6, line: 1, column: 7 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: '&ersand;',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 11, line: 1, column: 12 },
expect(text1).toStrictEqual({
type: NodeTypes.TEXT,
content: '&ersand;',
- isEmpty: false,
loc: {
start: { offset: 7, line: 1, column: 8 },
end: { offset: 20, line: 1, column: 21 },
expect(text2).toStrictEqual({
type: NodeTypes.TEXT,
content: '&ersand;',
- isEmpty: false,
loc: {
start: { offset: 23, line: 1, column: 24 },
end: { offset: 37, line: 1, column: 38 },
expect(text3).toStrictEqual({
type: NodeTypes.TEXT,
content: '&!',
- isEmpty: false,
loc: {
start: { offset: 40, line: 1, column: 41 },
end: { offset: 47, line: 1, column: 48 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: '†',
- isEmpty: false,
loc: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 6, line: 1, column: 7 },
{
type: NodeTypes.TEXT,
content: 'hello',
- isEmpty: false,
loc: {
start: { offset: 5, line: 1, column: 6 },
end: { offset: 10, line: 1, column: 11 },
value: {
type: NodeTypes.TEXT,
content: '',
- isEmpty: true,
loc: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 10, line: 1, column: 11 },
value: {
type: NodeTypes.TEXT,
content: '',
- isEmpty: true,
loc: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 10, line: 1, column: 11 },
value: {
type: NodeTypes.TEXT,
content: ">'",
- isEmpty: false,
loc: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 12, line: 1, column: 13 },
value: {
type: NodeTypes.TEXT,
content: '>"',
- isEmpty: false,
loc: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 12, line: 1, column: 13 },
value: {
type: NodeTypes.TEXT,
content: 'a/',
- isEmpty: false,
loc: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 10, line: 1, column: 11 },
value: {
type: NodeTypes.TEXT,
content: 'a',
- isEmpty: false,
loc: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 9, line: 1, column: 10 },
value: {
type: NodeTypes.TEXT,
content: 'c',
- isEmpty: false,
loc: {
start: { offset: 16, line: 1, column: 17 },
end: { offset: 19, line: 1, column: 20 },
value: {
type: NodeTypes.TEXT,
content: '',
- isEmpty: true,
loc: {
start: { offset: 32, line: 1, column: 33 },
end: { offset: 34, line: 1, column: 35 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'hello',
- isEmpty: false,
loc: {
start: { offset: 5, line: 1, column: 6 },
end: { offset: 10, line: 1, column: 11 },
"const _Vue = Vue
const _createVNode = Vue.createVNode
-const _hoisted_1 = _createVNode(\\"span\\", null, [\\"foo \\", _toString(1), _toString(true)])
+const _hoisted_1 = _createVNode(\\"span\\", null, [
+ \\"foo \\",
+ _toString(1),
+ \\" \\",
+ _toString(true)
+])
return function render() {
with (this) {
default: ({ bar }) => [toString(foo), toString(bar), toString(_ctx.baz)],
_compiled: true
}, 256 /* DYNAMIC_SLOTS */),
+ \\" \\",
toString(foo),
toString(_ctx.bar),
toString(_ctx.baz)
isConstant: true
}
},
+ {
+ type: NodeTypes.TEXT,
+ content: ` `
+ },
{
type: NodeTypes.INTERPOLATION,
content: {
}
},
// test scope
+ {
+ type: NodeTypes.TEXT,
+ content: ` `
+ },
{
type: NodeTypes.INTERPOLATION,
content: {
export interface TextNode extends Node {
type: NodeTypes.TEXT
content: string
- isEmpty: boolean
}
export interface CommentNode extends Node {
if (Array.isArray(node)) {
for (let i = 0; i < node.length; i++) {
- pushNode(context, nodes, node[i])
+ pushNode(nodes, node[i])
}
} else {
- pushNode(context, nodes, node)
+ pushNode(nodes, node)
}
}
- return nodes
+ // Whitespace management for more efficient output
+ // (same as v2 whitespance: 'condense')
+ let removedWhitespace = false
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i]
+ if (node.type === NodeTypes.TEXT) {
+ if (!node.content.trim()) {
+ const prev = nodes[i - 1]
+ const next = nodes[i + 1]
+ // If:
+ // - the whitespace is the first or last node, or:
+ // - the whitespace contains newline AND is between two element or comments
+ // Then the whitespace is ignored.
+ if (
+ !prev ||
+ !next ||
+ ((prev.type === NodeTypes.ELEMENT ||
+ prev.type === NodeTypes.COMMENT) &&
+ (next.type === NodeTypes.ELEMENT ||
+ next.type === NodeTypes.COMMENT) &&
+ /[\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
+ node.content = ' '
+ }
+ } else {
+ node.content = node.content.replace(/\s+/g, ' ')
+ }
+ }
+ }
+
+ return removedWhitespace ? nodes.filter(node => node !== null) : nodes
}
-function pushNode(
- context: ParserContext,
- nodes: TemplateChildNode[],
- node: TemplateChildNode
-): void {
+function pushNode(nodes: TemplateChildNode[], node: TemplateChildNode): void {
// ignore comments in production
/* istanbul ignore next */
if (!__DEV__ && node.type === NodeTypes.COMMENT) {
}
if (node.type === NodeTypes.TEXT) {
- if (node.isEmpty) {
- return
- }
-
+ const prev = last(nodes)
// Merge if both this and the previous node are text and those are
// consecutive. This happens for cases like "a < b".
- const prev = last(nodes)
if (
prev &&
prev.type === NodeTypes.TEXT &&
prev.loc.end.offset === node.loc.start.offset
) {
prev.content += node.content
- prev.isEmpty = prev.content.trim().length === 0
prev.loc.end = node.loc.end
prev.loc.source += node.loc.source
return
value: value && {
type: NodeTypes.TEXT,
content: value.content,
- isEmpty: value.content.trim().length === 0,
loc: value.loc
},
loc
__DEV__ && assert(context.source.length > 0)
const [open] = context.options.delimiters
+ // TODO could probably use some perf optimization
const endIndex = Math.min(
...[
context.source.indexOf('<', 1),
return {
type: NodeTypes.TEXT,
content,
- loc: getSelection(context, start),
- isEmpty: !content.trim()
+ loc: getSelection(context, start)
}
}
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some<div>text</div>and<!--comment-->',
- isEmpty: false,
loc: {
start: { offset: 10, line: 1, column: 11 },
end: { offset: 46, line: 1, column: 47 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: '&',
- isEmpty: false,
loc: {
start: { offset: 10, line: 1, column: 11 },
end: { offset: 15, line: 1, column: 16 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some<div>text</div>and<!--comment-->',
- isEmpty: false,
loc: {
start: { offset: 7, line: 1, column: 8 },
end: { offset: 43, line: 1, column: 44 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: '&',
- isEmpty: false,
loc: {
start: { offset: 7, line: 1, column: 8 },
end: { offset: 12, line: 1, column: 13 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'some text',
- isEmpty: false,
loc: {
start: { offset: 14, line: 1, column: 15 },
end: { offset: 23, line: 1, column: 24 },
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'hello</textarea</textarea0>',
- isEmpty: false,
loc: {
start: { offset: 10, line: 1, column: 11 },
end: { offset: 37, line: 1, column: 38 },