Skip to content

Commit 319a7ca

Browse files
committed
chore: fix remark tag parse
1 parent 6b0f90f commit 319a7ca

File tree

1 file changed

+15
-11
lines changed

1 file changed

+15
-11
lines changed

web/src/utils/remark-plugins/remark-tag.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,32 +36,36 @@ function isTagChar(char: string): boolean {
3636
// Parse tags from text and return segments
3737
function parseTagsFromText(text: string): Array<{ type: "text" | "tag"; value: string }> {
3838
const segments: Array<{ type: "text" | "tag"; value: string }> = [];
39+
40+
// Convert to array of code points for proper Unicode handling (emojis, etc.)
41+
const chars = [...text];
3942
let i = 0;
4043

41-
while (i < text.length) {
44+
while (i < chars.length) {
4245
// Check for tag pattern
43-
if (text[i] === "#" && i + 1 < text.length && isTagChar(text[i + 1])) {
46+
if (chars[i] === "#" && i + 1 < chars.length && isTagChar(chars[i + 1])) {
4447
// Check if this might be a heading (## at start or after whitespace)
45-
const prevChar = i > 0 ? text[i - 1] : "";
46-
const nextChar = i + 1 < text.length ? text[i + 1] : "";
48+
const prevChar = i > 0 ? chars[i - 1] : "";
49+
const nextChar = i + 1 < chars.length ? chars[i + 1] : "";
4750

4851
if (prevChar === "#" || nextChar === "#" || nextChar === " ") {
4952
// This is a heading, not a tag
50-
segments.push({ type: "text", value: text[i] });
53+
segments.push({ type: "text", value: chars[i] });
5154
i++;
5255
continue;
5356
}
5457

5558
// Extract tag content
5659
let j = i + 1;
57-
while (j < text.length && isTagChar(text[j])) {
60+
while (j < chars.length && isTagChar(chars[j])) {
5861
j++;
5962
}
6063

61-
const tagContent = text.slice(i + 1, j);
64+
const tagContent = chars.slice(i + 1, j).join("");
6265

63-
// Validate tag length (must match backend MAX_TAG_LENGTH)
64-
if (tagContent.length > 0 && tagContent.length <= MAX_TAG_LENGTH) {
66+
// Validate tag length by rune count (must match backend MAX_TAG_LENGTH)
67+
const runeCount = [...tagContent].length;
68+
if (runeCount > 0 && runeCount <= MAX_TAG_LENGTH) {
6569
segments.push({ type: "tag", value: tagContent });
6670
i = j;
6771
continue;
@@ -70,10 +74,10 @@ function parseTagsFromText(text: string): Array<{ type: "text" | "tag"; value: s
7074

7175
// Regular text
7276
let j = i + 1;
73-
while (j < text.length && text[j] !== "#") {
77+
while (j < chars.length && chars[j] !== "#") {
7478
j++;
7579
}
76-
segments.push({ type: "text", value: text.slice(i, j) });
80+
segments.push({ type: "text", value: chars.slice(i, j).join("") });
7781
i = j;
7882
}
7983

0 commit comments

Comments
 (0)