Skip to content

Commit 47bb99c

Browse files
committed
fix(compiler-core): prevent incorrect entity parsing with logical AND
1 parent d53daf1 commit 47bb99c

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

packages/compiler-core/__tests__/parse.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,17 @@ describe('compiler: parse', () => {
12641264
})
12651265
})
12661266

1267+
// #13361
1268+
test('directive with multiline value', () => {
1269+
const ast = baseParse(
1270+
`<div v-if="
1271+
foo &&
1272+
bar
1273+
"></div>`,
1274+
)
1275+
expect(ast.loc.end.line).toBe(4)
1276+
})
1277+
12671278
test('directive with argument', () => {
12681279
const ast = baseParse('<div v-on:click/>')
12691280
const directive = (ast.children[0] as ElementNode).props[0]

packages/compiler-core/src/tokenizer.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ export default class Tokenizer {
322322
}
323323
this.state = State.BeforeTagName
324324
this.sectionStart = this.index
325-
} else if (!__BROWSER__ && c === CharCodes.Amp) {
325+
} else if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
326326
this.startEntity()
327327
} else if (!this.inVPre && c === this.delimiterOpen[0]) {
328328
this.state = State.InterpolationOpen
@@ -436,7 +436,7 @@ export default class Tokenizer {
436436
(this.currentSequence === Sequences.TextareaEnd && !this.inSFCRoot)
437437
) {
438438
// We have to parse entities in <title> and <textarea> tags.
439-
if (!__BROWSER__ && c === CharCodes.Amp) {
439+
if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
440440
this.startEntity()
441441
} else if (!this.inVPre && c === this.delimiterOpen[0]) {
442442
// We also need to handle interpolation
@@ -795,7 +795,7 @@ export default class Tokenizer {
795795
this.index + 1,
796796
)
797797
this.state = State.BeforeAttrName
798-
} else if (!__BROWSER__ && c === CharCodes.Amp) {
798+
} else if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
799799
this.startEntity()
800800
}
801801
}
@@ -823,7 +823,7 @@ export default class Tokenizer {
823823
ErrorCodes.UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE,
824824
this.index,
825825
)
826-
} else if (!__BROWSER__ && c === CharCodes.Amp) {
826+
} else if (!__BROWSER__ && c === CharCodes.Amp && !this.isLogicalAnd()) {
827827
this.startEntity()
828828
}
829829
}
@@ -1178,4 +1178,11 @@ export default class Tokenizer {
11781178
}
11791179
}
11801180
}
1181+
1182+
private isLogicalAnd(): boolean {
1183+
return (
1184+
this.buffer.charCodeAt(this.index - 1) === CharCodes.Amp ||
1185+
this.buffer.charCodeAt(this.index + 1) === CharCodes.Amp
1186+
)
1187+
}
11811188
}

0 commit comments

Comments
 (0)