From 3b5e302f7fc1e62cbd075e154ad9415f20fde2ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=9F=E3=81=84=E3=81=A1=20=E3=81=B2?=
 <taichi221228@icloud.com>
Date: Wed, 14 Jun 2023 02:28:31 +0900
Subject: [PATCH] Rewrite `emoji_mart_data_light` as TS (#25138)

---
 .../features/emoji/emoji_compressed.d.ts      | 51 ++++++++++++++++++
 .../features/emoji/emoji_compressed.js        | 10 ++++
 .../features/emoji/emoji_mart_data_light.js   | 43 ---------------
 .../features/emoji/emoji_mart_data_light.ts   | 52 +++++++++++++++++++
 4 files changed, 113 insertions(+), 43 deletions(-)
 create mode 100644 app/javascript/mastodon/features/emoji/emoji_compressed.d.ts
 delete mode 100644 app/javascript/mastodon/features/emoji/emoji_mart_data_light.js
 create mode 100644 app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts

diff --git a/app/javascript/mastodon/features/emoji/emoji_compressed.d.ts b/app/javascript/mastodon/features/emoji/emoji_compressed.d.ts
new file mode 100644
index 000000000..2408942ed
--- /dev/null
+++ b/app/javascript/mastodon/features/emoji/emoji_compressed.d.ts
@@ -0,0 +1,51 @@
+import type { BaseEmoji, EmojiData, NimbleEmojiIndex } from 'emoji-mart';
+import type { Category, Data, Emoji } from 'emoji-mart/dist-es/utils/data';
+
+/*
+ * The 'search' property, although not defined in the [`Emoji`]{@link node_modules/@types/emoji-mart/dist-es/utils/data.d.ts#Emoji} type,
+ * is used in the application.
+ * This could be due to an oversight by the library maintainer.
+ * The `search` property is defined and used [here]{@link node_modules/emoji-mart/dist/utils/data.js#uncompress}.
+ */
+export type Search = string;
+/*
+ * The 'skins' property does not exist in the application data.
+ * This could be a potential area of refactoring or error handling.
+ * The non-existence of 'skins' property is evident at [this location]{@link app/javascript/mastodon/features/emoji/emoji_compressed.js:121}.
+ */
+export type Skins = null;
+
+export type FilenameData = string[] | string[][];
+export type ShortCodesToEmojiDataKey =
+  | EmojiData['id']
+  | BaseEmoji['native']
+  | keyof NimbleEmojiIndex['emojis'];
+
+export type SearchData = [
+  BaseEmoji['native'],
+  Emoji['short_names'],
+  Search,
+  Emoji['unified']
+];
+
+export interface ShortCodesToEmojiData {
+  [key: ShortCodesToEmojiDataKey]: [FilenameData, SearchData];
+}
+export type EmojisWithoutShortCodes = FilenameData[];
+
+export type EmojiCompressed = [
+  ShortCodesToEmojiData,
+  Skins,
+  Category[],
+  Data['aliases'],
+  EmojisWithoutShortCodes
+];
+
+/*
+ * `emoji_compressed.js` uses `babel-plugin-preval`, which makes it difficult to convert to TypeScript.
+ * As a temporary solution, we are allowing a default export here to apply the TypeScript type `EmojiCompressed` to the JS file export.
+ * - {@link app/javascript/mastodon/features/emoji/emoji_compressed.js}
+ */
+declare const emojiCompressed: EmojiCompressed;
+
+export default emojiCompressed; // eslint-disable-line import/no-default-export
diff --git a/app/javascript/mastodon/features/emoji/emoji_compressed.js b/app/javascript/mastodon/features/emoji/emoji_compressed.js
index 3d577e50f..883bf21a4 100644
--- a/app/javascript/mastodon/features/emoji/emoji_compressed.js
+++ b/app/javascript/mastodon/features/emoji/emoji_compressed.js
@@ -118,6 +118,16 @@ Object.keys(emojiIndex.emojis).forEach(key => {
 // inconsistent behavior in dev mode
 module.exports = JSON.parse(JSON.stringify([
   shortCodesToEmojiData,
+  /*
+   * The property `skins` is not found in the current context.
+   * This could potentially lead to issues when interacting with modules or data structures
+   * that expect the presence of `skins` property.
+   * Currently, no definitions or references to `skins` property can be found in:
+   * - {@link node_modules/emoji-mart/dist/utils/data.js}
+   * - {@link node_modules/emoji-mart/data/all.json}
+   * - {@link app/javascript/mastodon/features/emoji/emoji_compressed.d.ts#Skins}
+   * Future refactorings or updates should consider adding definitions or handling for `skins` property.
+   */
   emojiMartData.skins,
   emojiMartData.categories,
   emojiMartData.aliases,
diff --git a/app/javascript/mastodon/features/emoji/emoji_mart_data_light.js b/app/javascript/mastodon/features/emoji/emoji_mart_data_light.js
deleted file mode 100644
index 11698937c..000000000
--- a/app/javascript/mastodon/features/emoji/emoji_mart_data_light.js
+++ /dev/null
@@ -1,43 +0,0 @@
-// The output of this module is designed to mimic emoji-mart's
-// "data" object, such that we can use it for a light version of emoji-mart's
-// emojiIndex.search functionality.
-import emojiCompressed from './emoji_compressed';
-import { unicodeToUnifiedName } from './unicode_to_unified_name';
-
-const [ shortCodesToEmojiData, skins, categories, short_names ] = emojiCompressed;
-
-const emojis = {};
-
-// decompress
-Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
-  let [
-    filenameData, // eslint-disable-line @typescript-eslint/no-unused-vars
-    searchData,
-  ] = shortCodesToEmojiData[shortCode];
-  let [
-    native,
-    short_names,
-    search,
-    unified,
-  ] = searchData;
-
-  if (!unified) {
-    // unified name can be derived from unicodeToUnifiedName
-    unified = unicodeToUnifiedName(native);
-  }
-
-  short_names = [shortCode].concat(short_names);
-  emojis[shortCode] = {
-    native,
-    search,
-    short_names,
-    unified,
-  };
-});
-
-export {
-  emojis,
-  skins,
-  categories,
-  short_names,
-};
diff --git a/app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts b/app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts
new file mode 100644
index 000000000..62cb84baf
--- /dev/null
+++ b/app/javascript/mastodon/features/emoji/emoji_mart_data_light.ts
@@ -0,0 +1,52 @@
+// The output of this module is designed to mimic emoji-mart's
+// "data" object, such that we can use it for a light version of emoji-mart's
+// emojiIndex.search functionality.
+import type { BaseEmoji } from 'emoji-mart';
+import type { Emoji } from 'emoji-mart/dist-es/utils/data';
+
+import type { Search, ShortCodesToEmojiData } from './emoji_compressed';
+import emojiCompressed from './emoji_compressed';
+import { unicodeToUnifiedName } from './unicode_to_unified_name';
+
+type Emojis = {
+  [key in keyof ShortCodesToEmojiData]: {
+    native: BaseEmoji['native'];
+    search: Search;
+    short_names: Emoji['short_names'];
+    unified: Emoji['unified'];
+  };
+};
+
+const [
+  shortCodesToEmojiData,
+  skins,
+  categories,
+  short_names,
+  _emojisWithoutShortCodes,
+] = emojiCompressed;
+
+const emojis: Emojis = {};
+
+// decompress
+Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
+  const [_filenameData, searchData] = shortCodesToEmojiData[shortCode];
+  const native = searchData[0];
+  let short_names = searchData[1];
+  const search = searchData[2];
+  let unified = searchData[3];
+
+  if (!unified) {
+    // unified name can be derived from unicodeToUnifiedName
+    unified = unicodeToUnifiedName(native);
+  }
+
+  if (short_names) short_names = [shortCode].concat(short_names);
+  emojis[shortCode] = {
+    native,
+    search,
+    short_names,
+    unified,
+  };
+});
+
+export { emojis, skins, categories, short_names };