Skip to content

Commit 217c698

Browse files
committed
Chore: improve handling of v-expressions
1 parent bbe113f commit 217c698

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

src/html/intermediate-tokenizer.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ export class IntermediateTokenizer {
7979
this.tokenizer.namespace = value
8080
}
8181

82+
/**
83+
* The current flag of expression enabled.
84+
*/
85+
get expressionEnabled(): boolean {
86+
return this.tokenizer.expressionEnabled
87+
}
88+
set expressionEnabled(value: boolean) { //eslint-disable-line require-jsdoc
89+
this.tokenizer.expressionEnabled = value
90+
}
91+
8292
/**
8393
* Initialize this intermediate tokenizer.
8494
* @param tokenizer The tokenizer.

src/html/parser.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,34 +110,44 @@ export class Parser {
110110
/**
111111
* The tokens.
112112
*/
113-
get tokens(): Token[] {
113+
private get tokens(): Token[] {
114114
return this.tokenizer.tokens
115115
}
116116

117117
/**
118118
* The comments.
119119
*/
120-
get comments(): Token[] {
120+
private get comments(): Token[] {
121121
return this.tokenizer.comments
122122
}
123123

124124
/**
125125
* The syntax errors which are found in this parsing.
126126
*/
127-
get errors(): ParseError[] {
127+
private get errors(): ParseError[] {
128128
return this.tokenizer.errors
129129
}
130130

131131
/**
132132
* The current namespace.
133133
*/
134-
get namespace(): Namespace {
134+
private get namespace(): Namespace {
135135
return this.tokenizer.namespace
136136
}
137-
set namespace(value: Namespace) { //eslint-disable-line require-jsdoc
137+
private set namespace(value: Namespace) { //eslint-disable-line require-jsdoc
138138
this.tokenizer.namespace = value
139139
}
140140

141+
/**
142+
* The current flag of expression enabled.
143+
*/
144+
private get expressionEnabled(): boolean {
145+
return this.tokenizer.expressionEnabled
146+
}
147+
private set expressionEnabled(value: boolean) { //eslint-disable-line require-jsdoc
148+
this.tokenizer.expressionEnabled = value
149+
}
150+
141151
/**
142152
* Get the current node.
143153
*/
@@ -207,6 +217,11 @@ export class Parser {
207217
// Update the current namespace.
208218
const current = this.currentNode
209219
this.namespace = (current.type === "VElement") ? current.namespace : NS.HTML
220+
221+
// Update expression flag.
222+
if (this.elementStack.length === 0) {
223+
this.expressionEnabled = false
224+
}
210225
}
211226

212227
/**
@@ -341,6 +356,15 @@ export class Parser {
341356

342357
// Update the content type of this element.
343358
if (namespace === NS.HTML) {
359+
if (element.name === "template" && element.parent.type === "VDocumentFragment") {
360+
const langAttr = element.startTag.attributes.find(a => !a.directive && a.key.name === "lang") as (VAttribute | undefined)
361+
const lang = (langAttr && langAttr.value && langAttr.value.value) || "html"
362+
363+
if (lang !== "html") {
364+
this.tokenizer.state = "RAWTEXT"
365+
}
366+
this.expressionEnabled = true
367+
}
344368
if (HTML_RCDATA_TAGS.has(element.name)) {
345369
this.tokenizer.state = "RCDATA"
346370
}

src/html/tokenizer.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ export class Tokenizer {
167167
*/
168168
public namespace: Namespace
169169

170+
/**
171+
* The flag which enables expression tokens.
172+
* If this is true, this tokenizer will generate V_EXPRESSION_START and V_EXPRESSION_END tokens.
173+
*/
174+
public expressionEnabled: boolean
175+
170176
/**
171177
* Initialize this tokenizer.
172178
* @param text The source code to tokenize.
@@ -195,6 +201,7 @@ export class Tokenizer {
195201
this.tokenStartColumn = -1
196202
this.tokenStartLine = 1
197203
this.namespace = NS.HTML
204+
this.expressionEnabled = false
198205
}
199206

200207
/**
@@ -535,12 +542,12 @@ export class Tokenizer {
535542
this.setStartTokenMark()
536543
return "TAG_OPEN"
537544
}
538-
if (cp === LEFT_CURLY_BRACKET) {
545+
if (cp === LEFT_CURLY_BRACKET && this.expressionEnabled) {
539546
this.setStartTokenMark()
540547
this.returnState = "DATA"
541548
return "V_EXPRESSION_START"
542549
}
543-
if (cp === RIGHT_CURLY_BRACKET) {
550+
if (cp === RIGHT_CURLY_BRACKET && this.expressionEnabled) {
544551
this.setStartTokenMark()
545552
this.returnState = "DATA"
546553
return "V_EXPRESSION_END"
@@ -584,12 +591,12 @@ export class Tokenizer {
584591
this.setStartTokenMark()
585592
return "RCDATA_LESS_THAN_SIGN"
586593
}
587-
if (cp === LEFT_CURLY_BRACKET) {
594+
if (cp === LEFT_CURLY_BRACKET && this.expressionEnabled) {
588595
this.setStartTokenMark()
589596
this.returnState = "RCDATA"
590597
return "V_EXPRESSION_START"
591598
}
592-
if (cp === RIGHT_CURLY_BRACKET) {
599+
if (cp === RIGHT_CURLY_BRACKET && this.expressionEnabled) {
593600
this.setStartTokenMark()
594601
this.returnState = "RCDATA"
595602
return "V_EXPRESSION_END"
@@ -630,12 +637,12 @@ export class Tokenizer {
630637
this.setStartTokenMark()
631638
return "RAWTEXT_LESS_THAN_SIGN"
632639
}
633-
if (cp === LEFT_CURLY_BRACKET) {
640+
if (cp === LEFT_CURLY_BRACKET && this.expressionEnabled) {
634641
this.setStartTokenMark()
635642
this.returnState = "RAWTEXT"
636643
return "V_EXPRESSION_START"
637644
}
638-
if (cp === RIGHT_CURLY_BRACKET) {
645+
if (cp === RIGHT_CURLY_BRACKET && this.expressionEnabled) {
639646
this.setStartTokenMark()
640647
this.returnState = "RAWTEXT"
641648
return "V_EXPRESSION_END"

0 commit comments

Comments
 (0)