offset: number
line: number
column: number
- inPre: boolean
+ inPre: boolean // HTML <pre> tag, preserve whitespaces
+ inVPre: boolean // v-pre, do not process directives and interpolations
}
export function baseParse(
offset: 0,
originalSource: content,
source: content,
- inPre: false
+ inPre: false,
+ inVPre: false
}
}
let node: TemplateChildNode | TemplateChildNode[] | undefined = undefined
if (mode === TextModes.DATA || mode === TextModes.RCDATA) {
- if (!context.inPre && startsWith(s, context.options.delimiters[0])) {
+ if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {
// '{{'
node = parseInterpolation(context, mode)
} else if (mode === TextModes.DATA && s[0] === '<') {
// Whitespace management for more efficient output
// (same as v2 whitespace: 'condense')
let removedWhitespace = false
- if (
- mode !== TextModes.RAWTEXT &&
- (!parent || !context.options.isPreTag(parent.tag))
- ) {
- 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 is adjacent to a comment, or:
- // - the whitespace is between two elements AND contains newline
- // Then the whitespace is ignored.
- if (
- !prev ||
- !next ||
- 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
+ if (mode !== TextModes.RAWTEXT) {
+ if (!context.inPre) {
+ 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 is adjacent to a comment, or:
+ // - the whitespace is between two elements AND contains newline
+ // Then the whitespace is ignored.
+ if (
+ !prev ||
+ !next ||
+ 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
+ node.content = ' '
+ }
} else {
- // Otherwise, condensed consecutive whitespace inside the text down to
- // a single space
- node.content = ' '
+ node.content = node.content.replace(/\s+/g, ' ')
}
- } else {
- node.content = node.content.replace(/\s+/g, ' ')
}
}
+ } else {
+ // remove leading newline per html spec
+ // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element
+ const first = nodes[0]
+ if (first && first.type === NodeTypes.TEXT) {
+ first.content = first.content.replace(/^\r?\n/, '')
+ }
}
}
// Start tag.
const wasInPre = context.inPre
+ const wasInVPre = context.inVPre
const parent = last(ancestors)
const element = parseTag(context, TagType.Start, parent)
const isPreBoundary = context.inPre && !wasInPre
+ const isVPreBoundary = context.inVPre && !wasInVPre
if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
return element
if (isPreBoundary) {
context.inPre = false
}
+ if (isVPreBoundary) {
+ context.inVPre = false
+ }
return element
}
// Attributes.
let props = parseAttributes(context, type)
+ // check <pre> tag
+ if (context.options.isPreTag(tag)) {
+ context.inPre = true
+ }
+
// check v-pre
if (
- !context.inPre &&
+ !context.inVPre &&
props.some(p => p.type === NodeTypes.DIRECTIVE && p.name === 'pre')
) {
- context.inPre = true
+ context.inVPre = true
// reset context
extend(context, cursor)
context.source = currentSource
let tagType = ElementTypes.ELEMENT
const options = context.options
- if (!context.inPre && !options.isCustomElement(tag)) {
+ if (!context.inVPre && !options.isCustomElement(tag)) {
const hasVIs = props.some(
p => p.type === NodeTypes.DIRECTIVE && p.name === 'is'
)
}
const loc = getSelection(context, start)
- if (!context.inPre && /^(v-|:|@|#)/.test(name)) {
+ if (!context.inVPre && /^(v-|:|@|#)/.test(name)) {
const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^@|^#)([^\.]+))?(.+)?$/i.exec(
name
)!