wip: check duplicated attributes

This commit is contained in:
Evan You 2023-11-15 19:36:05 +08:00
parent ec33e61e87
commit 70edd1c61e
2 changed files with 39 additions and 31 deletions

View File

@ -143,6 +143,7 @@ export interface Callbacks {
onattribentity(codepoint: number): void
onattribend(quote: QuoteType, endIndex: number): void
onattribname(start: number, endIndex: number): void
onattribnameend(endIndex: number): void
ondirname(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
* recorded.
*/
public getPositionForIndex(index: number): Position {
public getPos(index: number): Position {
let line = 1
let column = index + 1
for (let i = this.newlines.length - 1; i >= 0; i--) {
@ -513,17 +514,13 @@ export default class Tokenizer {
private stateInAttributeName(c: number): void {
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
this.cbs.onattribname(this.sectionStart, this.index)
this.sectionStart = this.index
this.state = State.AfterAttributeName
this.stateAfterAttributeName(c)
this.handleAttributeNameEnd(c)
}
}
private stateInDirectiveName(c: number): void {
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
this.cbs.ondirname(this.sectionStart, this.index)
this.sectionStart = this.index
this.state = State.AfterAttributeName
this.stateAfterAttributeName(c)
this.handleAttributeNameEnd(c)
} else if (c === CharCodes.Colon) {
this.cbs.ondirname(this.sectionStart, this.index)
this.state = State.InDirectiveArg
@ -537,9 +534,7 @@ export default class Tokenizer {
private stateInDirectiveArg(c: number): void {
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
this.cbs.ondirarg(this.sectionStart, this.index)
this.sectionStart = this.index
this.state = State.AfterAttributeName
this.stateAfterAttributeName(c)
this.handleAttributeNameEnd(c)
} else if (c === CharCodes.LeftSqaure) {
this.state = State.InDirectiveDynamicArg
} else if (c === CharCodes.Dot) {
@ -558,14 +553,18 @@ export default class Tokenizer {
private stateInDirectiveModifier(c: number): void {
if (c === CharCodes.Eq || isEndOfTagSection(c)) {
this.cbs.ondirmodifier(this.sectionStart, this.index)
this.sectionStart = this.index
this.state = State.AfterAttributeName
this.stateAfterAttributeName(c)
this.handleAttributeNameEnd(c)
} else if (c === CharCodes.Dot) {
this.cbs.ondirmodifier(this.sectionStart, this.index)
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 {
if (c === CharCodes.Eq) {
this.state = State.BeforeAttributeValue

View File

@ -116,7 +116,6 @@ const tokenizer = new Tokenizer(
},
ondirname(start, end) {
// console.log('name ' + getSlice(start, end))
const raw = getSlice(start, end)
const name =
raw === '.' || raw === ':'
@ -135,8 +134,8 @@ const tokenizer = new Tokenizer(
loc: getLoc(start)
}
},
ondirarg(start, end) {
// console.log('arg ' + getSlice(start, end))
const arg = getSlice(start, end)
const isStatic = arg[0] !== `[`
;(currentProp as DirectiveNode).arg = {
@ -158,19 +157,28 @@ const tokenizer = new Tokenizer(
if (currentAttrStartIndex < 0) currentAttrStartIndex = start
currentAttrEndIndex = end
},
onattribentity(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) {
// TODO check duplicate
// if (currentAttrs.has(name)) {
// // emit error DUPLICATE_ATTRIBUTE
// } else {
// currentAttrs.add(name)
// }
if (currentElement) {
if (currentElement && currentProp) {
if (currentAttrValue) {
if (currentProp!.type === NodeTypes.ATTRIBUTE) {
if (currentProp.type === NodeTypes.ATTRIBUTE) {
// assign value
currentProp!.value = {
type: NodeTypes.TEXT,
@ -182,7 +190,7 @@ const tokenizer = new Tokenizer(
}
} else {
// directive
currentProp!.exp = {
currentProp.exp = {
type: NodeTypes.SIMPLE_EXPRESSION,
content: currentAttrValue,
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!)
}
currentAttrValue = ''
@ -232,7 +240,7 @@ function emitOpenTag(name: string, start: number) {
props: [],
children: [],
loc: {
start: tokenizer.getPositionForIndex(start - 1),
start: tokenizer.getPos(start - 1),
// @ts-expect-error to be attached on tag close
end: undefined,
source: ''
@ -273,8 +281,8 @@ function onText(content: string, start: number, end: number) {
type: NodeTypes.TEXT,
content,
loc: {
start: tokenizer.getPositionForIndex(start),
end: tokenizer.getPositionForIndex(end),
start: tokenizer.getPos(start),
end: tokenizer.getPos(end),
source: content
}
})
@ -287,7 +295,7 @@ function onCloseTag(el: ElementNode, end: number) {
while (currentInput.charCodeAt(end + offset) !== CharCodes.Gt) {
offset++
}
el.loc.end = tokenizer.getPositionForIndex(end + offset + 1)
el.loc.end = tokenizer.getPos(end + offset + 1)
// whitepsace management
el.children = condenseWhitespace(el.children)
}
@ -388,9 +396,9 @@ function getParent() {
function getLoc(start: number, end?: number): SourceLocation {
return {
start: tokenizer.getPositionForIndex(start),
start: tokenizer.getPos(start),
// @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)
const root = (currentRoot = createRoot([]))
tokenizer.parse(currentInput)
root.loc.end = tokenizer.getPos(input.length)
root.children = condenseWhitespace(root.children)
return root
}