fix(markdown): render default-presentation emoji without variation selectors

This commit is contained in:
Hampus authored and GitHub committed 2026-08-26 14:19:28 +02:00
1 parent f7ebc1492c
commit f98a40062a
2 files changed
+43 -14

No files matched your search

@@ -1,8 +1,17 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {initializeEmojiParser} from '@app/features/messaging/utils/markdown/EmojiProviderSetup';
import {ParserFlags} from '@app/features/messaging/utils/markdown/parser/Enums';
import {parseMarkdownAstWithWasm} from '@app/features/messaging/utils/markdown/parser/MarkdownParserWasm';
import {describe, expect, it} from 'vitest';
import {beforeAll, describe, expect, it, vi} from 'vitest';
vi.mock('@app/features/expressions/utils/EmojiUtils', () => ({
getEmojiURL: () => null,
}));
vi.mock('@lingui/core/macro', () => ({
msg: (descriptor: unknown) => descriptor,
}));
describe('markdown parser wasm blockquotes', () => {
it('preserves consecutive empty blockquote lines', () => {
@@ -62,3 +71,36 @@ describe('markdown parser wasm headings', () => {
});
});
});
describe('markdown parser wasm default-presentation emoji', () => {
beforeAll(() => {
initializeEmojiParser();
});
it.each([
['⌚', 'watch', '231a'],
['⌛', 'hourglass', '231b'],
['⏩', 'fast_forward', '23e9'],
['⏪', 'rewind', '23ea'],
['⏫', 'arrow_double_up', '23eb'],
['⏬', 'arrow_double_down', '23ec'],
['⏰', 'alarm_clock', '23f0'],
['⏳', 'hourglass_flowing_sand', '23f3'],
])('renders %s as an emoji without a variation selector', (raw, name, codepoints) => {
expect(parseMarkdownAstWithWasm(raw, 0)).toEqual({
nodes: [{type: 'Emoji', kind: {kind: 'Standard', raw, codepoints, name}}],
});
});
it('keeps text-presentation symbols as plain text when typed bare', () => {
expect(parseMarkdownAstWithWasm('❤', 0)).toEqual({
nodes: [{type: 'Text', content: '❤'}],
});
});
it('still renders text-presentation symbols carrying a variation selector', () => {
expect(parseMarkdownAstWithWasm('❤️', 0)).toEqual({
nodes: [{type: 'Emoji', kind: {kind: 'Standard', raw: '❤️', codepoints: '2764', name: 'heart'}}],
});
});
});
@@ -217,15 +217,6 @@ const SPECIAL_SHORTCODES: Record<string, string> = {
registered: '®',
};
function needsVariationSelector(codePoint: number): boolean {
return (
(codePoint >= 0x2190 && codePoint <= 0x21ff) ||
(codePoint >= 0x2300 && codePoint <= 0x23ff) ||
(codePoint >= 0x2600 && codePoint <= 0x27bf) ||
(codePoint >= 0x2900 && codePoint <= 0x297f)
);
}
function appendContextLine(parts: Array<string>): string {
return `${parts.join('\t')}\n`;
}
@@ -244,10 +235,6 @@ function buildEmojiContext(input: string): string {
while ((match = emojiRegex.exec(input)) !== null) {
const candidate = match[0];
if (!candidate || PLAINTEXT_SYMBOLS.has(candidate)) continue;
const hasVariationSelector = candidate.includes('️');
const codePoint = candidate.codePointAt(0) || 0;
const isDingbat = codePoint >= 0x2600 && codePoint <= 0x27bf;
if (!isDingbat && needsVariationSelector(codePoint) && !hasVariationSelector) continue;
const name = provider.getSurrogateName(candidate);
if (!name) continue;
const candidateBytes = textEncoder.encode(candidate).byteLength;