wip: pass more compiler-dom tests

This commit is contained in:
Evan You 2023-11-19 10:39:11 +08:00
parent 1912af04e3
commit a1b10a21ac
3 changed files with 55 additions and 32 deletions

View File

@ -178,7 +178,7 @@ export enum QuoteType {
export interface Callbacks { export interface Callbacks {
ontext(start: number, endIndex: number): void 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 oninterpolation(start: number, endIndex: number): void
@ -188,7 +188,7 @@ export interface Callbacks {
onclosetag(start: number, endIndex: number): void onclosetag(start: number, endIndex: number): void
onattribdata(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 onattribend(quote: QuoteType, endIndex: number): void
onattribname(start: number, endIndex: number): void onattribname(start: number, endIndex: number): void
onattribnameend(endIndex: number): void onattribnameend(endIndex: number): void
@ -325,6 +325,9 @@ export default class Tokenizer {
} else { } else {
this.delimiterIndex++ this.delimiterIndex++
} }
} else if (this.inRCDATA) {
this.state = State.InSpecialTag
this.stateInSpecialTag(c)
} else { } else {
this.state = State.Text this.state = State.Text
this.stateText(c) this.stateText(c)
@ -343,7 +346,11 @@ export default class Tokenizer {
if (c === this.delimiterClose[this.delimiterIndex]) { if (c === this.delimiterClose[this.delimiterIndex]) {
if (this.delimiterIndex === this.delimiterClose.length - 1) { if (this.delimiterIndex === this.delimiterClose.length - 1) {
this.cbs.oninterpolation(this.sectionStart, this.index + 1) this.cbs.oninterpolation(this.sectionStart, this.index + 1)
if (this.inRCDATA) {
this.state = State.InSpecialTag
} else {
this.state = State.Text this.state = State.Text
}
this.sectionStart = this.index + 1 this.sectionStart = this.index + 1
} else { } else {
this.delimiterIndex++ this.delimiterIndex++
@ -410,6 +417,11 @@ export default class Tokenizer {
// We have to parse entities in <title> and <textarea> tags. // We have to parse entities in <title> and <textarea> tags.
if (!__BROWSER__ && c === CharCodes.Amp) { if (!__BROWSER__ && c === CharCodes.Amp) {
this.startEntity() 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)) { } else if (this.fastForwardTo(CharCodes.Lt)) {
// Outside of <title> and <textarea> tags, we can fast-forward. // Outside of <title> and <textarea> tags, we can fast-forward.
@ -1077,7 +1089,11 @@ export default class Tokenizer {
this.sectionStart = this.entityStart + consumed this.sectionStart = this.entityStart + consumed
this.index = this.sectionStart - 1 this.index = this.sectionStart - 1
this.cbs.onattribentity(fromCodePoint(cp)) this.cbs.onattribentity(
fromCodePoint(cp),
this.entityStart,
this.sectionStart
)
} else { } else {
if (this.sectionStart < this.entityStart) { if (this.sectionStart < this.entityStart) {
this.cbs.ontext(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.sectionStart = this.entityStart + consumed
this.index = this.sectionStart - 1 this.index = this.sectionStart - 1
this.cbs.ontextentity(fromCodePoint(cp), this.sectionStart) this.cbs.ontextentity(
fromCodePoint(cp),
this.entityStart,
this.sectionStart
)
} }
} }
} }

View File

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

View File

@ -3,7 +3,6 @@ import {
NodeTypes, NodeTypes,
ElementNode, ElementNode,
TextNode, TextNode,
ErrorCodes,
ElementTypes, ElementTypes,
InterpolationNode, InterpolationNode,
AttributeNode, AttributeNode,
@ -302,15 +301,8 @@ describe('DOM parser', () => {
test('Strict end tag detection for textarea.', () => { test('Strict end tag detection for textarea.', () => {
const ast = parse( const ast = parse(
'<textarea>hello</textarea</textarea0></texTArea a="<>">', '<textarea>hello</textarea</textarea0></texTArea>',
{ parserOptions
...parserOptions,
onError: err => {
if (err.code !== ErrorCodes.END_TAG_WITH_ATTRIBUTES) {
throw err
}
}
}
) )
const element = ast.children[0] as ElementNode const element = ast.children[0] as ElementNode
const text = element.children[0] as TextNode const text = element.children[0] as TextNode