/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see .
*/
import {
type EmojiProvider,
setEmojiParserConfig,
type UnicodeEmoji,
} from '@fluxer/markdown_parser/src/parsers/EmojiParsers';
import emojiRegex from 'emoji-regex';
interface EmojiData {
surrogate: string;
names: Array;
hasDiversity?: boolean;
skins?: Array<{surrogate: string}>;
}
const EMOJI_DATA: Map = new Map([
['smile', {surrogate: 'π', names: ['smile', 'grinning_face_with_smiling_eyes']}],
[
'wave',
{
surrogate: 'π',
names: ['wave', 'waving_hand'],
hasDiversity: true,
skins: [{surrogate: 'ππ»'}, {surrogate: 'ππΌ'}, {surrogate: 'ππ½'}, {surrogate: 'ππΎ'}, {surrogate: 'ππΏ'}],
},
],
['heart', {surrogate: 'β€οΈ', names: ['heart', 'red_heart']}],
[
'thumbsup',
{
surrogate: 'π',
names: ['thumbsup', 'thumbs_up', '+1'],
hasDiversity: true,
skins: [{surrogate: 'ππ»'}, {surrogate: 'ππΌ'}, {surrogate: 'ππ½'}, {surrogate: 'ππΎ'}, {surrogate: 'ππΏ'}],
},
],
['blush', {surrogate: 'π', names: ['blush', 'smiling_face_with_smiling_eyes']}],
['grinning', {surrogate: 'π', names: ['grinning', 'grinning_face']}],
['smiley', {surrogate: 'π', names: ['smiley', 'smiling_face_with_open_mouth']}],
['grin', {surrogate: 'π', names: ['grin', 'beaming_face_with_smiling_eyes']}],
[
'foot',
{
surrogate: 'π¦Ά',
names: ['foot', 'leg'],
hasDiversity: true,
skins: [{surrogate: 'π¦Άπ»'}, {surrogate: 'π¦ΆπΌ'}, {surrogate: 'π¦Άπ½'}, {surrogate: 'π¦ΆπΎ'}, {surrogate: 'π¦ΆπΏ'}],
},
],
['face_holding_back_tears', {surrogate: 'π₯Ή', names: ['face_holding_back_tears']}],
['white_check_mark', {surrogate: 'β
', names: ['white_check_mark', 'check_mark_button']}],
['x', {surrogate: 'β', names: ['x', 'cross_mark']}],
['leftwards_arrow_with_hook', {surrogate: 'β©οΈ', names: ['leftwards_arrow_with_hook']}],
['rightwards_arrow_with_hook', {surrogate: 'βͺοΈ', names: ['rightwards_arrow_with_hook']}],
['arrow_heading_up', {surrogate: '‴οΈ', names: ['arrow_heading_up']}],
['family_mwgb', {surrogate: 'π¨βπ©βπ§βπ¦', names: ['family_mwgb', 'family_man_woman_girl_boy']}],
[
'mx_claus',
{
surrogate: 'π§βπ',
names: ['mx_claus'],
hasDiversity: true,
skins: [
{surrogate: 'π§π»βπ'},
{surrogate: 'π§πΌβπ'},
{surrogate: 'π§π½βπ'},
{surrogate: 'π§πΎβπ'},
{surrogate: 'π§πΏβπ'},
],
},
],
]);
const SKIN_TONE_SURROGATES: ReadonlyArray = ['π»', 'πΌ', 'π½', 'πΎ', 'πΏ'];
const SURROGATE_TO_NAME: Map = new Map();
const NAME_TO_EMOJI: Map = new Map();
const SKIN_TONE_EMOJI: Map = new Map();
for (const [mainName, data] of EMOJI_DATA) {
SURROGATE_TO_NAME.set(data.surrogate, mainName);
for (const name of data.names) {
NAME_TO_EMOJI.set(name, {surrogates: data.surrogate});
}
if (data.hasDiversity && data.skins) {
data.skins.forEach((skin, index) => {
const skinToneSurrogate = SKIN_TONE_SURROGATES[index];
for (const name of data.names) {
const skinKey = `${name}:${skinToneSurrogate}`;
SKIN_TONE_EMOJI.set(skinKey, {surrogates: skin.surrogate});
SURROGATE_TO_NAME.set(skin.surrogate, `${name}::skin-tone-${index + 1}`);
}
});
}
}
const testEmojiProvider: EmojiProvider = {
getSurrogateName(surrogate: string): string | null {
return SURROGATE_TO_NAME.get(surrogate) || null;
},
findEmojiByName(name: string): UnicodeEmoji | null {
return NAME_TO_EMOJI.get(name) || null;
},
findEmojiWithSkinTone(baseName: string, skinToneSurrogate: string): UnicodeEmoji | null {
const skinKey = `${baseName}:${skinToneSurrogate}`;
return SKIN_TONE_EMOJI.get(skinKey) || null;
},
};
export function setupTestEmojiProvider(): void {
setEmojiParserConfig({
emojiProvider: testEmojiProvider,
emojiRegex: emojiRegex(),
skinToneSurrogates: SKIN_TONE_SURROGATES,
});
}
export function clearTestEmojiProvider(): void {
setEmojiParserConfig({
emojiProvider: undefined,
emojiRegex: undefined,
skinToneSurrogates: undefined,
});
}