Source: app/util/messageParser/detectEmoji.js

import escapeStringRegexp from 'escape-string-regexp';
import flatten from 'lodash/flatten';
import find from 'lodash/find';
import trim from 'lodash/trim';
import emoticonData from '../../data/emoticon.json';
import { SEGMENT_EMOJI, SEGMENT_RAW } from '../../data/enum/SegmentType';
import { processMatches } from './index';

// Build a regex containing all the emoticons
const emoticonCollection = Object.values(emoticonData)
  .reduce((prev, curr) => {
    // Push the shortnames
    prev.push(escapeStringRegexp(curr.shortname));
    // Push the ascii combinations
    curr.ascii.map(ascii => prev.push(escapeStringRegexp(ascii)));
    return prev;
  }, [])
  .sort((a, b) => a.length - b.length)
  .join('|');

const emoticonCollectionRegex = new RegExp(`(?:^|\\s)(${emoticonCollection})(?=\\s|$)`, 'g');

/**
 * Detects an user tagging in each SEGMENT_RAW message segment provided to `input`. If an emoticon
 * is detected, will convert it to a SEGMENT_EMOJI and attach a emoji object.
 * @param input {Array<Object>} An array of message segments
 * @returns {Array<Object>} The processed array of message segments
 */
const detectEmoji = () => input =>
  flatten(
    input.map(segment => {
      const { type, data } = segment;
      switch (type) {
        case SEGMENT_RAW: {
          const match = data.match(emoticonCollectionRegex);
          if (match) {
            const dataMatch = [];
            let lastIndex = 0;
            match.forEach(emoji => {
              const index = data.indexOf(emoji, lastIndex);
              lastIndex = index + emoji.length;

              const { shortname, unicode } = find(
                Object.values(emoticonData),
                emoticon =>
                  emoticon.shortname === trim(emoji) || emoticon.ascii.includes(trim(emoji)),
              );

              return dataMatch.push({
                index,
                lastIndex,
                unicode,
                shortname,
              });
            });

            return processMatches(dataMatch, segment, SEGMENT_EMOJI);
          }

          return segment;
        }
        default:
          return segment;
      }
    }),
  );

export default detectEmoji;