Просмотр исходного кода

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
Evan You 2 лет назад
Родитель
Сommit
08f0baa2ad

+ 1 - 0
packages/compiler-core/src/ast.ts

@@ -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 {

+ 18 - 13
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) {

+ 3 - 2
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<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) {