]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): prevent incorrect entity parsing with logical AND edison/fix/13361 13363/head
authordaiwei <daiwei521@126.com>
Wed, 21 May 2025 09:31:55 +0000 (17:31 +0800)
committerdaiwei <daiwei521@126.com>
Wed, 21 May 2025 09:31:55 +0000 (17:31 +0800)
packages/compiler-core/__tests__/parse.spec.ts
packages/compiler-core/src/tokenizer.ts

index 4e5a96165118ce5a001329df595722bb9687a79a..15f211e7d9e37167c0c6d3ea6940315665fa3419 100644 (file)
@@ -1264,6 +1264,17 @@ describe('compiler: parse', () => {
       })
     })
 
+    // #13361
+    test('directive with multiline value', () => {
+      const ast = baseParse(
+        `<div v-if="
+          foo &&
+          bar
+        "></div>`,
+      )
+      expect(ast.loc.end.line).toBe(4)
+    })
+
     test('directive with argument', () => {
       const ast = baseParse('<div v-on:click/>')
       const directive = (ast.children[0] as ElementNode).props[0]
index 329e8b481814329442586bec16aa0ad45e05eeb9..041951f0b4401419ddd3ff2d19804d84b1a2263c 100644 (file)
@@ -322,7 +322,7 @@ export default class Tokenizer {
       }
       this.state = State.BeforeTagName
       this.sectionStart = this.index
-    } else if (!__BROWSER__ && c === CharCodes.Amp) {
+    } else if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
       this.startEntity()
     } else if (!this.inVPre && c === this.delimiterOpen[0]) {
       this.state = State.InterpolationOpen
@@ -436,7 +436,7 @@ export default class Tokenizer {
         (this.currentSequence === Sequences.TextareaEnd && !this.inSFCRoot)
       ) {
         // We have to parse entities in <title> and <textarea> tags.
-        if (!__BROWSER__ && c === CharCodes.Amp) {
+        if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
           this.startEntity()
         } else if (!this.inVPre && c === this.delimiterOpen[0]) {
           // We also need to handle interpolation
@@ -795,7 +795,7 @@ export default class Tokenizer {
         this.index + 1,
       )
       this.state = State.BeforeAttrName
-    } else if (!__BROWSER__ && c === CharCodes.Amp) {
+    } else if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
       this.startEntity()
     }
   }
@@ -823,7 +823,7 @@ export default class Tokenizer {
         ErrorCodes.UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE,
         this.index,
       )
-    } else if (!__BROWSER__ && c === CharCodes.Amp) {
+    } else if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
       this.startEntity()
     }
   }
@@ -1178,4 +1178,11 @@ export default class Tokenizer {
       }
     }
   }
+
+  private isLogicalAnd(): boolean {
+    return (
+      this.buffer.charCodeAt(this.index - 1) === CharCodes.Amp ||
+      this.buffer.charCodeAt(this.index + 1) === CharCodes.Amp
+    )
+  }
 }