]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: preserve source location convention in sfc mode for base parser
authorEvan You <yyx990803@gmail.com>
Sat, 25 Nov 2023 10:07:17 +0000 (18:07 +0800)
committerEvan You <yyx990803@gmail.com>
Sat, 25 Nov 2023 10:07:29 +0000 (18:07 +0800)
For compatibility w/ usage like https://github.com/vue-macros/vue-macros/blob/main/packages/setup-block/src/core/index.ts

packages/compiler-core/src/ast.ts
packages/compiler-core/src/parser.ts
packages/compiler-sfc/src/parse.ts

index 3569416a77a4d91031436ab76c12f61c39e06549..d16fc1f538d98a4c2b30ddb9398fa87858075d8e 100644 (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 {
index 20066193e490a257329fd02d811f05d94f54b3a6..9b87c3949dfbbf167fcf259967430caeaee97855 100644 (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) {
index a84a0816006842b586e5a106b86e0c7d031104ee..03971d431e8f47c7cdc93e711b491afce2929fb6 100644 (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) {