Remove rendering of custom emoji using the database (#37284)

This commit is contained in:
ChaosExAnima 2025-12-19 10:44:57 +01:00 committed by Claire
parent 32c3376d84
commit 3de59a9344
2 changed files with 30 additions and 51 deletions

View file

@ -7,6 +7,7 @@ import {
stringToEmojiState, stringToEmojiState,
tokenizeText, tokenizeText,
} from './render'; } from './render';
import type { EmojiStateCustom } from './types';
describe('tokenizeText', () => { describe('tokenizeText', () => {
test('returns an array of text to be a single token', () => { test('returns an array of text to be a single token', () => {
@ -82,12 +83,8 @@ describe('stringToEmojiState', () => {
}); });
}); });
test('returns custom emoji state for valid custom emoji', () => { test('returns null for custom emoji without data', () => {
expect(stringToEmojiState(':smile:')).toEqual({ expect(stringToEmojiState(':smile:')).toBeNull();
type: 'custom',
code: 'smile',
data: undefined,
});
}); });
test('returns custom emoji state with data when provided', () => { test('returns custom emoji state with data when provided', () => {
@ -107,7 +104,6 @@ describe('stringToEmojiState', () => {
test('returns null for invalid emoji strings', () => { test('returns null for invalid emoji strings', () => {
expect(stringToEmojiState('notanemoji')).toBeNull(); expect(stringToEmojiState('notanemoji')).toBeNull();
expect(stringToEmojiState(':invalid-emoji:')).toBeNull();
}); });
}); });
@ -130,18 +126,13 @@ describe('loadEmojiDataToState', () => {
}); });
}); });
test('loads custom emoji data into state', async () => { test('returns null for custom emoji without data', async () => {
const dbCall = vi const customState = {
.spyOn(db, 'loadCustomEmojiByShortcode')
.mockResolvedValueOnce(customEmojiFactory());
const customState = { type: 'custom', code: 'smile' } as const;
const result = await loadEmojiDataToState(customState, 'en');
expect(dbCall).toHaveBeenCalledWith('smile');
expect(result).toEqual({
type: 'custom', type: 'custom',
code: 'smile', code: 'smile',
data: customEmojiFactory(), } as const satisfies EmojiStateCustom;
}); const result = await loadEmojiDataToState(customState, 'en');
expect(result).toBeNull();
}); });
test('returns null if unicode emoji not found in database', async () => { test('returns null if unicode emoji not found in database', async () => {
@ -151,13 +142,6 @@ describe('loadEmojiDataToState', () => {
expect(result).toBeNull(); expect(result).toBeNull();
}); });
test('returns null if custom emoji not found in database', async () => {
vi.spyOn(db, 'loadCustomEmojiByShortcode').mockResolvedValueOnce(undefined);
const customState = { type: 'custom', code: 'smile' } as const;
const result = await loadEmojiDataToState(customState, 'en');
expect(result).toBeNull();
});
test('retries loading emoji data once if initial load fails', async () => { test('retries loading emoji data once if initial load fails', async () => {
const dbCall = vi const dbCall = vi
.spyOn(db, 'loadEmojiByHexcode') .spyOn(db, 'loadEmojiByHexcode')

View file

@ -4,11 +4,7 @@ import {
EMOJI_TYPE_UNICODE, EMOJI_TYPE_UNICODE,
EMOJI_TYPE_CUSTOM, EMOJI_TYPE_CUSTOM,
} from './constants'; } from './constants';
import { import { loadEmojiByHexcode, LocaleNotLoadedError } from './database';
loadCustomEmojiByShortcode,
loadEmojiByHexcode,
LocaleNotLoadedError,
} from './database';
import { importEmojiData } from './loader'; import { importEmojiData } from './loader';
import { emojiToUnicodeHex } from './normalize'; import { emojiToUnicodeHex } from './normalize';
import type { import type {
@ -79,7 +75,7 @@ export function tokenizeText(text: string): TokenizedText {
export function stringToEmojiState( export function stringToEmojiState(
code: string, code: string,
customEmoji: ExtraCustomEmojiMap = {}, customEmoji: ExtraCustomEmojiMap = {},
): EmojiState | null { ): EmojiStateUnicode | Required<EmojiStateCustom> | null {
if (isUnicodeEmoji(code)) { if (isUnicodeEmoji(code)) {
return { return {
type: EMOJI_TYPE_UNICODE, type: EMOJI_TYPE_UNICODE,
@ -89,11 +85,13 @@ export function stringToEmojiState(
if (isCustomEmoji(code)) { if (isCustomEmoji(code)) {
const shortCode = code.slice(1, -1); const shortCode = code.slice(1, -1);
return { if (customEmoji[shortCode]) {
type: EMOJI_TYPE_CUSTOM, return {
code: shortCode, type: EMOJI_TYPE_CUSTOM,
data: customEmoji[shortCode], code: shortCode,
}; data: customEmoji[shortCode],
};
}
} }
return null; return null;
@ -114,26 +112,23 @@ export async function loadEmojiDataToState(
return state; return state;
} }
// Don't try to load data for custom emoji.
if (state.type === EMOJI_TYPE_CUSTOM) {
return null;
}
// First, try to load the data from IndexedDB. // First, try to load the data from IndexedDB.
try { try {
// This is duplicative, but that's because TS can't distinguish the state type easily. // This is duplicative, but that's because TS can't distinguish the state type easily.
if (state.type === EMOJI_TYPE_UNICODE) { const data = await loadEmojiByHexcode(state.code, locale);
const data = await loadEmojiByHexcode(state.code, locale); if (data) {
if (data) { return {
return { ...state,
...state, type: EMOJI_TYPE_UNICODE,
data, data,
}; };
}
} else {
const data = await loadCustomEmojiByShortcode(state.code);
if (data) {
return {
...state,
data,
};
}
} }
// If not found, assume it's not an emoji and return null. // If not found, assume it's not an emoji and return null.
log( log(
'Could not find emoji %s of type %s for locale %s', 'Could not find emoji %s of type %s for locale %s',