Browse Source

Replace emoji-regex with emojibase-regex

Danilo Bargen 5 years ago
parent
commit
48edf26162
4 changed files with 47 additions and 46 deletions
  1. 8 8
      package-lock.json
  2. 1 1
      package.json
  3. 28 34
      src/helpers/emoji.ts
  4. 10 3
      tests/ts/emoji_helpers.ts

+ 8 - 8
package-lock.json

@@ -1823,7 +1823,7 @@
         },
         "util": {
           "version": "0.10.3",
-          "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+          "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
           "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
           "requires": {
             "inherits": "2.0.1"
@@ -3579,10 +3579,10 @@
         "minimalistic-crypto-utils": "^1.0.0"
       }
     },
-    "emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    "emojibase-regex": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/emojibase-regex/-/emojibase-regex-3.1.0.tgz",
+      "integrity": "sha512-Ylnk6lMrqbNCOR40N8ix3Mi+J0GT1wu7vnsOjd4YhY6HyLmG8seOD1m/dZBls/dH+OKPVmcSaOc5GCq5IH7BTw=="
     },
     "emojis-list": {
       "version": "2.1.0",
@@ -5140,7 +5140,7 @@
       "dependencies": {
         "bluebird": {
           "version": "3.4.6",
-          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz",
+          "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz",
           "integrity": "sha1-AdqNgh2HgT0ViWfnQ9X+bGLPjA8=",
           "dev": true
         },
@@ -7806,7 +7806,7 @@
     },
     "readable-stream": {
       "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+      "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
       "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
       "requires": {
         "core-util-is": "~1.0.0",
@@ -7830,7 +7830,7 @@
         },
         "string_decoder": {
           "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
           "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
           "requires": {
             "safe-buffer": "~5.1.0"

+ 1 - 1
package.json

@@ -66,7 +66,7 @@
     "babel-loader": "^8.0.6",
     "core-js": "^3.1.4",
     "croppie": "^2.6.4",
-    "emoji-regex": "^8.0.0",
+    "emojibase-regex": "^3.1.0",
     "file-saver": "^2.0.2",
     "messageformat": "^2.2.1",
     "msgpack-lite": "~0.1.26",

+ 28 - 34
src/helpers/emoji.ts

@@ -15,7 +15,7 @@
  * along with Threema Web. If not, see <http://www.gnu.org/licenses/>.
  */
 
-import * as emojiRegex from 'emoji-regex/es2015/index';
+import EMOJI_REGEX from 'emojibase-regex';
 import twemoji from 'twemoji';
 
 import {isEmojiInfo} from './../typeguards';
@@ -24,7 +24,7 @@ import {isEmojiInfo} from './../typeguards';
 // Try to keep all functions pure!
 
 // Generated with tools/twemoji/generate-shortname-mapping.py
-const shortnames = {
+const SHORTNAMES = {
     '+1': '👍️',
     '+1_tone1': '👍🏻',
     '+1_tone2': '👍🏼',
@@ -3120,6 +3120,9 @@ const shortnames = {
     'zzz': '💤',
 };
 
+// Characters that should never be matches as emoji when unqualified.
+const TEXT_WHEN_UNQUALIFIED = ['©', '®', '™'];
+
 /**
  * Convert emoji unicode characters to images.
  */
@@ -3143,7 +3146,8 @@ export function emojify(text: string): string {
  * TODO: Rename once emojify fn is removed.
  */
 export function emojifyNew(text: string): Array<threema.EmojiInfo | string> {
-    const regex: RegExp = emojiRegex();
+    // Create a global RegExp, which stores state
+    const regex = new RegExp(EMOJI_REGEX, 'g');
     const result = [];
 
     const textVariantSelector = '\ufe0e';
@@ -3166,43 +3170,33 @@ export function emojifyNew(text: string): Array<threema.EmojiInfo | string> {
             result.push(text.substring(prevEndIndex, startIndex));
         }
 
+        let forceText = false;
+        if (TEXT_WHEN_UNQUALIFIED.includes(emoji)) {
+            // Emoji that should always be shown as text when unqualified
+            forceText = true;
+        } else if (emoji.length > 1 && emoji.slice(-1) === textVariantSelector) {
+            // Emoji with text variant selector
+            forceText = true;
+        }
+
         // Push emoji
-        const codepoint = twemoji.convert.toCodePoint(emoji);
-        const strippedCodepoint = codepoint.replace(/-fe0[ef]$/, '');
-        result.push({
-            emojiString: emoji,
-            imgPath: `emoji/png32/${strippedCodepoint}.png`,
-            codepoint: codepoint,
-        });
+        if (forceText) {
+            result.push(emoji);
+        } else {
+            const codepoint = twemoji.convert.toCodePoint(emoji);
+            const strippedCodepoint = codepoint.replace(/-fe0[ef]$/, '');
+            result.push({
+                emojiString: emoji,
+                imgPath: `emoji/png32/${strippedCodepoint}.png`,
+                codepoint: codepoint,
+            });
+        }
     }
 
     if (endIndex < text.length) {
         result.push(text.substring(endIndex, text.length));
     }
 
-    // Handle variant selectors.
-    // See also: https://github.com/mathiasbynens/emoji-regex/issues/61
-    for (let i = 0; i < result.length; i++) {
-        if (i > 0) {
-            const curr = result[i];
-            const prev = result[i - 1];
-            // If an emoji variant selector follows an emoji, append it
-            // to the emoji text.
-            if (curr === emojiVariantSelector && isEmojiInfo(prev)) {
-                if (!prev.emojiString.endsWith(emojiVariantSelector)) {
-                    prev.emojiString += emojiVariantSelector;
-                }
-                result[i] = null;
-            }
-            // If a text variant selector follows an emoji, convert the
-            // preceding emoji back to text.
-            if (curr === textVariantSelector && isEmojiInfo(prev)) {
-                result[i - 1] = prev.emojiString + textVariantSelector;
-                result[i] = null;
-            }
-        }
-    }
-
     return result.filter((x) => x !== null);
 }
 
@@ -3210,7 +3204,7 @@ export function emojifyNew(text: string): Array<threema.EmojiInfo | string> {
  * Translate a shortname to UTF8.
  */
 export function shortnameToUnicode(shortname: string): string | null {
-    return shortnames[shortname] || null;
+    return SHORTNAMES[shortname] || null;
 }
 
 /**

+ 10 - 3
tests/ts/emoji_helpers.ts

@@ -26,6 +26,7 @@ const emojiVariantSelector = '\ufe0f';
 
 const beer = '\ud83c\udf7b';
 const bird = '\ud83d\udc26';
+const biohazard = '\u2623';
 
 function makeEmoji(emojiString: string, codepoint?: string, imgCodepoint?: string): threema.EmojiInfo {
     if (codepoint === undefined) {
@@ -65,6 +66,8 @@ describe('Emoji Helpers', () => {
         it('emojifies single emoji', function() {
             expect(emojifyNew(bird))
                 .toEqual([makeEmoji(bird)]);
+            expect(emojifyNew(beer))
+                .toEqual([makeEmoji(beer)]);
         });
 
         it('emojifies multiple emoji', function() {
@@ -83,6 +86,11 @@ describe('Emoji Helpers', () => {
                 .toEqual(['hi ', makeEmoji(bird), makeEmoji(beer)]);
         });
 
+        it('emojifies most text-default codepoints', function() {
+            expect(emojifyNew(biohazard))
+                .toEqual([makeEmoji(biohazard)]);
+        });
+
         it('ignores certain codepoints', function() {
             expect(emojifyNew('©')).toEqual(['©']);
             expect(emojifyNew('®')).toEqual(['®']);
@@ -108,14 +116,13 @@ describe('Emoji Helpers', () => {
             expect(emojifyNew(exclamation + textVariantSelector))
                 .toEqual([exclamation + textVariantSelector]);
             expect(emojifyNew(exclamation + emojiVariantSelector))
-                .toEqual([makeEmoji(exclamation + emojiVariantSelector, '2757', '2757')]);
+                .toEqual([makeEmoji(exclamation + emojiVariantSelector, '2757-fe0f', '2757')]);
         });
     });
 
     describe('shortnameToUnicode', () => {
         it('converts valid shortnames', function() {
             expect(shortnameToUnicode('+1')).toEqual('\ud83d\udc4d\ufe0f');
-            expect(shortnameToUnicode('thumbup')).toEqual('\ud83d\udc4d\ufe0f');
             expect(shortnameToUnicode('thumbsup')).toEqual('\ud83d\udc4d\ufe0f');
         });
 
@@ -124,7 +131,7 @@ describe('Emoji Helpers', () => {
         });
 
         it('handles multi-codepoint emoji', function() {
-            expect(shortnameToUnicode('ch')).toEqual('\ud83c\udde8\ud83c\udded');
+            expect(shortnameToUnicode('flag_ch')).toEqual('\ud83c\udde8\ud83c\udded');
         });
     });