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
Show file tree
Hide file tree
Changes from 1 commit
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
58 changes: 38 additions & 20 deletions src/libs/EmojiTrie.js → src/libs/EmojiTrie.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,46 @@
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';
import {MetaData} from './Trie/TrieNode';

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 LangEmoji = {
name?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a huge fan of this name. I know you're using what was already here, but I think something like localizedEmoji or emojiInLocalLanguage or something like that would be better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I've updated it

keywords: string[];
};

type LangEmojis = Record<string, LangEmoji>;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here.

Timing.start(CONST.TIMING.TRIE_INITIALIZATION);

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const supportedLanguages = [CONST.LOCALES.DEFAULT, CONST.LOCALES.ES];
const supportedLanguages = [CONST.LOCALES.DEFAULT, CONST.LOCALES.ES] as const;
type SupportedLanguages = (typeof supportedLanguages)[number];

We can use SupportedLanguages in createTrie() function.

/**
*
* @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<MetaData>, keywords: string[], item: Emoji, name: string, shouldPrependKeyword = false): void {
keywords.forEach((keyword) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function addKeywordsToTrie(trie: Trie<MetaData>, keywords: string[], item: Emoji, name: string, shouldPrependKeyword = false): void {
function addKeywordsToTrie(trie: Trie<MetaData>, keywords: string[], item: Emoji, name: string, shouldPrependKeyword = false) {

When the function don't return anything, we don't need to add void

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 +52,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: 'en' | 'es' = CONST.LOCALES.DEFAULT): Trie<MetaData> {
const trie = new Trie();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you extract 'en' | 'es' in a separate type?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VickyStash See my comment above about SupportedLanguages type.

const langEmojis = localeEmojis[lang];
const langEmojis: LangEmojis = localeEmojis[lang];
const defaultLangEmojis: LangEmojis = 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 +85,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 +101,7 @@ function createTrie(lang = CONST.LOCALES.DEFAULT) {
return trie;
}

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you improve the return type of this variable? Currently is just {}.

Screenshot 2023-09-18 at 17 37 00

Timing.end(CONST.TIMING.TRIE_INITIALIZATION);

Expand Down
11 changes: 10 additions & 1 deletion src/libs/Trie/TrieNode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
type MetaData = Record<string, unknown>;
type Suggestion = {
code: string;
types?: string[];
name?: string;
};

type MetaData = {
[key: string]: unknown;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trie and TrieNode were typed with generic MetaData in mind. So instead of overwriting it here define EmojiMetaData inside of EmojiTrie file and pass it as a generic argument:

// src/libs/EmojiTrie.ts
type Suggestion = {
    code: string;
    types?: string[];
    name?: string;
};

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

Trie<MetaData> -> Trie<EmojiMetaData>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

suggestions?: Suggestion[];
};

class TrieNode<TMetadata extends MetaData> {
children: Record<string, TrieNode<TMetadata>>;
Expand Down
Loading