|
|
@@ -26,6 +26,7 @@ import { CompilerCompatOptions } from '../compat/compatConfig'
|
|
|
import { NO, extend } from '@vue/shared'
|
|
|
import { defaultOnError, defaultOnWarn } from '../errors'
|
|
|
import { forAliasRE, isCoreComponent } from '../utils'
|
|
|
+import { decodeHTML } from 'entities/lib/decode.js'
|
|
|
|
|
|
type OptionalOptions =
|
|
|
| 'decodeEntities'
|
|
|
@@ -69,8 +70,8 @@ const tokenizer = new Tokenizer(stack, {
|
|
|
onText(getSlice(start, end), start, end)
|
|
|
},
|
|
|
|
|
|
- ontextentity(char, end) {
|
|
|
- onText(char, end - 1, end)
|
|
|
+ ontextentity(char, start, end) {
|
|
|
+ onText(char, start, end)
|
|
|
},
|
|
|
|
|
|
oninterpolation(start, end) {
|
|
|
@@ -85,13 +86,18 @@ const tokenizer = new Tokenizer(stack, {
|
|
|
while (isWhitespace(currentInput.charCodeAt(innerEnd - 1))) {
|
|
|
innerEnd--
|
|
|
}
|
|
|
+ let exp = getSlice(innerStart, innerEnd)
|
|
|
+ // decode entities for backwards compat
|
|
|
+ if (exp.includes('&')) {
|
|
|
+ if (__BROWSER__) {
|
|
|
+ exp = currentOptions.decodeEntities!(exp, false)
|
|
|
+ } else {
|
|
|
+ exp = decodeHTML(exp)
|
|
|
+ }
|
|
|
+ }
|
|
|
addNode({
|
|
|
type: NodeTypes.INTERPOLATION,
|
|
|
- content: createSimpleExpression(
|
|
|
- getSlice(innerStart, innerEnd),
|
|
|
- false,
|
|
|
- getLoc(innerStart, innerEnd)
|
|
|
- ),
|
|
|
+ content: createSimpleExpression(exp, false, getLoc(innerStart, innerEnd)),
|
|
|
loc: getLoc(start, end)
|
|
|
})
|
|
|
},
|
|
|
@@ -101,7 +107,7 @@ const tokenizer = new Tokenizer(stack, {
|
|
|
currentElement = {
|
|
|
type: NodeTypes.ELEMENT,
|
|
|
tag: name,
|
|
|
- ns: currentOptions.getNamespace(name, getParent()),
|
|
|
+ ns: currentOptions.getNamespace(name, stack[0]),
|
|
|
tagType: ElementTypes.ELEMENT, // will be refined on tag close
|
|
|
props: [],
|
|
|
children: [],
|
|
|
@@ -227,8 +233,10 @@ const tokenizer = new Tokenizer(stack, {
|
|
|
currentAttrEndIndex = end
|
|
|
},
|
|
|
|
|
|
- onattribentity(char) {
|
|
|
+ onattribentity(char, start, end) {
|
|
|
currentAttrValue += char
|
|
|
+ if (currentAttrStartIndex < 0) currentAttrStartIndex = start
|
|
|
+ currentAttrEndIndex = end
|
|
|
},
|
|
|
|
|
|
onattribnameend(end) {
|
|
|
@@ -316,7 +324,11 @@ const tokenizer = new Tokenizer(stack, {
|
|
|
},
|
|
|
|
|
|
oncdata(start, end) {
|
|
|
- // TODO throw error
|
|
|
+ if (stack[0].ns !== Namespaces.HTML) {
|
|
|
+ onText(getSlice(start, end), start, end)
|
|
|
+ } else {
|
|
|
+ // TODO throw error if ns is html
|
|
|
+ }
|
|
|
}
|
|
|
})
|
|
|
|
|
|
@@ -418,7 +430,7 @@ function onText(content: string, start: number, end: number) {
|
|
|
// TODO do not do this in <script> or <style>
|
|
|
content = currentOptions.decodeEntities!(content, false)
|
|
|
}
|
|
|
- const parent = getParent()
|
|
|
+ const parent = stack[0] || currentRoot
|
|
|
const lastNode = parent.children[parent.children.length - 1]
|
|
|
if (lastNode?.type === NodeTypes.TEXT) {
|
|
|
// merge
|
|
|
@@ -436,7 +448,10 @@ function onText(content: string, start: number, end: number) {
|
|
|
function onCloseTag(el: ElementNode, end: number) {
|
|
|
// attach end position
|
|
|
let offset = 0
|
|
|
- while (currentInput.charCodeAt(end + offset) !== CharCodes.Gt) {
|
|
|
+ while (
|
|
|
+ currentInput.charCodeAt(end + offset) !== CharCodes.Gt &&
|
|
|
+ end + offset < currentInput.length
|
|
|
+ ) {
|
|
|
offset++
|
|
|
}
|
|
|
el.loc.end = tokenizer.getPos(end + offset + 1)
|
|
|
@@ -634,11 +649,7 @@ function condense(str: string) {
|
|
|
}
|
|
|
|
|
|
function addNode(node: TemplateChildNode) {
|
|
|
- getParent().children.push(node)
|
|
|
-}
|
|
|
-
|
|
|
-function getParent() {
|
|
|
- return stack[0] || currentRoot
|
|
|
+ ;(stack[0] || currentRoot).children.push(node)
|
|
|
}
|
|
|
|
|
|
function getLoc(start: number, end?: number): SourceLocation {
|