From: Evan You Date: Sat, 25 Nov 2023 10:07:17 +0000 (+0800) Subject: refactor: preserve source location convention in sfc mode for base parser X-Git-Tag: v3.4.0-alpha.2~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=08f0baa2ad66890bbc2f8eb41129a9556d1834a6;p=thirdparty%2Fvuejs%2Fcore.git 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 --- diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts index 3569416a77..d16fc1f538 100644 --- a/packages/compiler-core/src/ast.ts +++ b/packages/compiler-core/src/ast.ts @@ -130,6 +130,7 @@ export interface BaseElementNode extends Node { tagType: ElementTypes props: Array children: TemplateChildNode[] + innerLoc?: SourceLocation // only for SFC root level elements } export interface PlainElementNode extends BaseElementNode { diff --git a/packages/compiler-core/src/parser.ts b/packages/compiler-core/src/parser.ts index 20066193e4..9b87c3949d 100644 --- a/packages/compiler-core/src/parser.ts +++ b/packages/compiler-core/src/parser.ts @@ -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) { diff --git a/packages/compiler-sfc/src/parse.ts b/packages/compiler-sfc/src/parse.ts index a84a081600..03971d431e 100644 --- a/packages/compiler-sfc/src/parse.ts +++ b/packages/compiler-sfc/src/parse.ts @@ -290,11 +290,12 @@ function createBlock( pad: SFCParseOptions['pad'] ): SFCBlock { const type = node.tag + const loc = node.innerLoc! const attrs: Record = {} 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) {