Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TS migration] migrate 'EmojiTrie.js' lib #27693

Merged
merged 4 commits into from
Sep 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 54 additions & 21 deletions src/libs/EmojiTrie.js → src/libs/EmojiTrie.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,61 @@
import _ from 'underscore';
import React from 'react';
import {SvgProps} from 'react-native-svg';
import emojis, {localeEmojis} from '../../assets/emojis';
import Trie from './Trie';
import Timing from './actions/Timing';
import CONST from '../CONST';

type Emoji = {
code: string;
header?: boolean;
icon?: React.FC<SvgProps>;
name?: string;
VickyStash marked this conversation as resolved.
Show resolved Hide resolved
types?: string[];
};

type LocalizedEmoji = {
name?: string;
keywords: string[];
};

type LocalizedEmojis = Record<string, LocalizedEmoji>;

type Suggestion = {
code: string;
types?: string[];
name?: string;
};

type EmojiMetaData = {
suggestions?: Suggestion[];
};

Timing.start(CONST.TIMING.TRIE_INITIALIZATION);

const supportedLanguages = [CONST.LOCALES.DEFAULT, CONST.LOCALES.ES];
const supportedLanguages = [CONST.LOCALES.DEFAULT, CONST.LOCALES.ES] as const;

type SupportedLanguage = (typeof supportedLanguages)[number];

type EmojiTrie = {
[key in SupportedLanguage]?: Trie<EmojiMetaData>;
};

/**
*
* @param {Trie} trie The Trie object.
* @param {Array<String>} keywords An array containing the keywords.
* @param {Object} item An object containing the properties of the emoji.
* @param {String} name The localized name of the emoji.
* @param {Boolean} shouldPrependKeyword Prepend the keyword (instead of append) to the suggestions
* @param trie The Trie object.
* @param keywords An array containing the keywords.
* @param item An object containing the properties of the emoji.
* @param name The localized name of the emoji.
* @param shouldPrependKeyword Prepend the keyword (instead of append) to the suggestions
*/
function addKeywordsToTrie(trie, keywords, item, name, shouldPrependKeyword = false) {
_.forEach(keywords, (keyword) => {
function addKeywordsToTrie(trie: Trie<EmojiMetaData>, keywords: string[], item: Emoji, name: string, shouldPrependKeyword = false) {
keywords.forEach((keyword) => {
const keywordNode = trie.search(keyword);
if (!keywordNode) {
trie.add(keyword, {suggestions: [{code: item.code, types: item.types, name}]});
} else {
const suggestion = {code: item.code, types: item.types, name};
const suggestions = shouldPrependKeyword ? [suggestion, ...keywordNode.metaData.suggestions] : [...keywordNode.metaData.suggestions, suggestion];
const suggestions = shouldPrependKeyword ? [suggestion, ...(keywordNode.metaData.suggestions ?? [])] : [...(keywordNode.metaData.suggestions ?? []), suggestion];
trie.update(keyword, {
...keywordNode.metaData,
suggestions,
Expand All @@ -35,26 +67,27 @@ function addKeywordsToTrie(trie, keywords, item, name, shouldPrependKeyword = fa
/**
* Allows searching based on parts of the name. This turns 'white_large_square' into ['white_large_square', 'large_square', 'square'].
*
* @param {String} name The emoji name
* @returns {Array<String>} An array containing the name parts
* @param name The emoji name
* @returns An array containing the name parts
*/
function getNameParts(name) {
function getNameParts(name: string): string[] {
const nameSplit = name.split('_');
return _.map(nameSplit, (_namePart, index) => nameSplit.slice(index).join('_'));
return nameSplit.map((namePart, index) => nameSplit.slice(index).join('_'));
}

function createTrie(lang = CONST.LOCALES.DEFAULT) {
function createTrie(lang: SupportedLanguage = CONST.LOCALES.DEFAULT): Trie<EmojiMetaData> {
const trie = new Trie();
const langEmojis = localeEmojis[lang];
const langEmojis: LocalizedEmojis = localeEmojis[lang];
const defaultLangEmojis: LocalizedEmojis = localeEmojis[CONST.LOCALES.DEFAULT];
const isDefaultLocale = lang === CONST.LOCALES.DEFAULT;

_.forEach(emojis, (item) => {
if (item.header) {
emojis.forEach((item: Emoji) => {
if (!item.name) {
return;
}

const englishName = item.name;
const localeName = _.get(langEmojis, [item.code, 'name'], englishName);
const localeName = langEmojis?.[item.code]?.name ?? englishName;

const node = trie.search(localeName);
if (!node) {
Expand All @@ -67,7 +100,7 @@ function createTrie(lang = CONST.LOCALES.DEFAULT) {
addKeywordsToTrie(trie, nameParts, item, localeName);

// Add keywords for both the locale language and English to enable users to search using either language.
const keywords = _.get(langEmojis, [item.code, 'keywords'], []).concat(isDefaultLocale ? [] : _.get(localeEmojis, [CONST.LOCALES.DEFAULT, item.code, 'keywords'], []));
const keywords = (langEmojis?.[item.code]?.keywords ?? []).concat(isDefaultLocale ? [] : defaultLangEmojis?.[item.code]?.keywords ?? []);
addKeywordsToTrie(trie, keywords, item, localeName);

/**
Expand All @@ -83,7 +116,7 @@ function createTrie(lang = CONST.LOCALES.DEFAULT) {
return trie;
}

const emojiTrie = _.reduce(supportedLanguages, (prev, cur) => ({...prev, [cur]: createTrie(cur)}), {});
const emojiTrie: EmojiTrie = supportedLanguages.reduce((prev, cur) => ({...prev, [cur]: createTrie(cur)}), {});

Timing.end(CONST.TIMING.TRIE_INITIALIZATION);

Expand Down
Loading