From aca1750e010b9c1c2305e293dfc1a57d3d16b8f1 Mon Sep 17 00:00:00 2001 From: Paul Procopiou <1726774+pauldps@users.noreply.github.com> Date: Fri, 3 May 2024 16:52:15 -0400 Subject: [PATCH] fix: `wrapEmoji` fixes and improvements (#43) --- index.js | 3 ++- package-lock.json | 16 +++++++++++----- package.json | 3 ++- src/constants.js | 11 ----------- src/html.js | 12 +----------- src/wrapEmoji.js | 39 +++++++++++++++++++++++++++++++++++++++ test/index.js | 3 ++- test/wrapEmoji.js | 22 +++++++++++++++------- 8 files changed, 72 insertions(+), 37 deletions(-) create mode 100644 src/wrapEmoji.js diff --git a/index.js b/index.js index ac6be70..f8ba247 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ // ts-check -import { html, wrapEmoji } from './src/html.js' +import { html } from './src/html.js' import { strip } from './src/strip.js' +import { wrapEmoji } from './src/wrapEmoji.js' export { html, strip, wrapEmoji } diff --git a/package-lock.json b/package-lock.json index a248348..84e4111 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,9 +6,10 @@ "packages": { "": { "name": "@webmuds/colors", - "version": "0.2.0", + "version": "0.3.0", "license": "MIT", "dependencies": { + "emoji-regex": "10.3.0", "escape-html": "1.0.3" }, "devDependencies": { @@ -1273,10 +1274,9 @@ "dev": true }, "node_modules/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==", - "dev": true + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" }, "node_modules/enquirer": { "version": "2.4.1", @@ -4640,6 +4640,12 @@ "node": ">=8" } }, + "node_modules/string-width/node_modules/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==", + "dev": true + }, "node_modules/string.prototype.matchall": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", diff --git a/package.json b/package.json index 32f0ddc..694973a 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ }, "homepage": "https://github.com/webmuds/colors#readme", "dependencies": { - "escape-html": "1.0.3" + "escape-html": "1.0.3", + "emoji-regex": "10.3.0" }, "devDependencies": { "@dimensionalpocket/development": "github:dimensionalpocket/development-js#1.3.0" diff --git a/src/constants.js b/src/constants.js index 2d05133..1efec98 100644 --- a/src/constants.js +++ b/src/constants.js @@ -24,14 +24,3 @@ export const COLOR_RX = new RegExp('({((?:' + COLORS + '))}((?:(?!{(' + COLORS + * RegExp to strip all color tags. */ export const STRIP_RX = new RegExp('{(?:' + COLORS + '|/)}', 'gim') - -/** - * RegExp to wrap all emoji in tags. - */ -export const EMOJI_RX = /([\p{Emoji_Presentation}]+)/gu - -/** - * Template to use when replacing emoji. - * (wmE = WebMUDs Emoji) - */ -export const EMOJI_REPLACEMENT_TEMPLATE = '$1' diff --git a/src/html.js b/src/html.js index 617b183..8580a23 100644 --- a/src/html.js +++ b/src/html.js @@ -2,7 +2,7 @@ 'use strict' -import { COLOR_RX, HTML_REPLACEMENT_TEMPLATE, EMOJI_RX, EMOJI_REPLACEMENT_TEMPLATE } from './constants.js' +import { COLOR_RX, HTML_REPLACEMENT_TEMPLATE } from './constants.js' import escapeHtml from 'escape-html' /** @@ -21,13 +21,3 @@ export function html (text, escape = true) { } return escapedText.replace(COLOR_RX, HTML_REPLACEMENT_TEMPLATE) } - -/** - * Wraps all emoji in a custom tag. - * - * @param {string} text - * @return {string} - */ -export function wrapEmoji (text) { - return text.replace(EMOJI_RX, EMOJI_REPLACEMENT_TEMPLATE) -} diff --git a/src/wrapEmoji.js b/src/wrapEmoji.js new file mode 100644 index 0000000..04943a4 --- /dev/null +++ b/src/wrapEmoji.js @@ -0,0 +1,39 @@ +// @ts-check + +'use strict' + +import emojiRegex from 'emoji-regex' + +/** + * RegExp to wrap all emoji in tags. + */ +const EMOJI_RX = emojiRegexPattern() + +/** + * Template to use when replacing emoji. + * (wmE = WebMUDs Emoji) + */ +const EMOJI_REPLACEMENT_TEMPLATE = '$1' + +/** + * Wraps all emoji in a custom tag. + * + * @param {string} text + * @return {string} + */ +export function wrapEmoji (text) { + return text.replace(EMOJI_RX, EMOJI_REPLACEMENT_TEMPLATE) +} + +/** + * Helper that extracts the RegExp from emoji-regex + * and returns a new RegExp with capture enabled. + */ +function emojiRegexPattern () { + const patternFromLib = emojiRegex().toString() + const lastSlashIndex = patternFromLib.lastIndexOf('/') + const pattern = patternFromLib.slice(1, lastSlashIndex) + const flags = patternFromLib.slice(lastSlashIndex + 1) + + return new RegExp(`((?:${pattern})+)`, flags) +} diff --git a/test/index.js b/test/index.js index 2a98d69..3be08dc 100644 --- a/test/index.js +++ b/test/index.js @@ -4,7 +4,8 @@ import { expect } from '@dimensionalpocket/development' import { html, strip, wrapEmoji } from '../index.js' -import { html as htmlFromSrc, wrapEmoji as wrapEmojiFromSrc } from '../src/html.js' +import { html as htmlFromSrc } from '../src/html.js' +import { wrapEmoji as wrapEmojiFromSrc } from '../src/wrapEmoji.js' import { strip as stripFromSrc } from '../src/strip.js' describe('main require', function () { diff --git a/test/wrapEmoji.js b/test/wrapEmoji.js index 2873367..01e1543 100644 --- a/test/wrapEmoji.js +++ b/test/wrapEmoji.js @@ -3,30 +3,38 @@ 'use strict' import { expect } from '@dimensionalpocket/development' -import { wrapEmoji } from '../src/html.js' +import { wrapEmoji } from '../src/wrapEmoji.js' describe('#wrapEmoji', function () { - it('wraps emojis in ', function () { + it('wraps unicode emoji', function () { expect(wrapEmoji('πŸ˜…')).to.eq('πŸ˜…') }) + it('wraps non-unicode emoji', function () { + expect(wrapEmoji('βš”')).to.eq('βš”') + }) + + it('wraps unicode version of non-unicode emoji', function () { + expect(wrapEmoji('βš”οΈ')).to.eq('βš”οΈ') + }) + it('does not affect non-emoji', function () { expect(wrapEmoji('123abcπŸ˜…def456#*')).to.eq('123abcπŸ˜…def456#*') }) - it('tags all emojis', function () { + it('wraps all emoji', function () { expect(wrapEmoji('abcπŸ˜…defπŸ˜‚')).to.eq('abcπŸ˜…defπŸ˜‚') }) - it('tags all emojis in multiline text', function () { + it('wraps all emoji in multiline text', function () { expect(wrapEmoji('πŸ’― ab\ncπŸ˜…def\n πŸ˜‚')).to.eq('πŸ’― ab\ncπŸ˜…def\n πŸ˜‚') }) - it('tags sequential emojis in a single tag', function () { + it('wraps sequential emojis in a single tag', function () { expect(wrapEmoji('abc πŸ˜‚πŸ’―πŸ˜… def')).to.eq('abc πŸ˜‚πŸ’―πŸ˜… def') }) - it('breaks down sequential emojis split by multiline', function () { - expect(wrapEmoji('abc πŸ˜‚\nπŸ’―πŸ˜… def')).to.eq('abc πŸ˜‚\nπŸ’―πŸ˜… def') + it('breaks down sequential emoji split by multiline', function () { + expect(wrapEmoji('abc πŸ˜‚\nπŸ’―πŸ˜± def')).to.eq('abc πŸ˜‚\nπŸ’―πŸ˜± def') }) })