mastodon/app/javascript/mastodon/features/emoji/utils.ts
Echo c12b8f51c1
Some checks failed
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Check formatting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Bundler Audit / security (push) Has been cancelled
Haml Linting / lint (push) Has been cancelled
Emoji Component (#36293)
2025-09-30 13:06:02 +00:00

69 lines
1.8 KiB
TypeScript

import debug from 'debug';
import { emojiRegexPolyfill } from '@/mastodon/polyfills';
export function emojiLogger(segment: string) {
return debug(`emojis:${segment}`);
}
export function stringHasUnicodeEmoji(input: string): boolean {
return new RegExp(EMOJI_REGEX, supportedFlags()).test(input);
}
export function isUnicodeEmoji(input: string): boolean {
return (
input.length > 0 &&
new RegExp(`^(${EMOJI_REGEX})+$`, supportedFlags()).test(input)
);
}
export function stringHasUnicodeFlags(input: string): boolean {
if (supportsRegExpSets()) {
return new RegExp(
'\\p{RGI_Emoji_Flag_Sequence}|\\p{RGI_Emoji_Tag_Sequence}',
'v',
).test(input);
}
return new RegExp(
// First range is regional indicator symbols,
// Second is a black flag + 0-9|a-z tag chars + cancel tag.
// See: https://en.wikipedia.org/wiki/Regional_indicator_symbol
'(?:\uD83C[\uDDE6-\uDDFF]){2}|\uD83C\uDFF4(?:\uDB40[\uDC30-\uDC7A])+\uDB40\uDC7F',
).test(input);
}
// Constant as this is supported by all browsers.
const CUSTOM_EMOJI_REGEX = /:([a-z0-9_]+):/i;
export function isCustomEmoji(input: string): boolean {
return new RegExp(`^${CUSTOM_EMOJI_REGEX.source}$`, 'i').test(input);
}
export function stringHasCustomEmoji(input: string) {
return CUSTOM_EMOJI_REGEX.test(input);
}
export function stringHasAnyEmoji(input: string) {
return stringHasUnicodeEmoji(input) || stringHasCustomEmoji(input);
}
export function anyEmojiRegex() {
return new RegExp(
`${EMOJI_REGEX}|${CUSTOM_EMOJI_REGEX.source}`,
supportedFlags('gi'),
);
}
function supportsRegExpSets() {
return 'unicodeSets' in RegExp.prototype;
}
function supportedFlags(flags = '') {
if (supportsRegExpSets()) {
return `${flags}v`;
}
return flags;
}
const EMOJI_REGEX = emojiRegexPolyfill?.source ?? '\\p{RGI_Emoji}';