mirror of https://github.com/vuejs/core.git
wip: v-pre handling
This commit is contained in:
parent
1a1f680536
commit
c342433cb5
|
@ -191,6 +191,7 @@ export interface DirectiveNode extends Node {
|
||||||
exp: ExpressionNode | undefined
|
exp: ExpressionNode | undefined
|
||||||
arg: ExpressionNode | undefined
|
arg: ExpressionNode | undefined
|
||||||
modifiers: string[]
|
modifiers: string[]
|
||||||
|
raw?: string
|
||||||
/**
|
/**
|
||||||
* optional property to cache the expression parse result for v-for
|
* optional property to cache the expression parse result for v-for
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -282,6 +282,7 @@ export default class Tokenizer {
|
||||||
this.cbs.oninterpolation(this.sectionStart, this.index)
|
this.cbs.oninterpolation(this.sectionStart, this.index)
|
||||||
this.state = State.Text
|
this.state = State.Text
|
||||||
this.sectionStart = this.index
|
this.sectionStart = this.index
|
||||||
|
this.stateText(this.buffer.charCodeAt(this.index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
Namespaces,
|
Namespaces,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
RootNode,
|
RootNode,
|
||||||
|
SimpleExpressionNode,
|
||||||
SourceLocation,
|
SourceLocation,
|
||||||
TemplateChildNode,
|
TemplateChildNode,
|
||||||
createRoot
|
createRoot
|
||||||
|
@ -67,7 +68,8 @@ let currentAttrStartIndex = -1
|
||||||
let currentAttrEndIndex = -1
|
let currentAttrEndIndex = -1
|
||||||
let currentAttrs: Set<string> = new Set()
|
let currentAttrs: Set<string> = new Set()
|
||||||
let inPre = 0
|
let inPre = 0
|
||||||
// let inVPre = 0
|
let inVPre = false
|
||||||
|
let currentElementIsVPreBoundary = false
|
||||||
const stack: ElementNode[] = []
|
const stack: ElementNode[] = []
|
||||||
|
|
||||||
const tokenizer = new Tokenizer({
|
const tokenizer = new Tokenizer({
|
||||||
|
@ -80,6 +82,9 @@ const tokenizer = new Tokenizer({
|
||||||
},
|
},
|
||||||
|
|
||||||
oninterpolation(start, end) {
|
oninterpolation(start, end) {
|
||||||
|
if (inVPre) {
|
||||||
|
return onText(getSlice(start, end), start, end)
|
||||||
|
}
|
||||||
let innerStart = start + tokenizer.delimiterOpen.length
|
let innerStart = start + tokenizer.delimiterOpen.length
|
||||||
let innerEnd = end - tokenizer.delimiterClose.length
|
let innerEnd = end - tokenizer.delimiterClose.length
|
||||||
while (isWhitespace(currentInput.charCodeAt(innerStart))) {
|
while (isWhitespace(currentInput.charCodeAt(innerStart))) {
|
||||||
|
@ -103,7 +108,24 @@ const tokenizer = new Tokenizer({
|
||||||
},
|
},
|
||||||
|
|
||||||
onopentagname(start, end) {
|
onopentagname(start, end) {
|
||||||
emitOpenTag(getSlice(start, end), start)
|
const name = getSlice(start, end)
|
||||||
|
currentElement = {
|
||||||
|
type: NodeTypes.ELEMENT,
|
||||||
|
tag: name,
|
||||||
|
ns: currentOptions.getNamespace(name, getParent()),
|
||||||
|
// TODO refine tag type
|
||||||
|
tagType: ElementTypes.ELEMENT,
|
||||||
|
props: [],
|
||||||
|
children: [],
|
||||||
|
loc: {
|
||||||
|
start: tokenizer.getPos(start - 1),
|
||||||
|
// @ts-expect-error to be attached on tag close
|
||||||
|
end: undefined,
|
||||||
|
source: ''
|
||||||
|
},
|
||||||
|
codegenNode: undefined
|
||||||
|
}
|
||||||
|
currentAttrs.clear()
|
||||||
},
|
},
|
||||||
|
|
||||||
onopentagend(end) {
|
onopentagend(end) {
|
||||||
|
@ -138,40 +160,72 @@ const tokenizer = new Tokenizer({
|
||||||
|
|
||||||
ondirname(start, end) {
|
ondirname(start, end) {
|
||||||
const raw = getSlice(start, end)
|
const raw = getSlice(start, end)
|
||||||
const name =
|
if (inVPre) {
|
||||||
raw === '.' || raw === ':'
|
currentProp = {
|
||||||
? 'bind'
|
type: NodeTypes.ATTRIBUTE,
|
||||||
: raw === '@'
|
name: raw,
|
||||||
? 'on'
|
value: undefined,
|
||||||
: raw === '#'
|
loc: getLoc(start)
|
||||||
? 'slot'
|
}
|
||||||
: raw.slice(2)
|
} else {
|
||||||
currentProp = {
|
const name =
|
||||||
type: NodeTypes.DIRECTIVE,
|
raw === '.' || raw === ':'
|
||||||
name,
|
? 'bind'
|
||||||
exp: undefined,
|
: raw === '@'
|
||||||
arg: undefined,
|
? 'on'
|
||||||
modifiers: [],
|
: raw === '#'
|
||||||
loc: getLoc(start)
|
? 'slot'
|
||||||
|
: raw.slice(2)
|
||||||
|
currentProp = {
|
||||||
|
type: NodeTypes.DIRECTIVE,
|
||||||
|
name,
|
||||||
|
raw,
|
||||||
|
exp: undefined,
|
||||||
|
arg: undefined,
|
||||||
|
modifiers: [],
|
||||||
|
loc: getLoc(start)
|
||||||
|
}
|
||||||
|
if (name === 'pre') {
|
||||||
|
inVPre = true
|
||||||
|
currentElementIsVPreBoundary = true
|
||||||
|
// force current element type
|
||||||
|
currentElement!.tagType = ElementTypes.ELEMENT
|
||||||
|
// convert dirs before this one to attributes
|
||||||
|
const props = currentElement!.props
|
||||||
|
for (let i = 0; i < props.length; i++) {
|
||||||
|
if (props[i].type === NodeTypes.DIRECTIVE) {
|
||||||
|
props[i] = dirToAttr(props[i] as DirectiveNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ondirarg(start, end) {
|
ondirarg(start, end) {
|
||||||
const arg = getSlice(start, end)
|
const arg = getSlice(start, end)
|
||||||
const isStatic = arg[0] !== `[`
|
if (inVPre) {
|
||||||
;(currentProp as DirectiveNode).arg = {
|
;(currentProp as AttributeNode).name += arg
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
} else {
|
||||||
content: arg,
|
const isStatic = arg[0] !== `[`
|
||||||
isStatic,
|
;(currentProp as DirectiveNode).arg = {
|
||||||
constType: isStatic
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
? ConstantTypes.CAN_STRINGIFY
|
content: arg,
|
||||||
: ConstantTypes.NOT_CONSTANT,
|
isStatic,
|
||||||
loc: getLoc(start, end)
|
constType: isStatic
|
||||||
|
? ConstantTypes.CAN_STRINGIFY
|
||||||
|
: ConstantTypes.NOT_CONSTANT,
|
||||||
|
loc: getLoc(start, end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ondirmodifier(start, end) {
|
ondirmodifier(start, end) {
|
||||||
;(currentProp as DirectiveNode).modifiers.push(getSlice(start, end))
|
const mod = getSlice(start, end)
|
||||||
|
if (inVPre) {
|
||||||
|
;(currentProp as AttributeNode).name += '.' + mod
|
||||||
|
} else {
|
||||||
|
;(currentProp as DirectiveNode).modifiers.push(mod)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onattribdata(start, end) {
|
onattribdata(start, end) {
|
||||||
|
@ -188,6 +242,9 @@ const tokenizer = new Tokenizer({
|
||||||
// check duplicate attrs
|
// check duplicate attrs
|
||||||
const start = currentProp!.loc.start.offset
|
const start = currentProp!.loc.start.offset
|
||||||
const name = getSlice(start, end)
|
const name = getSlice(start, end)
|
||||||
|
if (currentProp!.type === NodeTypes.DIRECTIVE) {
|
||||||
|
currentProp!.raw = name
|
||||||
|
}
|
||||||
if (currentAttrs.has(name)) {
|
if (currentAttrs.has(name)) {
|
||||||
currentProp = null
|
currentProp = null
|
||||||
// TODO emit error DUPLICATE_ATTRIBUTE
|
// TODO emit error DUPLICATE_ATTRIBUTE
|
||||||
|
@ -225,7 +282,12 @@ const tokenizer = new Tokenizer({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentProp.loc.end = tokenizer.getPos(end)
|
currentProp.loc.end = tokenizer.getPos(end)
|
||||||
currentElement.props.push(currentProp!)
|
if (
|
||||||
|
currentProp.type !== NodeTypes.DIRECTIVE ||
|
||||||
|
currentProp.name !== 'pre'
|
||||||
|
) {
|
||||||
|
currentElement.props.push(currentProp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currentAttrValue = ''
|
currentAttrValue = ''
|
||||||
currentAttrStartIndex = currentAttrEndIndex = -1
|
currentAttrStartIndex = currentAttrEndIndex = -1
|
||||||
|
@ -251,26 +313,6 @@ function getSlice(start: number, end: number) {
|
||||||
return currentInput.slice(start, end)
|
return currentInput.slice(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitOpenTag(name: string, start: number) {
|
|
||||||
currentElement = {
|
|
||||||
type: NodeTypes.ELEMENT,
|
|
||||||
tag: name,
|
|
||||||
ns: currentOptions.getNamespace(name, getParent()),
|
|
||||||
// TODO refine tag type
|
|
||||||
tagType: ElementTypes.ELEMENT,
|
|
||||||
props: [],
|
|
||||||
children: [],
|
|
||||||
loc: {
|
|
||||||
start: tokenizer.getPos(start - 1),
|
|
||||||
// @ts-expect-error to be attached on tag close
|
|
||||||
end: undefined,
|
|
||||||
source: ''
|
|
||||||
},
|
|
||||||
codegenNode: undefined
|
|
||||||
}
|
|
||||||
currentAttrs.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
function endOpenTag(end: number) {
|
function endOpenTag(end: number) {
|
||||||
addNode(currentElement!)
|
addNode(currentElement!)
|
||||||
const name = currentElement!.tag
|
const name = currentElement!.tag
|
||||||
|
@ -299,7 +341,7 @@ function onText(content: string, start: number, end: number) {
|
||||||
if (lastNode?.type === NodeTypes.TEXT) {
|
if (lastNode?.type === NodeTypes.TEXT) {
|
||||||
// merge
|
// merge
|
||||||
lastNode.content += content
|
lastNode.content += content
|
||||||
// TODO update loc
|
lastNode.loc.end = tokenizer.getPos(end)
|
||||||
} else {
|
} else {
|
||||||
parent.children.push({
|
parent.children.push({
|
||||||
type: NodeTypes.TEXT,
|
type: NodeTypes.TEXT,
|
||||||
|
@ -325,6 +367,10 @@ function onCloseTag(el: ElementNode, end: number) {
|
||||||
if (currentOptions.isPreTag(el.tag)) {
|
if (currentOptions.isPreTag(el.tag)) {
|
||||||
inPre--
|
inPre--
|
||||||
}
|
}
|
||||||
|
if (currentElementIsVPreBoundary) {
|
||||||
|
inVPre = false
|
||||||
|
currentElementIsVPreBoundary = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const windowsNewlineRE = /\r\n/g
|
const windowsNewlineRE = /\r\n/g
|
||||||
|
@ -429,6 +475,31 @@ function getLoc(start: number, end?: number): SourceLocation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dirToAttr(dir: DirectiveNode): AttributeNode {
|
||||||
|
const attr: AttributeNode = {
|
||||||
|
type: NodeTypes.ATTRIBUTE,
|
||||||
|
name: dir.raw!,
|
||||||
|
value: undefined,
|
||||||
|
loc: dir.loc
|
||||||
|
}
|
||||||
|
if (dir.exp) {
|
||||||
|
// account for quotes
|
||||||
|
const loc = dir.exp.loc
|
||||||
|
if (loc.end.offset < dir.loc.end.offset) {
|
||||||
|
loc.start.offset--
|
||||||
|
loc.start.column--
|
||||||
|
loc.end.offset++
|
||||||
|
loc.end.column++
|
||||||
|
}
|
||||||
|
attr.value = {
|
||||||
|
type: NodeTypes.TEXT,
|
||||||
|
content: (dir.exp as SimpleExpressionNode).content,
|
||||||
|
loc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return attr
|
||||||
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
tokenizer.reset()
|
tokenizer.reset()
|
||||||
currentElement = null
|
currentElement = null
|
||||||
|
|
Loading…
Reference in New Issue