Migrate pretty-text to `.js` extensions (#9243)

Migrate pretty-text to .js extensions (#9243)

diff --git a/app/assets/javascripts/pretty-text/censored-words.js b/app/assets/javascripts/pretty-text/censored-words.js
new file mode 100644
index 0000000..4453e3f
--- /dev/null
+++ b/app/assets/javascripts/pretty-text/censored-words.js
@@ -0,0 +1,26 @@
+export function censorFn(regexpString, replacementLetter) {
+  if (regexpString) {
+    let censorRegexp = new RegExp(regexpString, "ig");
+    replacementLetter = replacementLetter || "■";
+
+    return function(text) {
+      text = text.replace(censorRegexp, (fullMatch, ...groupMatches) => {
+        const stringMatch = groupMatches.find(g => typeof g === "string");
+        return fullMatch.replace(
+          stringMatch,
+          new Array(stringMatch.length + 1).join(replacementLetter)
+        );
+      });
+
+      return text;
+    };
+  }
+
+  return function(t) {
+    return t;
+  };
+}
+
+export function censor(text, censoredRegexp, replacementLetter) {
+  return censorFn(censoredRegexp, replacementLetter)(text);
+}
diff --git a/app/assets/javascripts/pretty-text/censored-words.js.es6 b/app/assets/javascripts/pretty-text/censored-words.js.es6
deleted file mode 100644
index 4453e3f..0000000
--- a/app/assets/javascripts/pretty-text/censored-words.js.es6
+++ /dev/null
@@ -1,26 +0,0 @@
-export function censorFn(regexpString, replacementLetter) {
-  if (regexpString) {
-    let censorRegexp = new RegExp(regexpString, "ig");
-    replacementLetter = replacementLetter || "■";
-
-    return function(text) {
-      text = text.replace(censorRegexp, (fullMatch, ...groupMatches) => {
-        const stringMatch = groupMatches.find(g => typeof g === "string");
-        return fullMatch.replace(
-          stringMatch,
-          new Array(stringMatch.length + 1).join(replacementLetter)
-        );
-      });
-
-      return text;
-    };
-  }
-
-  return function(t) {
-    return t;
-  };
-}
-
-export function censor(text, censoredRegexp, replacementLetter) {
-  return censorFn(censoredRegexp, replacementLetter)(text);
-}
diff --git a/app/assets/javascripts/pretty-text/context/inline-onebox-css-classes.js.erb b/app/assets/javascripts/pretty-text/context/inline-onebox-css-classes.js.erb
new file mode 100644
index 0000000..a252fb2
--- /dev/null
+++ b/app/assets/javascripts/pretty-text/context/inline-onebox-css-classes.js.erb
@@ -0,0 +1,5 @@
+export const INLINE_ONEBOX_LOADING_CSS_CLASS =
+  "<%= CookedPostProcessor::INLINE_ONEBOX_LOADING_CSS_CLASS %>";
+
+export const INLINE_ONEBOX_CSS_CLASS =
+  "<%= CookedPostProcessor::INLINE_ONEBOX_CSS_CLASS %>";
diff --git a/app/assets/javascripts/pretty-text/context/inline-onebox-css-classes.js.es6.erb b/app/assets/javascripts/pretty-text/context/inline-onebox-css-classes.js.es6.erb
deleted file mode 100644
index a252fb2..0000000
--- a/app/assets/javascripts/pretty-text/context/inline-onebox-css-classes.js.es6.erb
+++ /dev/null
@@ -1,5 +0,0 @@
-export const INLINE_ONEBOX_LOADING_CSS_CLASS =
-  "<%= CookedPostProcessor::INLINE_ONEBOX_LOADING_CSS_CLASS %>";
-
-export const INLINE_ONEBOX_CSS_CLASS =
-  "<%= CookedPostProcessor::INLINE_ONEBOX_CSS_CLASS %>";
diff --git a/app/assets/javascripts/pretty-text/emoji.js b/app/assets/javascripts/pretty-text/emoji.js
new file mode 100644
index 0000000..fa7754d
--- /dev/null
+++ b/app/assets/javascripts/pretty-text/emoji.js
@@ -0,0 +1,243 @@
+import {
+  emojis,
+  aliases,
+  searchAliases,
+  translations,
+  tonableEmojis,
+  replacements
+} from "pretty-text/emoji/data";
+import { IMAGE_VERSION } from "pretty-text/emoji/version";
+
+const extendedEmoji = {};
+
+export function registerEmoji(code, url) {
+  code = code.toLowerCase();
+  extendedEmoji[code] = url;
+}
+
+export function extendedEmojiList() {
+  return extendedEmoji;
+}
+
+const emojiHash = {};
+
+export function buildReplacementsList(emojiReplacements) {
+  return Object.keys(emojiReplacements)
+    .sort()
+    .reverse()
+    .map(emoji => {
+      return emoji
+        .split("")
+        .map(chr => {
+          return (
+            "\\u" +
+            chr
+              .charCodeAt(0)
+              .toString(16)
+              .padStart(4, "0")
+          );
+        })
+        .join("");
+    })
+    .join("|");
+}
+
+let replacementListCache;
+const unicodeRegexpCache = {};
+
+function replacementList() {
+  if (replacementListCache === undefined) {
+    replacementListCache = buildReplacementsList(replacements);
+  }
+
+  return replacementListCache;
+}
+
+function unicodeRegexp(inlineEmoji) {
+  if (unicodeRegexpCache[inlineEmoji] === undefined) {
+    const emojiExpression = inlineEmoji
+      ? "|:[^\\s:]+(?::t\\d)?:?"
+      : "|\\B:[^\\s:]+(?::t\\d)?:?\\B";
+
+    unicodeRegexpCache[inlineEmoji] = new RegExp(
+      replacementList() + emojiExpression,
+      "g"
+    );
+  }
+
+  return unicodeRegexpCache[inlineEmoji];
+}
+
+// add all default emojis
+emojis.forEach(code => (emojiHash[code] = true));
+
+// and their aliases
+const aliasHash = {};
+Object.keys(aliases).forEach(name => {
+  aliases[name].forEach(alias => (aliasHash[alias] = name));
+});
+
+function isReplacableInlineEmoji(string, index, inlineEmoji) {
+  if (inlineEmoji) return true;
+
+  // index depends on regex; when `inlineEmoji` is false, the regex starts
+  // with a `\B` character, so there's no need to subtract from the index
+  const beforeEmoji = string.slice(0, index - (inlineEmoji ? 1 : 0));
+
+  return (
+    beforeEmoji.length === 0 ||
+    /(?:\s|[>.,\/#!$%^&*;:{}=\-_`~()])$/.test(beforeEmoji) ||
+    new RegExp(`(?:${replacementList()})$`).test(beforeEmoji)
+  );
+}
+
+export function performEmojiUnescape(string, opts) {
+  if (!string || typeof string !== "string") {
+    return;
+  }
+
+  const inlineEmoji = opts.inlineEmoji;
+  const regexp = unicodeRegexp(inlineEmoji);
+
+  return string.replace(regexp, (m, index) => {
+    const isEmoticon = opts.enableEmojiShortcuts && !!translations[m];
+    const isUnicodeEmoticon = !!replacements[m];
+    let emojiVal;
+    if (isEmoticon) {
+      emojiVal = translations[m];
+    } else if (isUnicodeEmoticon) {
+      emojiVal = replacements[m];
+    } else {
+      emojiVal = m.slice(1, m.length - 1);
+    }
+    const hasEndingColon = m.lastIndexOf(":") === m.length - 1;
+    const url = buildEmojiUrl(emojiVal, opts);
+    const classes = isCustomEmoji(emojiVal, opts)
+      ? "emoji emoji-custom"
+      : "emoji";
+
+    const isReplacable =
+      (isEmoticon || hasEndingColon || isUnicodeEmoticon) &&
+      isReplacableInlineEmoji(string, index, inlineEmoji);
+
+    return url && isReplacable
+      ? `<img src='${url}' ${
+          opts.skipTitle ? "" : `title='${emojiVal}'`
+        } alt='${emojiVal}' class='${classes}'>`
+      : m;
+  });
+}
+
+export function performEmojiEscape(string, opts) {
+  const inlineEmoji = opts.inlineEmoji;
+  const regexp = unicodeRegexp(inlineEmoji);
+
+  return string.replace(regexp, (m, index) => {
+    if (isReplacableInlineEmoji(string, index, inlineEmoji)) {
+      if (!!translations[m]) {
+        return opts.emojiShortcuts ? `:${translations[m]}:` : m;
+      } else if (!!replacements[m]) {
+        return `:${replacements[m]}:`;
+      }
+    }
+
+    return m;
+  });
+}
+
+export function isCustomEmoji(code, opts) {
+  code = code.toLowerCase();
+  if (extendedEmoji.hasOwnProperty(code)) return true;
+  if (opts && opts.customEmoji && opts.customEmoji.hasOwnProperty(code))
+    return true;
+  return false;
+}
+
+export function buildEmojiUrl(code, opts) {
+  let url;
+  code = String(code).toLowerCase();
+  if (extendedEmoji.hasOwnProperty(code)) {
+    url = extendedEmoji[code];
+  }
+
+  if (opts && opts.customEmoji && opts.customEmoji[code]) {
+    url = opts.customEmoji[code];
+  }
+
+  const noToneMatch = code.match(/([^:]+):?/);
+  if (
+    noToneMatch &&
+    !url &&
+    (emojiHash.hasOwnProperty(noToneMatch[1]) ||
+      aliasHash.hasOwnProperty(noToneMatch[1]))
+  ) {
+    url = opts.getURL(

[... diff too long, it was truncated ...]

GitHub sha: c1505665

This commit appears in #9243 which was merged by eviltrout.