mirror of https://github.com/vuejs/core.git
wip: check duplicated attributes
This commit is contained in:
parent
ec33e61e87
commit
70edd1c61e
|
@ -143,6 +143,7 @@ export interface Callbacks {
|
||||||
onattribentity(codepoint: number): void
|
onattribentity(codepoint: 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
|
||||||
|
|
||||||
ondirname(start: number, endIndex: number): void
|
ondirname(start: number, endIndex: number): void
|
||||||
ondirarg(start: number, endIndex: number): void
|
ondirarg(start: number, endIndex: number): void
|
||||||
|
@ -218,7 +219,7 @@ export default class Tokenizer {
|
||||||
* processed index, so all the newlines up to this index should have been
|
* processed index, so all the newlines up to this index should have been
|
||||||
* recorded.
|
* recorded.
|
||||||
*/
|
*/
|
||||||
public getPositionForIndex(index: number): Position {
|
public getPos(index: number): Position {
|
||||||
let line = 1
|
let line = 1
|
||||||
let column = index + 1
|
let column = index + 1
|
||||||
for (let i = this.newlines.length - 1; i >= 0; i--) {
|
for (let i = this.newlines.length - 1; i >= 0; i--) {
|
||||||
|
@ -513,17 +514,13 @@ export default class Tokenizer {
|
||||||
private stateInAttributeName(c: number): void {
|
private stateInAttributeName(c: number): void {
|
||||||
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
||||||
this.cbs.onattribname(this.sectionStart, this.index)
|
this.cbs.onattribname(this.sectionStart, this.index)
|
||||||
this.sectionStart = this.index
|
this.handleAttributeNameEnd(c)
|
||||||
this.state = State.AfterAttributeName
|
|
||||||
this.stateAfterAttributeName(c)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private stateInDirectiveName(c: number): void {
|
private stateInDirectiveName(c: number): void {
|
||||||
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
||||||
this.cbs.ondirname(this.sectionStart, this.index)
|
this.cbs.ondirname(this.sectionStart, this.index)
|
||||||
this.sectionStart = this.index
|
this.handleAttributeNameEnd(c)
|
||||||
this.state = State.AfterAttributeName
|
|
||||||
this.stateAfterAttributeName(c)
|
|
||||||
} else if (c === CharCodes.Colon) {
|
} else if (c === CharCodes.Colon) {
|
||||||
this.cbs.ondirname(this.sectionStart, this.index)
|
this.cbs.ondirname(this.sectionStart, this.index)
|
||||||
this.state = State.InDirectiveArg
|
this.state = State.InDirectiveArg
|
||||||
|
@ -537,9 +534,7 @@ export default class Tokenizer {
|
||||||
private stateInDirectiveArg(c: number): void {
|
private stateInDirectiveArg(c: number): void {
|
||||||
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
||||||
this.cbs.ondirarg(this.sectionStart, this.index)
|
this.cbs.ondirarg(this.sectionStart, this.index)
|
||||||
this.sectionStart = this.index
|
this.handleAttributeNameEnd(c)
|
||||||
this.state = State.AfterAttributeName
|
|
||||||
this.stateAfterAttributeName(c)
|
|
||||||
} else if (c === CharCodes.LeftSqaure) {
|
} else if (c === CharCodes.LeftSqaure) {
|
||||||
this.state = State.InDirectiveDynamicArg
|
this.state = State.InDirectiveDynamicArg
|
||||||
} else if (c === CharCodes.Dot) {
|
} else if (c === CharCodes.Dot) {
|
||||||
|
@ -558,14 +553,18 @@ export default class Tokenizer {
|
||||||
private stateInDirectiveModifier(c: number): void {
|
private stateInDirectiveModifier(c: number): void {
|
||||||
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
|
||||||
this.cbs.ondirmodifier(this.sectionStart, this.index)
|
this.cbs.ondirmodifier(this.sectionStart, this.index)
|
||||||
this.sectionStart = this.index
|
this.handleAttributeNameEnd(c)
|
||||||
this.state = State.AfterAttributeName
|
|
||||||
this.stateAfterAttributeName(c)
|
|
||||||
} else if (c === CharCodes.Dot) {
|
} else if (c === CharCodes.Dot) {
|
||||||
this.cbs.ondirmodifier(this.sectionStart, this.index)
|
this.cbs.ondirmodifier(this.sectionStart, this.index)
|
||||||
this.sectionStart = this.index + 1
|
this.sectionStart = this.index + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private handleAttributeNameEnd(c: number): void {
|
||||||
|
this.sectionStart = this.index
|
||||||
|
this.state = State.AfterAttributeName
|
||||||
|
this.cbs.onattribnameend(this.index)
|
||||||
|
this.stateAfterAttributeName(c)
|
||||||
|
}
|
||||||
private stateAfterAttributeName(c: number): void {
|
private stateAfterAttributeName(c: number): void {
|
||||||
if (c === CharCodes.Eq) {
|
if (c === CharCodes.Eq) {
|
||||||
this.state = State.BeforeAttributeValue
|
this.state = State.BeforeAttributeValue
|
||||||
|
|
|
@ -116,7 +116,6 @@ const tokenizer = new Tokenizer(
|
||||||
},
|
},
|
||||||
|
|
||||||
ondirname(start, end) {
|
ondirname(start, end) {
|
||||||
// console.log('name ' + getSlice(start, end))
|
|
||||||
const raw = getSlice(start, end)
|
const raw = getSlice(start, end)
|
||||||
const name =
|
const name =
|
||||||
raw === '.' || raw === ':'
|
raw === '.' || raw === ':'
|
||||||
|
@ -135,8 +134,8 @@ const tokenizer = new Tokenizer(
|
||||||
loc: getLoc(start)
|
loc: getLoc(start)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ondirarg(start, end) {
|
ondirarg(start, end) {
|
||||||
// console.log('arg ' + getSlice(start, end))
|
|
||||||
const arg = getSlice(start, end)
|
const arg = getSlice(start, end)
|
||||||
const isStatic = arg[0] !== `[`
|
const isStatic = arg[0] !== `[`
|
||||||
;(currentProp as DirectiveNode).arg = {
|
;(currentProp as DirectiveNode).arg = {
|
||||||
|
@ -158,19 +157,28 @@ const tokenizer = new Tokenizer(
|
||||||
if (currentAttrStartIndex < 0) currentAttrStartIndex = start
|
if (currentAttrStartIndex < 0) currentAttrStartIndex = start
|
||||||
currentAttrEndIndex = end
|
currentAttrEndIndex = end
|
||||||
},
|
},
|
||||||
|
|
||||||
onattribentity(codepoint) {
|
onattribentity(codepoint) {
|
||||||
currentAttrValue += fromCodePoint(codepoint)
|
currentAttrValue += fromCodePoint(codepoint)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onattribnameend(end) {
|
||||||
|
// check duplicate attrs
|
||||||
|
const start = currentProp!.loc.start.offset
|
||||||
|
const name = getSlice(start, end)
|
||||||
|
if (currentAttrs.has(name)) {
|
||||||
|
currentProp = null
|
||||||
|
// TODO emit error DUPLICATE_ATTRIBUTE
|
||||||
|
throw new Error(`duplicate attr ${name}`)
|
||||||
|
} else {
|
||||||
|
currentAttrs.add(name)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
onattribend(quote, end) {
|
onattribend(quote, end) {
|
||||||
// TODO check duplicate
|
if (currentElement && currentProp) {
|
||||||
// if (currentAttrs.has(name)) {
|
|
||||||
// // emit error DUPLICATE_ATTRIBUTE
|
|
||||||
// } else {
|
|
||||||
// currentAttrs.add(name)
|
|
||||||
// }
|
|
||||||
if (currentElement) {
|
|
||||||
if (currentAttrValue) {
|
if (currentAttrValue) {
|
||||||
if (currentProp!.type === NodeTypes.ATTRIBUTE) {
|
if (currentProp.type === NodeTypes.ATTRIBUTE) {
|
||||||
// assign value
|
// assign value
|
||||||
currentProp!.value = {
|
currentProp!.value = {
|
||||||
type: NodeTypes.TEXT,
|
type: NodeTypes.TEXT,
|
||||||
|
@ -182,7 +190,7 @@ const tokenizer = new Tokenizer(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// directive
|
// directive
|
||||||
currentProp!.exp = {
|
currentProp.exp = {
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||||
content: currentAttrValue,
|
content: currentAttrValue,
|
||||||
isStatic: false,
|
isStatic: false,
|
||||||
|
@ -194,7 +202,7 @@ const tokenizer = new Tokenizer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
currentProp!.loc.end = tokenizer.getPositionForIndex(end)
|
currentProp.loc.end = tokenizer.getPos(end)
|
||||||
currentElement.props.push(currentProp!)
|
currentElement.props.push(currentProp!)
|
||||||
}
|
}
|
||||||
currentAttrValue = ''
|
currentAttrValue = ''
|
||||||
|
@ -232,7 +240,7 @@ function emitOpenTag(name: string, start: number) {
|
||||||
props: [],
|
props: [],
|
||||||
children: [],
|
children: [],
|
||||||
loc: {
|
loc: {
|
||||||
start: tokenizer.getPositionForIndex(start - 1),
|
start: tokenizer.getPos(start - 1),
|
||||||
// @ts-expect-error to be attached on tag close
|
// @ts-expect-error to be attached on tag close
|
||||||
end: undefined,
|
end: undefined,
|
||||||
source: ''
|
source: ''
|
||||||
|
@ -273,8 +281,8 @@ function onText(content: string, start: number, end: number) {
|
||||||
type: NodeTypes.TEXT,
|
type: NodeTypes.TEXT,
|
||||||
content,
|
content,
|
||||||
loc: {
|
loc: {
|
||||||
start: tokenizer.getPositionForIndex(start),
|
start: tokenizer.getPos(start),
|
||||||
end: tokenizer.getPositionForIndex(end),
|
end: tokenizer.getPos(end),
|
||||||
source: content
|
source: content
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -287,7 +295,7 @@ function onCloseTag(el: ElementNode, end: number) {
|
||||||
while (currentInput.charCodeAt(end + offset) !== CharCodes.Gt) {
|
while (currentInput.charCodeAt(end + offset) !== CharCodes.Gt) {
|
||||||
offset++
|
offset++
|
||||||
}
|
}
|
||||||
el.loc.end = tokenizer.getPositionForIndex(end + offset + 1)
|
el.loc.end = tokenizer.getPos(end + offset + 1)
|
||||||
// whitepsace management
|
// whitepsace management
|
||||||
el.children = condenseWhitespace(el.children)
|
el.children = condenseWhitespace(el.children)
|
||||||
}
|
}
|
||||||
|
@ -388,9 +396,9 @@ function getParent() {
|
||||||
|
|
||||||
function getLoc(start: number, end?: number): SourceLocation {
|
function getLoc(start: number, end?: number): SourceLocation {
|
||||||
return {
|
return {
|
||||||
start: tokenizer.getPositionForIndex(start),
|
start: tokenizer.getPos(start),
|
||||||
// @ts-expect-error allow late attachment
|
// @ts-expect-error allow late attachment
|
||||||
end: end && tokenizer.getPositionForIndex(end)
|
end: end && tokenizer.getPos(end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,6 +419,7 @@ export function baseParse(input: string, options?: ParserOptions): RootNode {
|
||||||
currentOptions = extend({}, defaultParserOptions, options)
|
currentOptions = extend({}, defaultParserOptions, options)
|
||||||
const root = (currentRoot = createRoot([]))
|
const root = (currentRoot = createRoot([]))
|
||||||
tokenizer.parse(currentInput)
|
tokenizer.parse(currentInput)
|
||||||
|
root.loc.end = tokenizer.getPos(input.length)
|
||||||
root.children = condenseWhitespace(root.children)
|
root.children = condenseWhitespace(root.children)
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue