Skip to content

Commit 31425ae

Browse files
committed
🐛 disable expressions in v-pre elements (vuejs/eslint-plugin-vue#733)
1 parent 7113191 commit 31425ae

File tree

5 files changed

+1476
-4
lines changed

5 files changed

+1476
-4
lines changed

Diff for: src/html/parser.ts

+34-4
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ export class Parser {
151151
private parserOptions: any
152152
private document: VDocumentFragment
153153
private elementStack: VElement[]
154+
private vPreElement: VElement | null
154155

155156
/**
156157
* The source code text.
@@ -211,6 +212,13 @@ export class Parser {
211212
return last(this.elementStack) || this.document
212213
}
213214

215+
/**
216+
* Check if the current location is in a v-pre element.
217+
*/
218+
private get isInVPreElement(): boolean {
219+
return this.vPreElement != null
220+
}
221+
214222
/**
215223
* Initialize this parser.
216224
* @param tokenizer The tokenizer to parse.
@@ -237,6 +245,7 @@ export class Parser {
237245
errors: this.errors,
238246
}
239247
this.elementStack = []
248+
this.vPreElement = null
240249
}
241250

242251
/**
@@ -277,14 +286,20 @@ export class Parser {
277286
private popElementStack(): void {
278287
assert(this.elementStack.length >= 1)
279288

280-
const element = this.elementStack.pop() as VElement
289+
const element = this.elementStack.pop()!
281290
propagateEndLocation(element)
282291

283292
// Update the current namespace.
284293
const current = this.currentNode
285294
this.namespace =
286295
current.type === "VElement" ? current.namespace : NS.HTML
287296

297+
// Update v-pre state.
298+
if (this.vPreElement === element) {
299+
this.vPreElement = null
300+
this.expressionEnabled = true
301+
}
302+
288303
// Update expression flag.
289304
if (this.elementStack.length === 0) {
290305
this.expressionEnabled = false
@@ -384,9 +399,11 @@ export class Parser {
384399
const attrName = node.key.name
385400

386401
if (
387-
DIRECTIVE_NAME.test(attrName) ||
388-
attrName === "slot-scope" ||
389-
(tagName === "template" && attrName === "scope")
402+
(this.expressionEnabled ||
403+
(attrName === "v-pre" && !this.isInVPreElement)) &&
404+
(DIRECTIVE_NAME.test(attrName) ||
405+
attrName === "slot-scope" ||
406+
(tagName === "template" && attrName === "scope"))
390407
) {
391408
convertToDirective(
392409
this.text,
@@ -442,6 +459,14 @@ export class Parser {
442459
endTag: null,
443460
variables: [],
444461
}
462+
const hasVPre =
463+
!this.isInVPreElement &&
464+
token.attributes.some(a => a.key.name === "v-pre")
465+
466+
// Disable expression if v-pre
467+
if (hasVPre) {
468+
this.expressionEnabled = false
469+
}
445470

446471
// Setup relations.
447472
parent.children.push(element)
@@ -470,11 +495,16 @@ export class Parser {
470495

471496
// Vue.js supports self-closing elements even if it's not one of void elements.
472497
if (token.selfClosing || isVoid) {
498+
this.expressionEnabled = !this.isInVPreElement
473499
return
474500
}
475501

476502
// Push to stack.
477503
this.elementStack.push(element)
504+
if (hasVPre) {
505+
assert(this.vPreElement === null)
506+
this.vPreElement = element
507+
}
478508
this.namespace = namespace
479509

480510
// Update the content type of this element.

0 commit comments

Comments
 (0)