-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathhelpers.js
More file actions
108 lines (96 loc) · 2.72 KB
/
Copy pathhelpers.js
File metadata and controls
108 lines (96 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
'use strict';
let emojiTable = null;
let emojiAliases = null;
let characterIndex = null;
function getEmojiTable() {
if (!emojiTable) {
emojiTable = nodebb.require('nodebb-plugin-emoji/build/emoji/table.json');
}
return emojiTable;
}
function getEmojiAliases() {
if (!emojiAliases) {
emojiAliases = nodebb.require('nodebb-plugin-emoji/build/emoji/aliases.json');
}
return emojiAliases;
}
function getCharacterIndex() {
if (!characterIndex) {
characterIndex = new Map();
Object.keys(getEmojiTable()).forEach((name) => {
const entry = getEmojiTable()[name];
if (entry && entry.character && !characterIndex.has(entry.character)) {
characterIndex.set(entry.character, name);
}
});
}
return characterIndex;
}
function resolveByName(name) {
if (!name || typeof name !== 'string') {
return null;
}
name = name.trim();
if (getEmojiTable()[name]) {
return name;
}
const aliases = getEmojiAliases();
if (aliases[name] && getEmojiTable()[aliases[name]]) {
return aliases[name];
}
return null;
}
function resolveReaction(content, tag) {
if (typeof content !== 'string' || !content.trim()) {
return null;
}
const trimmed = content.trim();
let reaction;
// `:shortcode:`
const shortcode = trimmed.match(/^:([a-z0-9_+-]+):$/i);
if (shortcode) {
reaction = resolveByName(shortcode[1]);
} else {
// Bare name (only accepted when it resolves to a local emoji)
reaction = resolveByName(trimmed);
if (!reaction) {
// Unicode grapheme
const index = getCharacterIndex();
if (index.has(trimmed)) {
reaction = index.get(trimmed);
}
// Retry without variation selectors (table entries may omit them, e.g. keycaps)
const noVariation = trimmed.replace(/\uFE0F/g, '');
if (!reaction && noVariation !== trimmed && index.has(noVariation)) {
reaction = index.get(noVariation);
}
const firstCodepoint = [...trimmed][0];
if (!reaction && firstCodepoint && index.has(firstCodepoint)) {
reaction = index.get(firstCodepoint);
}
}
}
// Custom emoji: the tag carries the emoji's identity, so it is consulted
// when the content alone does not resolve to a local emoji (a remote
// custom emoji whose name matches a built-in one is usable)
if (!reaction && Array.isArray(tag)) {
const emojiTag = tag.find(t => t && t.type === 'Emoji' && typeof t.name === 'string');
if (emojiTag) {
const name = emojiTag.name.replace(/^:|:$/g, '');
// Try to resolve as a local emoji first
reaction = resolveByName(name);
// If not local, return the tag so the caller can cache the custom emoji
if (!reaction) {
return { emoji: name, emojiTag };
}
}
}
return reaction;
}
module.exports = {
getEmojiTable,
getEmojiAliases,
getCharacterIndex,
resolveByName,
resolveReaction,
};