-
-
Notifications
You must be signed in to change notification settings - Fork 48
/
build.js
163 lines (148 loc) · 5.37 KB
/
build.js
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
const fs = require('fs')
const orderedEmojiData = fs.readFileSync('./emoji-order.txt', 'utf-8')
const groupedEmojiData = fs.readFileSync('./emoji-group.txt', 'utf-8')
const VARIATION_16 = String.fromCodePoint(0xfe0f)
const SKIN_TONE_VARIATION_DESC = /\sskin\stone(?:,|$)/
// Final data holder
const orderedEmoji = []
const dataByEmoji = {}
const dataByGroup = {}
const emojiComponents = {}
// The group data tells if the emoji is one of the following:
// component
// fully-qualified
// minimally-qualified
// unqualified
//
// We only want fully-qualified emoji in the output data
// # group: Smileys & Emotion
// |1--------------|
//
const GROUP_REGEX = /^#\sgroup:\s(?<name>.+)/
// 1F646 200D 2640 FE0F ; fully-qualified # 🙆♀️ E4.0 woman gesturing OK
// |1------------| |2--||3-| |4---------------|
// 1F469 200D 1F469 200D 1F467 200D 1F467 ; fully-qualified # 👩👩👧👧 E2.0 family: woman, woman, girl, girl
// |1------------| |2-| |3| |4-----------------------------|
//
const EMOJI_REGEX = /^[^#]+;\s(?<type>[\w-]+)\s+#\s(?<emoji>\S+)\sE(?<emojiversion>\d+\.\d)\s(?<desc>.+)/
let currentGroup = null
groupedEmojiData.split('\n').forEach(line => {
const groupMatch = line.match(GROUP_REGEX)
if (groupMatch) {
currentGroup = groupMatch.groups.name
} else {
const emojiMatch = line.match(EMOJI_REGEX)
if (emojiMatch) {
const {groups: {type, emoji, desc, emojiversion}} = emojiMatch
if (type === 'fully-qualified') {
if (line.match(SKIN_TONE_VARIATION_DESC)) return
dataByEmoji[emoji] = {
name: null,
slug: null,
group: currentGroup,
emoji_version: emojiversion,
unicode_version: null,
skin_tone_support: null
}
} else if (type === 'component') {
emojiComponents[slugify(desc)] = emoji
}
}
}
})
// 'flag: St. Kitts & Nevis' -> 'flag_st_kitts_nevis'
// 'family: woman, woman, boy, boy' -> 'family_woman_woman_boy_boy'
// 'A button (blood type)' -> 'a_button'
// 'Cocos (Keeling) Islands' -> 'cocos_islands'
//
// Returns machine readable emoji short code
function slugify(str) {
return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\(.+\)/g, '').trim().replace(/[\W|_]+/g, '_').toLowerCase()
}
// U+1F44B ; 6.0 # 👋 waving hand
// |1--| |2-|3----------|
//
// U+1F442 U+1F3FB ; 8.0 # 👂🏻 ear: light skin tone
// |1--| |2-|3--||4--------------|
//
// U+1F469 U+200D U+1F467 U+200D U+1F467 ; 6.0 # 👩👧👧 family: woman, girl, girl
// |1--| |2-|3-----||4----------------|
//
const ORDERED_EMOJI_REGEX = /.+\s;\s(?<version>[0-9.]+)\s#\s(?<emoji>\S+)\s(?<name>[^:]+)(?::\s)?(?<desc>.+)?/
let currentEmoji = null
orderedEmojiData.split('\n').forEach(line => {
if (line.length === 0) return
const match = line.match(ORDERED_EMOJI_REGEX)
if (!match) return
const {groups: {version, emoji, name, desc}} = match
const isSkinToneVariation = desc && !!desc.match(SKIN_TONE_VARIATION_DESC)
const fullName = desc && !isSkinToneVariation ? [name, desc].join(' ') : name
if (isSkinToneVariation) {
dataByEmoji[currentEmoji].skin_tone_support = true
dataByEmoji[currentEmoji].skin_tone_support_unicode_version = version
} else {
// Workaround for ordered data missing VARIATION_16 (smiling_face)
emojiWithOptionalVariation16 = dataByEmoji[emoji] ? emoji : emoji + VARIATION_16
const emojiEntry = dataByEmoji[emojiWithOptionalVariation16]
if (!emojiEntry) {
if (Object.values(emojiComponents).includes(emoji)) return
throw `${emoji} entry from emoji-order.txt match not found in emoji-group.txt`
}
currentEmoji = emojiWithOptionalVariation16
orderedEmoji.push(currentEmoji)
dataByEmoji[currentEmoji].name = fullName
dataByEmoji[currentEmoji].slug = slugify(fullName)
dataByEmoji[currentEmoji].unicode_version = version
dataByEmoji[currentEmoji].skin_tone_support = false
}
})
for (const emoji of orderedEmoji) {
const {group, skin_tone_support, skin_tone_support_unicode_version, name, slug, emoji_version, unicode_version} = dataByEmoji[emoji]
const existingGroup = dataByGroup[group]
if (!existingGroup) dataByGroup[group] = []
dataByGroup[group].push({
emoji,
skin_tone_support,
skin_tone_support_unicode_version,
name,
slug,
unicode_version,
emoji_version
})
}
// {
// "😀": {
// "group": "Smileys & Emotion",
// "name": "grinning face",
// "slug": "grinning_face",
// "version": "6.1",
// "skin_tone_support": false
// },
// ...
// }
fs.writeFileSync('data-by-emoji.json', JSON.stringify(dataByEmoji, null, 2))
// {
// "Smileys & Emotion": [
// {
// "emoji": "😀",
// "skin_tone_support": false,
// "name": "grinning face",
// "slug": "grinning_face",
// "version": "6.1"
// },
// ],
// ...
// }
fs.writeFileSync('data-by-group.json', JSON.stringify(dataByGroup, null, 2))
// [
// "😀",
// "😃",
// ...
// ]
fs.writeFileSync('data-ordered-emoji.json', JSON.stringify(orderedEmoji, null, 2))
// {
// "light_skin_tone": "🏻",
// "medium_light_skin_tone": "🏼",
// ...
// }
fs.writeFileSync('data-emoji-components.json', JSON.stringify(emojiComponents, null, 2))