refactor: preserve source location convention in sfc mode for base parser

For compatibility w/ usage like https://github.com/vue-macros/vue-macros/blob/main/packages/setup-block/src/core/index.ts
This commit is contained in:
Evan You 2023-11-25 18:07:17 +08:00
parent be6cae7dac
commit 08f0baa2ad
3 changed files with 22 additions and 15 deletions

View File

@ -130,6 +130,7 @@ export interface BaseElementNode extends Node {
tagType: ElementTypes
props: Array<AttributeNode | DirectiveNode>
children: TemplateChildNode[]
innerLoc?: SourceLocation // only for SFC root level elements
}
export interface PlainElementNode extends BaseElementNode {

View File

@ -123,10 +123,6 @@ const tokenizer = new Tokenizer(stack, {
onopentagname(start, end) {
const name = getSlice(start, end)
// in SFC mode, root-level tags locations are for its inner content.
const startIndex = tokenizer.inSFCRoot
? end + fastForward(end, CharCodes.Gt) + 1
: start - 1
currentOpenTag = {
type: NodeTypes.ELEMENT,
tag: name,
@ -134,9 +130,16 @@ const tokenizer = new Tokenizer(stack, {
tagType: ElementTypes.ELEMENT, // will be refined on tag close
props: [],
children: [],
loc: getLoc(startIndex, end),
loc: getLoc(start - 1, end),
codegenNode: undefined
}
if (tokenizer.inSFCRoot) {
// in SFC mode, generate locations for root-level tags' inner content.
currentOpenTag.innerLoc = getLoc(
end + fastForward(end, CharCodes.Gt) + 1,
end
)
}
},
onopentagend(end) {
@ -571,20 +574,22 @@ function onText(content: string, start: number, end: number) {
function onCloseTag(el: ElementNode, end: number, isImplied = false) {
// attach end position
if (tokenizer.inSFCRoot) {
// SFC root tag, end position should be inner end
if (el.children.length) {
el.loc.end = extend({}, el.children[el.children.length - 1].loc.end)
} else {
el.loc.end = extend({}, el.loc.start)
}
} else if (isImplied) {
if (isImplied) {
// implied close, end should be backtracked to close
el.loc.end = tokenizer.getPos(backTrack(end, CharCodes.Lt))
} else {
el.loc.end = tokenizer.getPos(end + fastForward(end, CharCodes.Gt) + 1)
}
if (tokenizer.inSFCRoot) {
// SFC root tag, resolve inner end
if (el.children.length) {
el.innerLoc!.end = extend({}, el.children[el.children.length - 1].loc.end)
} else {
el.innerLoc!.end = extend({}, el.innerLoc!.start)
}
}
// refine element type
const { tag, ns } = el
if (!inVPre) {

View File

@ -290,11 +290,12 @@ function createBlock(
pad: SFCParseOptions['pad']
): SFCBlock {
const type = node.tag
const loc = node.innerLoc!
const attrs: Record<string, string | true> = {}
const block: SFCBlock = {
type,
content: source.slice(node.loc.start.offset, node.loc.end.offset),
loc: node.loc,
content: source.slice(loc.start.offset, loc.end.offset),
loc,
attrs
}
if (pad) {