mirror of https://github.com/vuejs/core.git
wip: pass more compiler-dom tests
This commit is contained in:
parent
1912af04e3
commit
a1b10a21ac
|
@ -178,7 +178,7 @@ export enum QuoteType {
|
|||
|
||||
export interface Callbacks {
|
||||
ontext(start: number, endIndex: number): void
|
||||
ontextentity(char: string, endIndex: number): void
|
||||
ontextentity(char: string, start: number, endIndex: number): void
|
||||
|
||||
oninterpolation(start: number, endIndex: number): void
|
||||
|
||||
|
@ -188,7 +188,7 @@ export interface Callbacks {
|
|||
onclosetag(start: number, endIndex: number): void
|
||||
|
||||
onattribdata(start: number, endIndex: number): void
|
||||
onattribentity(char: string): void
|
||||
onattribentity(char: string, start: number, end: number): void
|
||||
onattribend(quote: QuoteType, endIndex: number): void
|
||||
onattribname(start: number, endIndex: number): void
|
||||
onattribnameend(endIndex: number): void
|
||||
|
@ -325,6 +325,9 @@ export default class Tokenizer {
|
|||
} else {
|
||||
this.delimiterIndex++
|
||||
}
|
||||
} else if (this.inRCDATA) {
|
||||
this.state = State.InSpecialTag
|
||||
this.stateInSpecialTag(c)
|
||||
} else {
|
||||
this.state = State.Text
|
||||
this.stateText(c)
|
||||
|
@ -343,7 +346,11 @@ export default class Tokenizer {
|
|||
if (c === this.delimiterClose[this.delimiterIndex]) {
|
||||
if (this.delimiterIndex === this.delimiterClose.length - 1) {
|
||||
this.cbs.oninterpolation(this.sectionStart, this.index + 1)
|
||||
this.state = State.Text
|
||||
if (this.inRCDATA) {
|
||||
this.state = State.InSpecialTag
|
||||
} else {
|
||||
this.state = State.Text
|
||||
}
|
||||
this.sectionStart = this.index + 1
|
||||
} else {
|
||||
this.delimiterIndex++
|
||||
|
@ -410,6 +417,11 @@ export default class Tokenizer {
|
|||
// We have to parse entities in <title> and <textarea> tags.
|
||||
if (!__BROWSER__ && c === CharCodes.Amp) {
|
||||
this.startEntity()
|
||||
} else if (c === this.delimiterOpen[0]) {
|
||||
// We also need to handle interpolation
|
||||
this.state = State.InterpolationOpen
|
||||
this.delimiterIndex = 0
|
||||
this.stateInterpolationOpen(c)
|
||||
}
|
||||
} else if (this.fastForwardTo(CharCodes.Lt)) {
|
||||
// Outside of <title> and <textarea> tags, we can fast-forward.
|
||||
|
@ -1077,7 +1089,11 @@ export default class Tokenizer {
|
|||
this.sectionStart = this.entityStart + consumed
|
||||
this.index = this.sectionStart - 1
|
||||
|
||||
this.cbs.onattribentity(fromCodePoint(cp))
|
||||
this.cbs.onattribentity(
|
||||
fromCodePoint(cp),
|
||||
this.entityStart,
|
||||
this.sectionStart
|
||||
)
|
||||
} else {
|
||||
if (this.sectionStart < this.entityStart) {
|
||||
this.cbs.ontext(this.sectionStart, this.entityStart)
|
||||
|
@ -1085,7 +1101,11 @@ export default class Tokenizer {
|
|||
this.sectionStart = this.entityStart + consumed
|
||||
this.index = this.sectionStart - 1
|
||||
|
||||
this.cbs.ontextentity(fromCodePoint(cp), this.sectionStart)
|
||||
this.cbs.ontextentity(
|
||||
fromCodePoint(cp),
|
||||
this.entityStart,
|
||||
this.sectionStart
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
NodeTypes,
|
||||
ElementNode,
|
||||
TextNode,
|
||||
ErrorCodes,
|
||||
ElementTypes,
|
||||
InterpolationNode,
|
||||
AttributeNode,
|
||||
|
@ -302,15 +301,8 @@ describe('DOM parser', () => {
|
|||
|
||||
test('Strict end tag detection for textarea.', () => {
|
||||
const ast = parse(
|
||||
'<textarea>hello</textarea</textarea0></texTArea a="<>">',
|
||||
{
|
||||
...parserOptions,
|
||||
onError: err => {
|
||||
if (err.code !== ErrorCodes.END_TAG_WITH_ATTRIBUTES) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
'<textarea>hello</textarea</textarea0></texTArea>',
|
||||
parserOptions
|
||||
)
|
||||
const element = ast.children[0] as ElementNode
|
||||
const text = element.children[0] as TextNode
|
||||
|
|
Loading…
Reference in New Issue