]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
chore: group parser edge case tests
authorEvan You <yyx990803@gmail.com>
Thu, 30 Nov 2023 14:39:55 +0000 (22:39 +0800)
committerEvan You <yyx990803@gmail.com>
Thu, 30 Nov 2023 14:39:55 +0000 (22:39 +0800)
packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
packages/compiler-core/__tests__/parse.spec.ts

index 92403845087d6f9dba870e179e72426c0779829c..8886ce33717d0df489ebdbbdd53b7e8246ebde81 100644 (file)
@@ -1,19 +1,45 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[cdata]]></template> 1`] = `
+exports[`compiler: parse > Edge Cases > invalid html 1`] = `
 {
   "cached": 0,
   "children": [
     {
-      "children": [],
+      "children": [
+        {
+          "children": [],
+          "codegenNode": undefined,
+          "loc": {
+            "end": {
+              "column": 1,
+              "line": 3,
+              "offset": 13,
+            },
+            "source": "<span>
+",
+            "start": {
+              "column": 1,
+              "line": 2,
+              "offset": 6,
+            },
+          },
+          "ns": 0,
+          "props": [],
+          "tag": "span",
+          "tagType": 0,
+          "type": 1,
+        },
+      ],
       "codegenNode": undefined,
       "loc": {
         "end": {
-          "column": 39,
-          "line": 1,
-          "offset": 38,
+          "column": 7,
+          "line": 3,
+          "offset": 19,
         },
-        "source": "<template><![CDATA[cdata]]></template>",
+        "source": "<div>
+<span>
+</div>",
         "start": {
           "column": 1,
           "line": 1,
@@ -22,7 +48,7 @@ exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[c
       },
       "ns": 0,
       "props": [],
-      "tag": "template",
+      "tag": "div",
       "tagType": 0,
       "type": 1,
     },
@@ -35,87 +61,192 @@ exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[c
   "imports": [],
   "loc": {
     "end": {
-      "column": 39,
-      "line": 1,
-      "offset": 38,
+      "column": 8,
+      "line": 4,
+      "offset": 27,
     },
-    "source": "<template><![CDATA[cdata]]></template>",
+    "source": "<div>
+<span>
+</div>
+</span>",
     "start": {
       "column": 1,
       "line": 1,
       "offset": 0,
     },
   },
-  "source": "<template><![CDATA[cdata]]></template>",
+  "source": "<div>
+<span>
+</div>
+</span>",
   "temps": 0,
   "type": 0,
 }
 `;
 
-exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><svg><![CDATA[cdata]]></svg></template> 1`] = `
+exports[`compiler: parse > Edge Cases > self closing multiple tag 1`] = `
 {
   "cached": 0,
   "children": [
     {
-      "children": [
+      "children": [],
+      "codegenNode": undefined,
+      "isSelfClosing": true,
+      "loc": {
+        "end": {
+          "column": 37,
+          "line": 1,
+          "offset": 36,
+        },
+        "source": "<div :class=\\"{ some: condition }\\" />",
+        "start": {
+          "column": 1,
+          "line": 1,
+          "offset": 0,
+        },
+      },
+      "ns": 0,
+      "props": [
         {
-          "children": [
-            {
-              "content": "cdata",
-              "loc": {
-                "end": {
-                  "column": 30,
-                  "line": 1,
-                  "offset": 29,
-                },
-                "source": "cdata",
-                "start": {
-                  "column": 25,
-                  "line": 1,
-                  "offset": 24,
-                },
+          "arg": {
+            "constType": 3,
+            "content": "class",
+            "isStatic": true,
+            "loc": {
+              "end": {
+                "column": 12,
+                "line": 1,
+                "offset": 11,
+              },
+              "source": "class",
+              "start": {
+                "column": 7,
+                "line": 1,
+                "offset": 6,
               },
-              "type": 2,
             },
-          ],
-          "codegenNode": undefined,
+            "type": 4,
+          },
+          "exp": {
+            "constType": 0,
+            "content": "{ some: condition }",
+            "isStatic": false,
+            "loc": {
+              "end": {
+                "column": 33,
+                "line": 1,
+                "offset": 32,
+              },
+              "source": "{ some: condition }",
+              "start": {
+                "column": 14,
+                "line": 1,
+                "offset": 13,
+              },
+            },
+            "type": 4,
+          },
           "loc": {
             "end": {
-              "column": 39,
+              "column": 34,
               "line": 1,
-              "offset": 38,
+              "offset": 33,
             },
-            "source": "<svg><![CDATA[cdata]]></svg>",
+            "source": ":class=\\"{ some: condition }\\"",
             "start": {
-              "column": 11,
+              "column": 6,
               "line": 1,
-              "offset": 10,
+              "offset": 5,
             },
           },
-          "ns": 1,
-          "props": [],
-          "tag": "svg",
-          "tagType": 0,
-          "type": 1,
+          "modifiers": [],
+          "name": "bind",
+          "rawName": ":class",
+          "type": 7,
         },
       ],
+      "tag": "div",
+      "tagType": 0,
+      "type": 1,
+    },
+    {
+      "children": [],
       "codegenNode": undefined,
+      "isSelfClosing": true,
       "loc": {
         "end": {
-          "column": 50,
-          "line": 1,
-          "offset": 49,
+          "column": 37,
+          "line": 2,
+          "offset": 73,
         },
-        "source": "<template><svg><![CDATA[cdata]]></svg></template>",
+        "source": "<p v-bind:style=\\"{ color: 'red' }\\"/>",
         "start": {
           "column": 1,
-          "line": 1,
-          "offset": 0,
+          "line": 2,
+          "offset": 37,
         },
       },
       "ns": 0,
-      "props": [],
-      "tag": "template",
+      "props": [
+        {
+          "arg": {
+            "constType": 3,
+            "content": "style",
+            "isStatic": true,
+            "loc": {
+              "end": {
+                "column": 16,
+                "line": 2,
+                "offset": 52,
+              },
+              "source": "style",
+              "start": {
+                "column": 11,
+                "line": 2,
+                "offset": 47,
+              },
+            },
+            "type": 4,
+          },
+          "exp": {
+            "constType": 0,
+            "content": "{ color: 'red' }",
+            "isStatic": false,
+            "loc": {
+              "end": {
+                "column": 34,
+                "line": 2,
+                "offset": 70,
+              },
+              "source": "{ color: 'red' }",
+              "start": {
+                "column": 18,
+                "line": 2,
+                "offset": 54,
+              },
+            },
+            "type": 4,
+          },
+          "loc": {
+            "end": {
+              "column": 35,
+              "line": 2,
+              "offset": 71,
+            },
+            "source": "v-bind:style=\\"{ color: 'red' }\\"",
+            "start": {
+              "column": 4,
+              "line": 2,
+              "offset": 40,
+            },
+          },
+          "modifiers": [],
+          "name": "bind",
+          "rawName": "v-bind:style",
+          "type": 7,
+        },
+      ],
+      "tag": "p",
       "tagType": 0,
       "type": 1,
     },
@@ -128,24 +259,26 @@ exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><svg><![CD
   "imports": [],
   "loc": {
     "end": {
-      "column": 50,
-      "line": 1,
-      "offset": 49,
+      "column": 37,
+      "line": 2,
+      "offset": 73,
     },
-    "source": "<template><svg><![CDATA[cdata]]></svg></template>",
+    "source": "<div :class=\\"{ some: condition }\\" />
+<p v-bind:style=\\"{ color: 'red' }\\"/>",
     "start": {
       "column": 1,
       "line": 1,
       "offset": 0,
     },
   },
-  "source": "<template><svg><![CDATA[cdata]]></svg></template>",
+  "source": "<div :class=\\"{ some: condition }\\" />
+<p v-bind:style=\\"{ color: 'red' }\\"/>",
   "temps": 0,
   "type": 0,
 }
 `;
 
-exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" id=""></div></template> 1`] = `
+exports[`compiler: parse > Edge Cases > valid html 1`] = `
 {
   "cached": 0,
   "children": [
@@ -154,129 +287,113 @@ exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" i
         {
           "children": [],
           "codegenNode": undefined,
+          "isSelfClosing": true,
           "loc": {
             "end": {
-              "column": 34,
-              "line": 1,
-              "offset": 33,
+              "column": 39,
+              "line": 2,
+              "offset": 73,
             },
-            "source": "<div id=\\"\\" id=\\"\\"></div>",
+            "source": "<p v-bind:style=\\"{ color: 'red' }\\"/>",
             "start": {
-              "column": 11,
-              "line": 1,
-              "offset": 10,
-            },
-          },
+              "column": 3,
+              "line": 2,
+              "offset": 37,
+            },
+          },
           "ns": 0,
           "props": [
             {
-              "loc": {
-                "end": {
-                  "column": 21,
-                  "line": 1,
-                  "offset": 20,
-                },
-                "source": "id=\\"\\"",
-                "start": {
-                  "column": 16,
-                  "line": 1,
-                  "offset": 15,
-                },
-              },
-              "name": "id",
-              "nameLoc": {
-                "end": {
-                  "column": 18,
-                  "line": 1,
-                  "offset": 17,
-                },
-                "source": "id",
-                "start": {
-                  "column": 16,
-                  "line": 1,
-                  "offset": 15,
+              "arg": {
+                "constType": 3,
+                "content": "style",
+                "isStatic": true,
+                "loc": {
+                  "end": {
+                    "column": 18,
+                    "line": 2,
+                    "offset": 52,
+                  },
+                  "source": "style",
+                  "start": {
+                    "column": 13,
+                    "line": 2,
+                    "offset": 47,
+                  },
                 },
+                "type": 4,
               },
-              "type": 6,
-              "value": {
-                "content": "",
+              "exp": {
+                "constType": 0,
+                "content": "{ color: 'red' }",
+                "isStatic": false,
                 "loc": {
                   "end": {
-                    "column": 21,
-                    "line": 1,
-                    "offset": 20,
+                    "column": 36,
+                    "line": 2,
+                    "offset": 70,
                   },
-                  "source": "\\"\\"",
+                  "source": "{ color: 'red' }",
                   "start": {
-                    "column": 19,
-                    "line": 1,
-                    "offset": 18,
+                    "column": 20,
+                    "line": 2,
+                    "offset": 54,
                   },
                 },
-                "type": 2,
+                "type": 4,
               },
-            },
-            {
               "loc": {
                 "end": {
-                  "column": 27,
-                  "line": 1,
-                  "offset": 26,
-                },
-                "source": "id=\\"\\"",
-                "start": {
-                  "column": 22,
-                  "line": 1,
-                  "offset": 21,
-                },
-              },
-              "name": "id",
-              "nameLoc": {
-                "end": {
-                  "column": 24,
-                  "line": 1,
-                  "offset": 23,
+                  "column": 37,
+                  "line": 2,
+                  "offset": 71,
                 },
-                "source": "id",
+                "source": "v-bind:style=\\"{ color: 'red' }\\"",
                 "start": {
-                  "column": 22,
-                  "line": 1,
-                  "offset": 21,
-                },
-              },
-              "type": 6,
-              "value": {
-                "content": "",
-                "loc": {
-                  "end": {
-                    "column": 27,
-                    "line": 1,
-                    "offset": 26,
-                  },
-                  "source": "\\"\\"",
-                  "start": {
-                    "column": 25,
-                    "line": 1,
-                    "offset": 24,
-                  },
+                  "column": 6,
+                  "line": 2,
+                  "offset": 40,
                 },
-                "type": 2,
               },
+              "modifiers": [],
+              "name": "bind",
+              "rawName": "v-bind:style",
+              "type": 7,
             },
           ],
-          "tag": "div",
+          "tag": "p",
           "tagType": 0,
           "type": 1,
         },
+        {
+          "content": " a comment with <html> inside it ",
+          "loc": {
+            "end": {
+              "column": 43,
+              "line": 3,
+              "offset": 116,
+            },
+            "source": "<!-- a comment with <html> inside it -->",
+            "start": {
+              "column": 3,
+              "line": 3,
+              "offset": 76,
+            },
+          },
+          "type": 3,
+        },
       ],
       "codegenNode": undefined,
       "loc": {
         "end": {
-          "column": 45,
-          "line": 1,
-          "offset": 44,
+          "column": 7,
+          "line": 4,
+          "offset": 123,
         },
-        "source": "<template><div id=\\"\\" id=\\"\\"></div></template>",
+        "source": "<div :class=\\"{ some: condition }\\">
+  <p v-bind:style=\\"{ color: 'red' }\\"/>
+  <!-- a comment with <html> inside it -->
+</div>",
         "start": {
           "column": 1,
           "line": 1,
@@ -284,8 +401,66 @@ exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" i
         },
       },
       "ns": 0,
-      "props": [],
-      "tag": "template",
+      "props": [
+        {
+          "arg": {
+            "constType": 3,
+            "content": "class",
+            "isStatic": true,
+            "loc": {
+              "end": {
+                "column": 12,
+                "line": 1,
+                "offset": 11,
+              },
+              "source": "class",
+              "start": {
+                "column": 7,
+                "line": 1,
+                "offset": 6,
+              },
+            },
+            "type": 4,
+          },
+          "exp": {
+            "constType": 0,
+            "content": "{ some: condition }",
+            "isStatic": false,
+            "loc": {
+              "end": {
+                "column": 33,
+                "line": 1,
+                "offset": 32,
+              },
+              "source": "{ some: condition }",
+              "start": {
+                "column": 14,
+                "line": 1,
+                "offset": 13,
+              },
+            },
+            "type": 4,
+          },
+          "loc": {
+            "end": {
+              "column": 34,
+              "line": 1,
+              "offset": 33,
+            },
+            "source": ":class=\\"{ some: condition }\\"",
+            "start": {
+              "column": 6,
+              "line": 1,
+              "offset": 5,
+            },
+          },
+          "modifiers": [],
+          "name": "bind",
+          "rawName": ":class",
+          "type": 7,
+        },
+      ],
+      "tag": "div",
       "tagType": 0,
       "type": 1,
     },
@@ -298,55 +473,43 @@ exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" i
   "imports": [],
   "loc": {
     "end": {
-      "column": 45,
-      "line": 1,
-      "offset": 44,
+      "column": 7,
+      "line": 4,
+      "offset": 123,
     },
-    "source": "<template><div id=\\"\\" id=\\"\\"></div></template>",
+    "source": "<div :class=\\"{ some: condition }\\">
+  <p v-bind:style=\\"{ color: 'red' }\\"/>
+  <!-- a comment with <html> inside it -->
+</div>",
     "start": {
       "column": 1,
       "line": 1,
       "offset": 0,
     },
   },
-  "source": "<template><div id=\\"\\" id=\\"\\"></div></template>",
+  "source": "<div :class=\\"{ some: condition }\\">
+  <p v-bind:style=\\"{ color: 'red' }\\"/>
+  <!-- a comment with <html> inside it -->
+</div>",
   "temps": 0,
   "type": 0,
 }
 `;
 
-exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template>< 1`] = `
+exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[cdata]]></template> 1`] = `
 {
   "cached": 0,
   "children": [
     {
-      "children": [
-        {
-          "content": "<",
-          "loc": {
-            "end": {
-              "column": 12,
-              "line": 1,
-              "offset": 11,
-            },
-            "source": "<",
-            "start": {
-              "column": 11,
-              "line": 1,
-              "offset": 10,
-            },
-          },
-          "type": 2,
-        },
-      ],
+      "children": [],
       "codegenNode": undefined,
       "loc": {
         "end": {
-          "column": 13,
+          "column": 39,
           "line": 1,
-          "offset": 12,
+          "offset": 38,
         },
-        "source": "<template><",
+        "source": "<template><![CDATA[cdata]]></template>",
         "start": {
           "column": 1,
           "line": 1,
@@ -368,55 +531,78 @@ exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template>< 1`] = `
   "imports": [],
   "loc": {
     "end": {
-      "column": 12,
+      "column": 39,
       "line": 1,
-      "offset": 11,
+      "offset": 38,
     },
-    "source": "<template><",
+    "source": "<template><![CDATA[cdata]]></template>",
     "start": {
       "column": 1,
       "line": 1,
       "offset": 0,
     },
   },
-  "source": "<template><",
+  "source": "<template><![CDATA[cdata]]></template>",
   "temps": 0,
   "type": 0,
 }
 `;
 
-exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template></ 1`] = `
+exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><svg><![CDATA[cdata]]></svg></template> 1`] = `
 {
   "cached": 0,
   "children": [
     {
       "children": [
         {
-          "content": "</",
+          "children": [
+            {
+              "content": "cdata",
+              "loc": {
+                "end": {
+                  "column": 30,
+                  "line": 1,
+                  "offset": 29,
+                },
+                "source": "cdata",
+                "start": {
+                  "column": 25,
+                  "line": 1,
+                  "offset": 24,
+                },
+              },
+              "type": 2,
+            },
+          ],
+          "codegenNode": undefined,
           "loc": {
             "end": {
-              "column": 13,
+              "column": 39,
               "line": 1,
-              "offset": 12,
+              "offset": 38,
             },
-            "source": "</",
+            "source": "<svg><![CDATA[cdata]]></svg>",
             "start": {
               "column": 11,
               "line": 1,
               "offset": 10,
             },
           },
-          "type": 2,
+          "ns": 1,
+          "props": [],
+          "tag": "svg",
+          "tagType": 0,
+          "type": 1,
         },
       ],
       "codegenNode": undefined,
       "loc": {
         "end": {
-          "column": 14,
+          "column": 50,
           "line": 1,
-          "offset": 13,
+          "offset": 49,
         },
-        "source": "<template></",
+        "source": "<template><svg><![CDATA[cdata]]></svg></template>",
         "start": {
           "column": 1,
           "line": 1,
@@ -438,24 +624,24 @@ exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template></ 1`] = `
   "imports": [],
   "loc": {
     "end": {
-      "column": 13,
+      "column": 50,
       "line": 1,
-      "offset": 12,
+      "offset": 49,
     },
-    "source": "<template></",
+    "source": "<template><svg><![CDATA[cdata]]></svg></template>",
     "start": {
       "column": 1,
       "line": 1,
       "offset": 0,
     },
   },
-  "source": "<template></",
+  "source": "<template><svg><![CDATA[cdata]]></svg></template>",
   "temps": 0,
   "type": 0,
 }
 `;
 
-exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`] = `
+exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" id=""></div></template> 1`] = `
 {
   "cached": 0,
   "children": [
@@ -466,20 +652,115 @@ exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`]
           "codegenNode": undefined,
           "loc": {
             "end": {
-              "column": 26,
+              "column": 34,
               "line": 1,
-              "offset": 25,
+              "offset": 33,
             },
-            "source": "<svg><![CDATA[",
+            "source": "<div id=\\"\\" id=\\"\\"></div>",
             "start": {
               "column": 11,
               "line": 1,
               "offset": 10,
             },
           },
-          "ns": 1,
-          "props": [],
-          "tag": "svg",
+          "ns": 0,
+          "props": [
+            {
+              "loc": {
+                "end": {
+                  "column": 21,
+                  "line": 1,
+                  "offset": 20,
+                },
+                "source": "id=\\"\\"",
+                "start": {
+                  "column": 16,
+                  "line": 1,
+                  "offset": 15,
+                },
+              },
+              "name": "id",
+              "nameLoc": {
+                "end": {
+                  "column": 18,
+                  "line": 1,
+                  "offset": 17,
+                },
+                "source": "id",
+                "start": {
+                  "column": 16,
+                  "line": 1,
+                  "offset": 15,
+                },
+              },
+              "type": 6,
+              "value": {
+                "content": "",
+                "loc": {
+                  "end": {
+                    "column": 21,
+                    "line": 1,
+                    "offset": 20,
+                  },
+                  "source": "\\"\\"",
+                  "start": {
+                    "column": 19,
+                    "line": 1,
+                    "offset": 18,
+                  },
+                },
+                "type": 2,
+              },
+            },
+            {
+              "loc": {
+                "end": {
+                  "column": 27,
+                  "line": 1,
+                  "offset": 26,
+                },
+                "source": "id=\\"\\"",
+                "start": {
+                  "column": 22,
+                  "line": 1,
+                  "offset": 21,
+                },
+              },
+              "name": "id",
+              "nameLoc": {
+                "end": {
+                  "column": 24,
+                  "line": 1,
+                  "offset": 23,
+                },
+                "source": "id",
+                "start": {
+                  "column": 22,
+                  "line": 1,
+                  "offset": 21,
+                },
+              },
+              "type": 6,
+              "value": {
+                "content": "",
+                "loc": {
+                  "end": {
+                    "column": 27,
+                    "line": 1,
+                    "offset": 26,
+                  },
+                  "source": "\\"\\"",
+                  "start": {
+                    "column": 25,
+                    "line": 1,
+                    "offset": 24,
+                  },
+                },
+                "type": 2,
+              },
+            },
+          ],
+          "tag": "div",
           "tagType": 0,
           "type": 1,
         },
@@ -487,11 +768,11 @@ exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`]
       "codegenNode": undefined,
       "loc": {
         "end": {
-          "column": 26,
+          "column": 45,
           "line": 1,
-          "offset": 25,
+          "offset": 44,
         },
-        "source": "<template><svg><![CDATA[",
+        "source": "<template><div id=\\"\\" id=\\"\\"></div></template>",
         "start": {
           "column": 1,
           "line": 1,
@@ -513,78 +794,55 @@ exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`]
   "imports": [],
   "loc": {
     "end": {
-      "column": 25,
+      "column": 45,
       "line": 1,
-      "offset": 24,
+      "offset": 44,
     },
-    "source": "<template><svg><![CDATA[",
+    "source": "<template><div id=\\"\\" id=\\"\\"></div></template>",
     "start": {
       "column": 1,
       "line": 1,
       "offset": 0,
     },
   },
-  "source": "<template><svg><![CDATA[",
+  "source": "<template><div id=\\"\\" id=\\"\\"></div></template>",
   "temps": 0,
   "type": 0,
 }
 `;
 
-exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[cdata 1`] = `
+exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template>< 1`] = `
 {
   "cached": 0,
   "children": [
     {
       "children": [
         {
-          "children": [
-            {
-              "content": "cdata",
-              "loc": {
-                "end": {
-                  "column": 30,
-                  "line": 1,
-                  "offset": 29,
-                },
-                "source": "cdata",
-                "start": {
-                  "column": 25,
-                  "line": 1,
-                  "offset": 24,
-                },
-              },
-              "type": 2,
-            },
-          ],
-          "codegenNode": undefined,
+          "content": "<",
           "loc": {
             "end": {
-              "column": 31,
+              "column": 12,
               "line": 1,
-              "offset": 30,
+              "offset": 11,
             },
-            "source": "<svg><![CDATA[cdata",
+            "source": "<",
             "start": {
               "column": 11,
               "line": 1,
               "offset": 10,
             },
           },
-          "ns": 1,
-          "props": [],
-          "tag": "svg",
-          "tagType": 0,
-          "type": 1,
+          "type": 2,
         },
       ],
       "codegenNode": undefined,
       "loc": {
         "end": {
-          "column": 31,
+          "column": 13,
           "line": 1,
-          "offset": 30,
+          "offset": 12,
         },
-        "source": "<template><svg><![CDATA[cdata",
+        "source": "<template><",
         "start": {
           "column": 1,
           "line": 1,
@@ -606,35 +864,273 @@ exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[cdata
   "imports": [],
   "loc": {
     "end": {
-      "column": 30,
+      "column": 12,
       "line": 1,
-      "offset": 29,
+      "offset": 11,
     },
-    "source": "<template><svg><![CDATA[cdata",
+    "source": "<template><",
     "start": {
       "column": 1,
       "line": 1,
       "offset": 0,
     },
   },
-  "source": "<template><svg><![CDATA[cdata",
+  "source": "<template><",
   "temps": 0,
   "type": 0,
 }
 `;
 
-exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!-- 1`] = `
+exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template></ 1`] = `
 {
   "cached": 0,
   "children": [
     {
-      "children": [],
+      "children": [
+        {
+          "content": "</",
+          "loc": {
+            "end": {
+              "column": 13,
+              "line": 1,
+              "offset": 12,
+            },
+            "source": "</",
+            "start": {
+              "column": 11,
+              "line": 1,
+              "offset": 10,
+            },
+          },
+          "type": 2,
+        },
+      ],
       "codegenNode": undefined,
       "loc": {
         "end": {
-          "column": 16,
+          "column": 14,
           "line": 1,
-          "offset": 15,
+          "offset": 13,
+        },
+        "source": "<template></",
+        "start": {
+          "column": 1,
+          "line": 1,
+          "offset": 0,
+        },
+      },
+      "ns": 0,
+      "props": [],
+      "tag": "template",
+      "tagType": 0,
+      "type": 1,
+    },
+  ],
+  "codegenNode": undefined,
+  "components": [],
+  "directives": [],
+  "helpers": Set {},
+  "hoists": [],
+  "imports": [],
+  "loc": {
+    "end": {
+      "column": 13,
+      "line": 1,
+      "offset": 12,
+    },
+    "source": "<template></",
+    "start": {
+      "column": 1,
+      "line": 1,
+      "offset": 0,
+    },
+  },
+  "source": "<template></",
+  "temps": 0,
+  "type": 0,
+}
+`;
+
+exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`] = `
+{
+  "cached": 0,
+  "children": [
+    {
+      "children": [
+        {
+          "children": [],
+          "codegenNode": undefined,
+          "loc": {
+            "end": {
+              "column": 26,
+              "line": 1,
+              "offset": 25,
+            },
+            "source": "<svg><![CDATA[",
+            "start": {
+              "column": 11,
+              "line": 1,
+              "offset": 10,
+            },
+          },
+          "ns": 1,
+          "props": [],
+          "tag": "svg",
+          "tagType": 0,
+          "type": 1,
+        },
+      ],
+      "codegenNode": undefined,
+      "loc": {
+        "end": {
+          "column": 26,
+          "line": 1,
+          "offset": 25,
+        },
+        "source": "<template><svg><![CDATA[",
+        "start": {
+          "column": 1,
+          "line": 1,
+          "offset": 0,
+        },
+      },
+      "ns": 0,
+      "props": [],
+      "tag": "template",
+      "tagType": 0,
+      "type": 1,
+    },
+  ],
+  "codegenNode": undefined,
+  "components": [],
+  "directives": [],
+  "helpers": Set {},
+  "hoists": [],
+  "imports": [],
+  "loc": {
+    "end": {
+      "column": 25,
+      "line": 1,
+      "offset": 24,
+    },
+    "source": "<template><svg><![CDATA[",
+    "start": {
+      "column": 1,
+      "line": 1,
+      "offset": 0,
+    },
+  },
+  "source": "<template><svg><![CDATA[",
+  "temps": 0,
+  "type": 0,
+}
+`;
+
+exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[cdata 1`] = `
+{
+  "cached": 0,
+  "children": [
+    {
+      "children": [
+        {
+          "children": [
+            {
+              "content": "cdata",
+              "loc": {
+                "end": {
+                  "column": 30,
+                  "line": 1,
+                  "offset": 29,
+                },
+                "source": "cdata",
+                "start": {
+                  "column": 25,
+                  "line": 1,
+                  "offset": 24,
+                },
+              },
+              "type": 2,
+            },
+          ],
+          "codegenNode": undefined,
+          "loc": {
+            "end": {
+              "column": 31,
+              "line": 1,
+              "offset": 30,
+            },
+            "source": "<svg><![CDATA[cdata",
+            "start": {
+              "column": 11,
+              "line": 1,
+              "offset": 10,
+            },
+          },
+          "ns": 1,
+          "props": [],
+          "tag": "svg",
+          "tagType": 0,
+          "type": 1,
+        },
+      ],
+      "codegenNode": undefined,
+      "loc": {
+        "end": {
+          "column": 31,
+          "line": 1,
+          "offset": 30,
+        },
+        "source": "<template><svg><![CDATA[cdata",
+        "start": {
+          "column": 1,
+          "line": 1,
+          "offset": 0,
+        },
+      },
+      "ns": 0,
+      "props": [],
+      "tag": "template",
+      "tagType": 0,
+      "type": 1,
+    },
+  ],
+  "codegenNode": undefined,
+  "components": [],
+  "directives": [],
+  "helpers": Set {},
+  "hoists": [],
+  "imports": [],
+  "loc": {
+    "end": {
+      "column": 30,
+      "line": 1,
+      "offset": 29,
+    },
+    "source": "<template><svg><![CDATA[cdata",
+    "start": {
+      "column": 1,
+      "line": 1,
+      "offset": 0,
+    },
+  },
+  "source": "<template><svg><![CDATA[cdata",
+  "temps": 0,
+  "type": 0,
+}
+`;
+
+exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!-- 1`] = `
+{
+  "cached": 0,
+  "children": [
+    {
+      "children": [],
+      "codegenNode": undefined,
+      "loc": {
+        "end": {
+          "column": 16,
+          "line": 1,
+          "offset": 15,
         },
         "source": "<template><!--",
         "start": {
@@ -4326,499 +4822,3 @@ exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{}} 1`] = `
   "type": 0,
 }
 `;
-
-exports[`compiler: parse > invalid html 1`] = `
-{
-  "cached": 0,
-  "children": [
-    {
-      "children": [
-        {
-          "children": [],
-          "codegenNode": undefined,
-          "loc": {
-            "end": {
-              "column": 1,
-              "line": 3,
-              "offset": 13,
-            },
-            "source": "<span>
-",
-            "start": {
-              "column": 1,
-              "line": 2,
-              "offset": 6,
-            },
-          },
-          "ns": 0,
-          "props": [],
-          "tag": "span",
-          "tagType": 0,
-          "type": 1,
-        },
-      ],
-      "codegenNode": undefined,
-      "loc": {
-        "end": {
-          "column": 7,
-          "line": 3,
-          "offset": 19,
-        },
-        "source": "<div>
-<span>
-</div>",
-        "start": {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "ns": 0,
-      "props": [],
-      "tag": "div",
-      "tagType": 0,
-      "type": 1,
-    },
-  ],
-  "codegenNode": undefined,
-  "components": [],
-  "directives": [],
-  "helpers": Set {},
-  "hoists": [],
-  "imports": [],
-  "loc": {
-    "end": {
-      "column": 8,
-      "line": 4,
-      "offset": 27,
-    },
-    "source": "<div>
-<span>
-</div>
-</span>",
-    "start": {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "source": "<div>
-<span>
-</div>
-</span>",
-  "temps": 0,
-  "type": 0,
-}
-`;
-
-exports[`compiler: parse > self closing multiple tag 1`] = `
-{
-  "cached": 0,
-  "children": [
-    {
-      "children": [],
-      "codegenNode": undefined,
-      "isSelfClosing": true,
-      "loc": {
-        "end": {
-          "column": 37,
-          "line": 1,
-          "offset": 36,
-        },
-        "source": "<div :class=\\"{ some: condition }\\" />",
-        "start": {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "ns": 0,
-      "props": [
-        {
-          "arg": {
-            "constType": 3,
-            "content": "class",
-            "isStatic": true,
-            "loc": {
-              "end": {
-                "column": 12,
-                "line": 1,
-                "offset": 11,
-              },
-              "source": "class",
-              "start": {
-                "column": 7,
-                "line": 1,
-                "offset": 6,
-              },
-            },
-            "type": 4,
-          },
-          "exp": {
-            "constType": 0,
-            "content": "{ some: condition }",
-            "isStatic": false,
-            "loc": {
-              "end": {
-                "column": 33,
-                "line": 1,
-                "offset": 32,
-              },
-              "source": "{ some: condition }",
-              "start": {
-                "column": 14,
-                "line": 1,
-                "offset": 13,
-              },
-            },
-            "type": 4,
-          },
-          "loc": {
-            "end": {
-              "column": 34,
-              "line": 1,
-              "offset": 33,
-            },
-            "source": ":class=\\"{ some: condition }\\"",
-            "start": {
-              "column": 6,
-              "line": 1,
-              "offset": 5,
-            },
-          },
-          "modifiers": [],
-          "name": "bind",
-          "rawName": ":class",
-          "type": 7,
-        },
-      ],
-      "tag": "div",
-      "tagType": 0,
-      "type": 1,
-    },
-    {
-      "children": [],
-      "codegenNode": undefined,
-      "isSelfClosing": true,
-      "loc": {
-        "end": {
-          "column": 37,
-          "line": 2,
-          "offset": 73,
-        },
-        "source": "<p v-bind:style=\\"{ color: 'red' }\\"/>",
-        "start": {
-          "column": 1,
-          "line": 2,
-          "offset": 37,
-        },
-      },
-      "ns": 0,
-      "props": [
-        {
-          "arg": {
-            "constType": 3,
-            "content": "style",
-            "isStatic": true,
-            "loc": {
-              "end": {
-                "column": 16,
-                "line": 2,
-                "offset": 52,
-              },
-              "source": "style",
-              "start": {
-                "column": 11,
-                "line": 2,
-                "offset": 47,
-              },
-            },
-            "type": 4,
-          },
-          "exp": {
-            "constType": 0,
-            "content": "{ color: 'red' }",
-            "isStatic": false,
-            "loc": {
-              "end": {
-                "column": 34,
-                "line": 2,
-                "offset": 70,
-              },
-              "source": "{ color: 'red' }",
-              "start": {
-                "column": 18,
-                "line": 2,
-                "offset": 54,
-              },
-            },
-            "type": 4,
-          },
-          "loc": {
-            "end": {
-              "column": 35,
-              "line": 2,
-              "offset": 71,
-            },
-            "source": "v-bind:style=\\"{ color: 'red' }\\"",
-            "start": {
-              "column": 4,
-              "line": 2,
-              "offset": 40,
-            },
-          },
-          "modifiers": [],
-          "name": "bind",
-          "rawName": "v-bind:style",
-          "type": 7,
-        },
-      ],
-      "tag": "p",
-      "tagType": 0,
-      "type": 1,
-    },
-  ],
-  "codegenNode": undefined,
-  "components": [],
-  "directives": [],
-  "helpers": Set {},
-  "hoists": [],
-  "imports": [],
-  "loc": {
-    "end": {
-      "column": 37,
-      "line": 2,
-      "offset": 73,
-    },
-    "source": "<div :class=\\"{ some: condition }\\" />
-<p v-bind:style=\\"{ color: 'red' }\\"/>",
-    "start": {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "source": "<div :class=\\"{ some: condition }\\" />
-<p v-bind:style=\\"{ color: 'red' }\\"/>",
-  "temps": 0,
-  "type": 0,
-}
-`;
-
-exports[`compiler: parse > valid html 1`] = `
-{
-  "cached": 0,
-  "children": [
-    {
-      "children": [
-        {
-          "children": [],
-          "codegenNode": undefined,
-          "isSelfClosing": true,
-          "loc": {
-            "end": {
-              "column": 39,
-              "line": 2,
-              "offset": 73,
-            },
-            "source": "<p v-bind:style=\\"{ color: 'red' }\\"/>",
-            "start": {
-              "column": 3,
-              "line": 2,
-              "offset": 37,
-            },
-          },
-          "ns": 0,
-          "props": [
-            {
-              "arg": {
-                "constType": 3,
-                "content": "style",
-                "isStatic": true,
-                "loc": {
-                  "end": {
-                    "column": 18,
-                    "line": 2,
-                    "offset": 52,
-                  },
-                  "source": "style",
-                  "start": {
-                    "column": 13,
-                    "line": 2,
-                    "offset": 47,
-                  },
-                },
-                "type": 4,
-              },
-              "exp": {
-                "constType": 0,
-                "content": "{ color: 'red' }",
-                "isStatic": false,
-                "loc": {
-                  "end": {
-                    "column": 36,
-                    "line": 2,
-                    "offset": 70,
-                  },
-                  "source": "{ color: 'red' }",
-                  "start": {
-                    "column": 20,
-                    "line": 2,
-                    "offset": 54,
-                  },
-                },
-                "type": 4,
-              },
-              "loc": {
-                "end": {
-                  "column": 37,
-                  "line": 2,
-                  "offset": 71,
-                },
-                "source": "v-bind:style=\\"{ color: 'red' }\\"",
-                "start": {
-                  "column": 6,
-                  "line": 2,
-                  "offset": 40,
-                },
-              },
-              "modifiers": [],
-              "name": "bind",
-              "rawName": "v-bind:style",
-              "type": 7,
-            },
-          ],
-          "tag": "p",
-          "tagType": 0,
-          "type": 1,
-        },
-        {
-          "content": " a comment with <html> inside it ",
-          "loc": {
-            "end": {
-              "column": 43,
-              "line": 3,
-              "offset": 116,
-            },
-            "source": "<!-- a comment with <html> inside it -->",
-            "start": {
-              "column": 3,
-              "line": 3,
-              "offset": 76,
-            },
-          },
-          "type": 3,
-        },
-      ],
-      "codegenNode": undefined,
-      "loc": {
-        "end": {
-          "column": 7,
-          "line": 4,
-          "offset": 123,
-        },
-        "source": "<div :class=\\"{ some: condition }\\">
-  <p v-bind:style=\\"{ color: 'red' }\\"/>
-  <!-- a comment with <html> inside it -->
-</div>",
-        "start": {
-          "column": 1,
-          "line": 1,
-          "offset": 0,
-        },
-      },
-      "ns": 0,
-      "props": [
-        {
-          "arg": {
-            "constType": 3,
-            "content": "class",
-            "isStatic": true,
-            "loc": {
-              "end": {
-                "column": 12,
-                "line": 1,
-                "offset": 11,
-              },
-              "source": "class",
-              "start": {
-                "column": 7,
-                "line": 1,
-                "offset": 6,
-              },
-            },
-            "type": 4,
-          },
-          "exp": {
-            "constType": 0,
-            "content": "{ some: condition }",
-            "isStatic": false,
-            "loc": {
-              "end": {
-                "column": 33,
-                "line": 1,
-                "offset": 32,
-              },
-              "source": "{ some: condition }",
-              "start": {
-                "column": 14,
-                "line": 1,
-                "offset": 13,
-              },
-            },
-            "type": 4,
-          },
-          "loc": {
-            "end": {
-              "column": 34,
-              "line": 1,
-              "offset": 33,
-            },
-            "source": ":class=\\"{ some: condition }\\"",
-            "start": {
-              "column": 6,
-              "line": 1,
-              "offset": 5,
-            },
-          },
-          "modifiers": [],
-          "name": "bind",
-          "rawName": ":class",
-          "type": 7,
-        },
-      ],
-      "tag": "div",
-      "tagType": 0,
-      "type": 1,
-    },
-  ],
-  "codegenNode": undefined,
-  "components": [],
-  "directives": [],
-  "helpers": Set {},
-  "hoists": [],
-  "imports": [],
-  "loc": {
-    "end": {
-      "column": 7,
-      "line": 4,
-      "offset": 123,
-    },
-    "source": "<div :class=\\"{ some: condition }\\">
-  <p v-bind:style=\\"{ color: 'red' }\\"/>
-  <!-- a comment with <html> inside it -->
-</div>",
-    "start": {
-      "column": 1,
-      "line": 1,
-      "offset": 0,
-    },
-  },
-  "source": "<div :class=\\"{ some: condition }\\">
-  <p v-bind:style=\\"{ color: 'red' }\\"/>
-  <!-- a comment with <html> inside it -->
-</div>",
-  "temps": 0,
-  "type": 0,
-}
-`;
index 4e6c80b38e0d999005ea5484a053f2c89c4ad953..05a2afcdc6eb3c46c08268b48241cb6f26c29cd5 100644 (file)
@@ -1796,166 +1796,167 @@ describe('compiler: parse', () => {
     })
   })
 
-  test('self closing single tag', () => {
-    const ast = baseParse('<div :class="{ some: condition }" />')
+  describe('Edge Cases', () => {
+    test('self closing single tag', () => {
+      const ast = baseParse('<div :class="{ some: condition }" />')
 
-    expect(ast.children).toHaveLength(1)
-    expect(ast.children[0]).toMatchObject({ tag: 'div' })
-  })
+      expect(ast.children).toHaveLength(1)
+      expect(ast.children[0]).toMatchObject({ tag: 'div' })
+    })
 
-  test('self closing multiple tag', () => {
-    const ast = baseParse(
-      `<div :class="{ some: condition }" />\n` +
-        `<p v-bind:style="{ color: 'red' }"/>`
-    )
+    test('self closing multiple tag', () => {
+      const ast = baseParse(
+        `<div :class="{ some: condition }" />\n` +
+          `<p v-bind:style="{ color: 'red' }"/>`
+      )
 
-    expect(ast).toMatchSnapshot()
+      expect(ast).toMatchSnapshot()
 
-    expect(ast.children).toHaveLength(2)
-    expect(ast.children[0]).toMatchObject({ tag: 'div' })
-    expect(ast.children[1]).toMatchObject({ tag: 'p' })
-  })
+      expect(ast.children).toHaveLength(2)
+      expect(ast.children[0]).toMatchObject({ tag: 'div' })
+      expect(ast.children[1]).toMatchObject({ tag: 'p' })
+    })
 
-  test('valid html', () => {
-    const ast = baseParse(
-      `<div :class="{ some: condition }">\n` +
-        `  <p v-bind:style="{ color: 'red' }"/>\n` +
-        `  <!-- a comment with <html> inside it -->\n` +
-        `</div>`
-    )
+    test('valid html', () => {
+      const ast = baseParse(
+        `<div :class="{ some: condition }">\n` +
+          `  <p v-bind:style="{ color: 'red' }"/>\n` +
+          `  <!-- a comment with <html> inside it -->\n` +
+          `</div>`
+      )
 
-    expect(ast).toMatchSnapshot()
+      expect(ast).toMatchSnapshot()
 
-    expect(ast.children).toHaveLength(1)
-    const el = ast.children[0] as any
-    expect(el).toMatchObject({
-      tag: 'div'
-    })
-    expect(el.children).toHaveLength(2)
-    expect(el.children[0]).toMatchObject({
-      tag: 'p'
-    })
-    expect(el.children[1]).toMatchObject({
-      type: NodeTypes.COMMENT
+      expect(ast.children).toHaveLength(1)
+      const el = ast.children[0] as any
+      expect(el).toMatchObject({
+        tag: 'div'
+      })
+      expect(el.children).toHaveLength(2)
+      expect(el.children[0]).toMatchObject({
+        tag: 'p'
+      })
+      expect(el.children[1]).toMatchObject({
+        type: NodeTypes.COMMENT
+      })
     })
-  })
 
-  test('invalid html', () => {
-    expect(() => {
-      baseParse(`<div>\n<span>\n</div>\n</span>`)
-    }).toThrow('Element is missing end tag.')
+    test('invalid html', () => {
+      expect(() => {
+        baseParse(`<div>\n<span>\n</div>\n</span>`)
+      }).toThrow('Element is missing end tag.')
 
-    const spy = vi.fn()
-    const ast = baseParse(`<div>\n<span>\n</div>\n</span>`, {
-      onError: spy
-    })
+      const spy = vi.fn()
+      const ast = baseParse(`<div>\n<span>\n</div>\n</span>`, {
+        onError: spy
+      })
 
-    expect(spy.mock.calls).toMatchObject([
-      [
-        {
-          code: ErrorCodes.X_MISSING_END_TAG,
-          loc: {
-            start: {
-              offset: 6,
-              line: 2,
-              column: 1
+      expect(spy.mock.calls).toMatchObject([
+        [
+          {
+            code: ErrorCodes.X_MISSING_END_TAG,
+            loc: {
+              start: {
+                offset: 6,
+                line: 2,
+                column: 1
+              }
             }
           }
-        }
-      ],
-      [
-        {
-          code: ErrorCodes.X_INVALID_END_TAG,
-          loc: {
-            start: {
-              offset: 20,
-              line: 4,
-              column: 1
+        ],
+        [
+          {
+            code: ErrorCodes.X_INVALID_END_TAG,
+            loc: {
+              start: {
+                offset: 20,
+                line: 4,
+                column: 1
+              }
             }
           }
-        }
-      ]
-    ])
-
-    expect(ast).toMatchSnapshot()
-  })
-
-  test('parse with correct location info', () => {
-    const fooSrc = `foo
- is `
-    const barSrc = `{{ bar }}`
-    const butSrc = ` but `
-    const bazSrc = `{{ baz }}`
-    const [foo, bar, but, baz] = baseParse(
-      fooSrc + barSrc + butSrc + bazSrc
-    ).children
-
-    let offset = 0
-    expect(foo.loc.start).toEqual({ line: 1, column: 1, offset })
-    offset += fooSrc.length
-    expect(foo.loc.end).toEqual({ line: 2, column: 5, offset })
-
-    expect(bar.loc.start).toEqual({ line: 2, column: 5, offset })
-    const barInner = (bar as InterpolationNode).content
-    offset += 3
-    expect(barInner.loc.start).toEqual({ line: 2, column: 8, offset })
-    offset += 3
-    expect(barInner.loc.end).toEqual({ line: 2, column: 11, offset })
-    offset += 3
-    expect(bar.loc.end).toEqual({ line: 2, column: 14, offset })
-
-    expect(but.loc.start).toEqual({ line: 2, column: 14, offset })
-    offset += butSrc.length
-    expect(but.loc.end).toEqual({ line: 2, column: 19, offset })
-
-    expect(baz.loc.start).toEqual({ line: 2, column: 19, offset })
-    const bazInner = (baz as InterpolationNode).content
-    offset += 3
-    expect(bazInner.loc.start).toEqual({ line: 2, column: 22, offset })
-    offset += 3
-    expect(bazInner.loc.end).toEqual({ line: 2, column: 25, offset })
-    offset += 3
-    expect(baz.loc.end).toEqual({ line: 2, column: 28, offset })
-  })
+        ]
+      ])
 
-  // With standard HTML parsing, the following input would ignore the slash
-  // and treat "<" and "template" as attributes on the open tag of "Hello",
-  // causing `<template>` to fail to close, and `<script>` being parsed as its
-  // child. This is would never be intended in actual templates, but is a common
-  // intermediate state from user input when parsing for IDE support. We want
-  // the `<script>` to be at root-level to keep the SFC structure stable for
-  // Volar to do incremental computations.
-  test('tag termination handling for IDE', () => {
-    const spy = vi.fn()
-    const ast = baseParse(
-      `<template><Hello\n</template><script>console.log(1)</script>`,
-      {
-        onError: spy
-      }
-    )
-    //
-    expect(ast.children.length).toBe(2)
-    expect(ast.children[1]).toMatchObject({
-      type: NodeTypes.ELEMENT,
-      tag: 'script'
+      expect(ast).toMatchSnapshot()
+    })
+
+    test('parse with correct location info', () => {
+      const fooSrc = `foo\n is `
+      const barSrc = `{{ bar }}`
+      const butSrc = ` but `
+      const bazSrc = `{{ baz }}`
+      const [foo, bar, but, baz] = baseParse(
+        fooSrc + barSrc + butSrc + bazSrc
+      ).children
+
+      let offset = 0
+      expect(foo.loc.start).toEqual({ line: 1, column: 1, offset })
+      offset += fooSrc.length
+      expect(foo.loc.end).toEqual({ line: 2, column: 5, offset })
+
+      expect(bar.loc.start).toEqual({ line: 2, column: 5, offset })
+      const barInner = (bar as InterpolationNode).content
+      offset += 3
+      expect(barInner.loc.start).toEqual({ line: 2, column: 8, offset })
+      offset += 3
+      expect(barInner.loc.end).toEqual({ line: 2, column: 11, offset })
+      offset += 3
+      expect(bar.loc.end).toEqual({ line: 2, column: 14, offset })
+
+      expect(but.loc.start).toEqual({ line: 2, column: 14, offset })
+      offset += butSrc.length
+      expect(but.loc.end).toEqual({ line: 2, column: 19, offset })
+
+      expect(baz.loc.start).toEqual({ line: 2, column: 19, offset })
+      const bazInner = (baz as InterpolationNode).content
+      offset += 3
+      expect(bazInner.loc.start).toEqual({ line: 2, column: 22, offset })
+      offset += 3
+      expect(bazInner.loc.end).toEqual({ line: 2, column: 25, offset })
+      offset += 3
+      expect(baz.loc.end).toEqual({ line: 2, column: 28, offset })
+    })
+
+    // With standard HTML parsing, the following input would ignore the slash
+    // and treat "<" and "template" as attributes on the open tag of "Hello",
+    // causing `<template>` to fail to close, and `<script>` being parsed as its
+    // child. This is would never be intended in actual templates, but is a common
+    // intermediate state from user input when parsing for IDE support. We want
+    // the `<script>` to be at root-level to keep the SFC structure stable for
+    // Volar to do incremental computations.
+    test('tag termination handling for IDE', () => {
+      const spy = vi.fn()
+      const ast = baseParse(
+        `<template><Hello\n</template><script>console.log(1)</script>`,
+        {
+          onError: spy
+        }
+      )
+      //
+      expect(ast.children.length).toBe(2)
+      expect(ast.children[1]).toMatchObject({
+        type: NodeTypes.ELEMENT,
+        tag: 'script'
+      })
     })
-  })
 
-  test('arg should be undefined on shorthand dirs with no arg', () => {
-    const ast = baseParse(`<template #></template>`)
-    const el = ast.children[0] as ElementNode
-    expect(el.props[0]).toMatchObject({
-      type: NodeTypes.DIRECTIVE,
-      name: 'slot',
-      exp: undefined,
-      arg: undefined
+    test('arg should be undefined on shorthand dirs with no arg', () => {
+      const ast = baseParse(`<template #></template>`)
+      const el = ast.children[0] as ElementNode
+      expect(el.props[0]).toMatchObject({
+        type: NodeTypes.DIRECTIVE,
+        name: 'slot',
+        exp: undefined,
+        arg: undefined
+      })
     })
-  })
 
-  // edge case found in vue-macros where the input is TS or JSX
-  test('should reset inRCDATA state', () => {
-    baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
-    expect(() => baseParse(`{ foo }`)).not.toThrow()
+    // edge case found in vue-macros where the input is TS or JSX
+    test('should reset inRCDATA state', () => {
+      baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
+      expect(() => baseParse(`{ foo }`)).not.toThrow()
+    })
   })
 
   describe('decodeEntities option', () => {