From 40039f1622e4cbf33108eec3ef538771fba37abe Mon Sep 17 00:00:00 2001
From: Woongsik Choi <woongsik.choi@gmail.com>
Date: Wed, 19 Mar 2025 12:26:41 +0900
Subject: [PATCH] fix: text token type in V_EXPRESSION_DATA state

---
 src/html/tokenizer.ts                         |   4 +-
 .../ast/mustache-errors-in-textarea/ast.json  | 495 ++++++++++++++++++
 .../mustache-errors-in-textarea/source.vue    |   3 +
 .../token-ranges.json                         |  18 +
 .../ast/mustache-errors-in-textarea/tree.json |  49 ++
 5 files changed, 567 insertions(+), 2 deletions(-)
 create mode 100644 test/fixtures/ast/mustache-errors-in-textarea/ast.json
 create mode 100644 test/fixtures/ast/mustache-errors-in-textarea/source.vue
 create mode 100644 test/fixtures/ast/mustache-errors-in-textarea/token-ranges.json
 create mode 100644 test/fixtures/ast/mustache-errors-in-textarea/tree.json

diff --git a/src/html/tokenizer.ts b/src/html/tokenizer.ts
index 6285cdf..ad95bc8 100644
--- a/src/html/tokenizer.ts
+++ b/src/html/tokenizer.ts
@@ -1892,9 +1892,9 @@ export class Tokenizer {
             const type = isWhitespace(cp)
                 ? "HTMLWhitespace"
                 : state === "RCDATA"
-                  ? "HTMLRawText"
+                  ? "HTMLRCDataText"
                   : state === "RAWTEXT"
-                    ? "HTMLRCDataText"
+                    ? "HTMLRawText"
                     : "HTMLText"
             if (this.currentToken != null && this.currentToken.type !== type) {
                 this.endToken()
diff --git a/test/fixtures/ast/mustache-errors-in-textarea/ast.json b/test/fixtures/ast/mustache-errors-in-textarea/ast.json
new file mode 100644
index 0000000..9dd73fe
--- /dev/null
+++ b/test/fixtures/ast/mustache-errors-in-textarea/ast.json
@@ -0,0 +1,495 @@
+{
+    "type": "Program",
+    "start": 0,
+    "end": 0,
+    "loc": {
+        "start": {
+            "line": 1,
+            "column": 0
+        },
+        "end": {
+            "line": 1,
+            "column": 0
+        }
+    },
+    "range": [
+        0,
+        0
+    ],
+    "body": [],
+    "sourceType": "module",
+    "comments": [],
+    "tokens": [],
+    "templateBody": {
+        "type": "VElement",
+        "range": [
+            0,
+            59
+        ],
+        "loc": {
+            "start": {
+                "line": 1,
+                "column": 0
+            },
+            "end": {
+                "line": 3,
+                "column": 11
+            }
+        },
+        "name": "template",
+        "rawName": "template",
+        "namespace": "http://www.w3.org/1999/xhtml",
+        "startTag": {
+            "type": "VStartTag",
+            "range": [
+                0,
+                10
+            ],
+            "loc": {
+                "start": {
+                    "line": 1,
+                    "column": 0
+                },
+                "end": {
+                    "line": 1,
+                    "column": 10
+                }
+            },
+            "selfClosing": false,
+            "attributes": []
+        },
+        "children": [
+            {
+                "type": "VText",
+                "range": [
+                    10,
+                    15
+                ],
+                "loc": {
+                    "start": {
+                        "line": 1,
+                        "column": 10
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 4
+                    }
+                },
+                "value": "\n    "
+            },
+            {
+                "type": "VElement",
+                "range": [
+                    15,
+                    47
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 4
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 36
+                    }
+                },
+                "name": "textarea",
+                "rawName": "textarea",
+                "namespace": "http://www.w3.org/1999/xhtml",
+                "startTag": {
+                    "type": "VStartTag",
+                    "range": [
+                        15,
+                        25
+                    ],
+                    "loc": {
+                        "start": {
+                            "line": 2,
+                            "column": 4
+                        },
+                        "end": {
+                            "line": 2,
+                            "column": 14
+                        }
+                    },
+                    "selfClosing": false,
+                    "attributes": []
+                },
+                "children": [
+                    {
+                        "type": "VExpressionContainer",
+                        "range": [
+                            25,
+                            36
+                        ],
+                        "loc": {
+                            "start": {
+                                "line": 2,
+                                "column": 14
+                            },
+                            "end": {
+                                "line": 2,
+                                "column": 25
+                            }
+                        },
+                        "expression": null,
+                        "references": []
+                    }
+                ],
+                "endTag": {
+                    "type": "VEndTag",
+                    "range": [
+                        36,
+                        47
+                    ],
+                    "loc": {
+                        "start": {
+                            "line": 2,
+                            "column": 25
+                        },
+                        "end": {
+                            "line": 2,
+                            "column": 36
+                        }
+                    }
+                },
+                "variables": []
+            },
+            {
+                "type": "VText",
+                "range": [
+                    47,
+                    48
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 36
+                    },
+                    "end": {
+                        "line": 3,
+                        "column": 0
+                    }
+                },
+                "value": "\n"
+            }
+        ],
+        "endTag": {
+            "type": "VEndTag",
+            "range": [
+                48,
+                59
+            ],
+            "loc": {
+                "start": {
+                    "line": 3,
+                    "column": 0
+                },
+                "end": {
+                    "line": 3,
+                    "column": 11
+                }
+            }
+        },
+        "variables": [],
+        "tokens": [
+            {
+                "type": "HTMLTagOpen",
+                "range": [
+                    0,
+                    9
+                ],
+                "loc": {
+                    "start": {
+                        "line": 1,
+                        "column": 0
+                    },
+                    "end": {
+                        "line": 1,
+                        "column": 9
+                    }
+                },
+                "value": "template"
+            },
+            {
+                "type": "HTMLTagClose",
+                "range": [
+                    9,
+                    10
+                ],
+                "loc": {
+                    "start": {
+                        "line": 1,
+                        "column": 9
+                    },
+                    "end": {
+                        "line": 1,
+                        "column": 10
+                    }
+                },
+                "value": ""
+            },
+            {
+                "type": "HTMLWhitespace",
+                "range": [
+                    10,
+                    15
+                ],
+                "loc": {
+                    "start": {
+                        "line": 1,
+                        "column": 10
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 4
+                    }
+                },
+                "value": "\n    "
+            },
+            {
+                "type": "HTMLTagOpen",
+                "range": [
+                    15,
+                    24
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 4
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 13
+                    }
+                },
+                "value": "textarea"
+            },
+            {
+                "type": "HTMLTagClose",
+                "range": [
+                    24,
+                    25
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 13
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 14
+                    }
+                },
+                "value": ""
+            },
+            {
+                "type": "VExpressionStart",
+                "range": [
+                    25,
+                    27
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 14
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 16
+                    }
+                },
+                "value": "{{"
+            },
+            {
+                "type": "HTMLRCDataText",
+                "range": [
+                    27,
+                    30
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 16
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 19
+                    }
+                },
+                "value": "foo"
+            },
+            {
+                "type": "HTMLWhitespace",
+                "range": [
+                    30,
+                    31
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 19
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 20
+                    }
+                },
+                "value": " "
+            },
+            {
+                "type": "HTMLRCDataText",
+                "range": [
+                    31,
+                    34
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 20
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 23
+                    }
+                },
+                "value": "bar"
+            },
+            {
+                "type": "VExpressionEnd",
+                "range": [
+                    34,
+                    36
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 23
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 25
+                    }
+                },
+                "value": "}}"
+            },
+            {
+                "type": "HTMLEndTagOpen",
+                "range": [
+                    36,
+                    46
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 25
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 35
+                    }
+                },
+                "value": "textarea"
+            },
+            {
+                "type": "HTMLTagClose",
+                "range": [
+                    46,
+                    47
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 35
+                    },
+                    "end": {
+                        "line": 2,
+                        "column": 36
+                    }
+                },
+                "value": ""
+            },
+            {
+                "type": "HTMLWhitespace",
+                "range": [
+                    47,
+                    48
+                ],
+                "loc": {
+                    "start": {
+                        "line": 2,
+                        "column": 36
+                    },
+                    "end": {
+                        "line": 3,
+                        "column": 0
+                    }
+                },
+                "value": "\n"
+            },
+            {
+                "type": "HTMLEndTagOpen",
+                "range": [
+                    48,
+                    58
+                ],
+                "loc": {
+                    "start": {
+                        "line": 3,
+                        "column": 0
+                    },
+                    "end": {
+                        "line": 3,
+                        "column": 10
+                    }
+                },
+                "value": "template"
+            },
+            {
+                "type": "HTMLTagClose",
+                "range": [
+                    58,
+                    59
+                ],
+                "loc": {
+                    "start": {
+                        "line": 3,
+                        "column": 10
+                    },
+                    "end": {
+                        "line": 3,
+                        "column": 11
+                    }
+                },
+                "value": ""
+            },
+            {
+                "type": "HTMLWhitespace",
+                "range": [
+                    59,
+                    60
+                ],
+                "loc": {
+                    "start": {
+                        "line": 3,
+                        "column": 11
+                    },
+                    "end": {
+                        "line": 4,
+                        "column": 0
+                    }
+                },
+                "value": "\n"
+            }
+        ],
+        "comments": [],
+        "errors": [
+            {
+                "message": "Unexpected token bar",
+                "index": 31,
+                "lineNumber": 2,
+                "column": 20
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/test/fixtures/ast/mustache-errors-in-textarea/source.vue b/test/fixtures/ast/mustache-errors-in-textarea/source.vue
new file mode 100644
index 0000000..da4a40a
--- /dev/null
+++ b/test/fixtures/ast/mustache-errors-in-textarea/source.vue
@@ -0,0 +1,3 @@
+<template>
+    <textarea>{{foo bar}}</textarea>
+</template>
diff --git a/test/fixtures/ast/mustache-errors-in-textarea/token-ranges.json b/test/fixtures/ast/mustache-errors-in-textarea/token-ranges.json
new file mode 100644
index 0000000..8f3b13e
--- /dev/null
+++ b/test/fixtures/ast/mustache-errors-in-textarea/token-ranges.json
@@ -0,0 +1,18 @@
+[
+    "<template",
+    ">",
+    "\n    ",
+    "<textarea",
+    ">",
+    "{{",
+    "foo",
+    " ",
+    "bar",
+    "}}",
+    "</textarea",
+    ">",
+    "\n",
+    "</template",
+    ">",
+    "\n"
+]
\ No newline at end of file
diff --git a/test/fixtures/ast/mustache-errors-in-textarea/tree.json b/test/fixtures/ast/mustache-errors-in-textarea/tree.json
new file mode 100644
index 0000000..f5b30cc
--- /dev/null
+++ b/test/fixtures/ast/mustache-errors-in-textarea/tree.json
@@ -0,0 +1,49 @@
+[
+    {
+        "type": "VElement",
+        "text": "<template>\n    <textarea>{{foo bar}}</textarea>\n</template>",
+        "children": [
+            {
+                "type": "VStartTag",
+                "text": "<template>",
+                "children": []
+            },
+            {
+                "type": "VText",
+                "text": "\n    ",
+                "children": []
+            },
+            {
+                "type": "VElement",
+                "text": "<textarea>{{foo bar}}</textarea>",
+                "children": [
+                    {
+                        "type": "VStartTag",
+                        "text": "<textarea>",
+                        "children": []
+                    },
+                    {
+                        "type": "VExpressionContainer",
+                        "text": "{{foo bar}}",
+                        "children": []
+                    },
+                    {
+                        "type": "VEndTag",
+                        "text": "</textarea>",
+                        "children": []
+                    }
+                ]
+            },
+            {
+                "type": "VText",
+                "text": "\n",
+                "children": []
+            },
+            {
+                "type": "VEndTag",
+                "text": "</template>",
+                "children": []
+            }
+        ]
+    }
+]
\ No newline at end of file