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
* 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--) {
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
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) {
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
},
ondirname(start, end) {
- // console.log('name ' + getSlice(start, end))
const raw = getSlice(start, end)
const name =
raw === '.' || raw === ':'
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 = {
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,
}
} else {
// directive
- currentProp!.exp = {
+ currentProp.exp = {
type: NodeTypes.SIMPLE_EXPRESSION,
content: currentAttrValue,
isStatic: false,
}
}
}
- currentProp!.loc.end = tokenizer.getPositionForIndex(end)
+ currentProp.loc.end = tokenizer.getPos(end)
currentElement.props.push(currentProp!)
}
currentAttrValue = ''
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: ''
type: NodeTypes.TEXT,
content,
loc: {
- start: tokenizer.getPositionForIndex(start),
- end: tokenizer.getPositionForIndex(end),
+ start: tokenizer.getPos(start),
+ end: tokenizer.getPos(end),
source: content
}
})
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)
}
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)
}
}
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
}