fix(tags): include combining marks in tag character class (#6051)

This commit is contained in:
Santhosh Thottingal
2026-06-28 08:11:41 +05:30
committed by GitHub
parent 047175dbed
commit 281e0dc17c
3 changed files with 25 additions and 2 deletions
+6 -2
View File
@@ -4,10 +4,14 @@
* tagMarkdown.ts) and the read-only renderer (utils/remark-plugins/remark-tag.ts)
* so they can't drift.
*
* A tag character is any Unicode letter, number, or symbol, plus `_ - / &`.
* A tag character is any Unicode letter, mark, number, or symbol, plus
* `_ - / &`. The mark class (`\p{M}`) keeps combining marks — Indic vowel
* signs, Arabic harakat, Hebrew niqqud, decomposed accents — attached to the
* base letters they belong to, so a tag like `#കവിത` isn't cut short at its
* first vowel sign.
* A tag run is capped at MAX_TAG_LENGTH characters.
*/
export const TAG_CHAR_CLASS = "[\\p{L}\\p{N}\\p{S}_\\-/&]";
export const TAG_CHAR_CLASS = "[\\p{L}\\p{M}\\p{N}\\p{S}_\\-/&]";
export const MAX_TAG_LENGTH = 100;
+10
View File
@@ -43,6 +43,16 @@ describe("Tag mark", () => {
expect(tagged?.marks?.find((m) => m.type === "tag")?.attrs?.tag).toBe("work/project-1");
});
it("includes combining marks in a tag run", () => {
// Malayalam കവിത carries a spacing combining vowel sign (U+0D3F, \p{M});
// the tag must cover the whole word, not stop at the first mark.
expect(firstParagraphChildren("#കവിത")[0]).toMatchObject({
type: "text",
text: "#കവിത",
marks: [{ type: "tag", attrs: { tag: "കവിത" } }],
});
});
it("does not turn headings into tags", () => {
expect(parseMarkdown("# heading").content?.[0]?.type).toBe("heading");
});
+9
View File
@@ -70,6 +70,15 @@ describe("remarkTag", () => {
expect(html).toContain('data-tag="second"');
});
it("tags a whole word containing combining marks", () => {
// Malayalam കവിത = ka, va, vowel-sign-i (U+0D3F, a spacing combining mark),
// ta. The vowel sign is a \p{M} character, so the tag must not stop at കവ.
const html = renderMarkdown("#കവിത");
expect(html).toContain('data-tag="കവിത"');
expect(html).not.toContain('data-tag="കവ"');
});
it("still tags a hash that shares a text node with an entity reference", () => {
// The source slice ("...&...") differs from the decoded value, so the
// escape-aware path bows out and the tag is detected the original way.