UNPKG

6.21 kBPlain TextView Raw
1import { join, resolve, basename } from 'path';
2import {
3 mkdirp,
4 copy,
5 remove,
6 writeFile,
7 symlink,
8} from 'fs-extra';
9import { uniq } from 'lodash';
10
11import * as cssBuilders from './css-builders';
12import { clearCache } from './parse';
13import { getCustomizations } from './customizations';
14
15const nconf = require.main.require('nconf');
16const winston = require.main.require('winston');
17const plugins = require.main.require('./src/plugins');
18
19export const assetsDir = join(__dirname, '../emoji');
20
21const linkDirs = (sourceDir: string, destDir: string) => {
22 const type = (process.platform === 'win32') ? 'junction' : 'dir';
23 return symlink(sourceDir, destDir, type);
24};
25
26export const tableFile = join(assetsDir, 'table.json');
27export const aliasesFile = join(assetsDir, 'aliases.json');
28export const asciiFile = join(assetsDir, 'ascii.json');
29export const charactersFile = join(assetsDir, 'characters.json');
30export const categoriesFile = join(assetsDir, 'categories.json');
31export const packsFile = join(assetsDir, 'packs.json');
32
33export default async function build() {
34 winston.verbose('[emoji] Building emoji assets');
35
36 // fetch the emoji definitions
37 const { packs }: { packs: EmojiDefinition[] } = await plugins.fireHook('filter:emoji.packs', { packs: [] });
38 // filter out invalid ones
39 const filtered = packs.filter((pack) => {
40 if (pack && pack.id && pack.name && pack.mode && pack.dictionary && pack.path) {
41 return true;
42 }
43
44 winston.warn('[emoji] pack invalid: ', pack.path || pack.id);
45 return false;
46 });
47
48 winston.verbose('[emoji] Loaded packs: ' + filtered.map((pack) => pack.id).join(', '));
49
50 await remove(assetsDir);
51 await mkdirp(assetsDir);
52
53 const customizations = await getCustomizations();
54
55 const table: MetaData.Table = {};
56 const aliases: MetaData.Aliases = {};
57 const ascii: MetaData.Ascii = {};
58 const characters: MetaData.Characters = {};
59
60 const categoriesInfo: MetaData.Categories = {};
61 const packsInfo: MetaData.Packs = [];
62
63 packs.forEach((pack) => {
64 packsInfo.push({
65 name: pack.name,
66 id: pack.id,
67 attribution: pack.attribution,
68 license: pack.license,
69 });
70
71 Object.keys(pack.dictionary).forEach((key) => {
72 const name = key.toLowerCase();
73 const emoji = pack.dictionary[key];
74
75 if (!table[name]) {
76 table[name] = {
77 name,
78 character: emoji.character || `:${name}:`,
79 image: emoji.image || '',
80 pack: pack.id,
81 aliases: emoji.aliases || [],
82 keywords: emoji.keywords || [],
83 };
84 }
85
86 if (!characters[emoji.character]) {
87 characters[emoji.character] = name;
88 }
89
90 if (emoji.aliases) {
91 emoji.aliases.forEach((alias) => {
92 const a = alias.toLowerCase();
93 if (!aliases[a]) {
94 aliases[a] = name;
95 }
96 });
97 }
98
99 if (emoji.ascii) {
100 emoji.ascii.forEach((str) => {
101 if (!ascii[str]) {
102 ascii[str] = name;
103 }
104 });
105 }
106
107 const categories = emoji.categories || ['other'];
108 categories.forEach((category) => {
109 categoriesInfo[category] = categoriesInfo[category] || [];
110 categoriesInfo[category].push(name);
111 });
112 });
113 });
114
115 Object.keys(categoriesInfo).forEach((category) => {
116 categoriesInfo[category] = uniq(categoriesInfo[category]);
117 });
118
119 customizations.emojis.forEach((emoji) => {
120 const name = emoji.name.toLowerCase();
121
122 table[name] = {
123 name,
124 character: `:${name}:`,
125 pack: 'customizations',
126 keywords: [],
127 image: emoji.image,
128 aliases: emoji.aliases,
129 };
130
131 emoji.aliases.forEach((alias) => {
132 const a = alias.toLowerCase();
133 if (!aliases[a]) {
134 aliases[a] = name;
135 }
136 });
137
138 emoji.ascii.forEach((str) => {
139 if (!ascii[str]) {
140 ascii[str] = name;
141 }
142 });
143
144 categoriesInfo.custom = categoriesInfo.custom || [];
145 categoriesInfo.custom.push(name);
146 });
147 customizations.adjuncts.forEach((adjunct) => {
148 const name = adjunct.name;
149 if (!table[name]) { return; }
150
151 table[name] = {
152 ...table[name],
153 aliases: table[name].aliases.concat(adjunct.aliases),
154 };
155
156 adjunct.aliases.forEach((alias) => { aliases[alias] = name; });
157 adjunct.ascii.forEach((str) => { ascii[str] = name; });
158 });
159
160 // generate CSS styles
161 const css = packs.map((pack) => cssBuilders[pack.mode](pack)).join('\n');
162 const cssFile = `${css}\n.emoji-customizations {
163 display: inline-block;
164 height: 23px;
165 margin-top: -1px;
166 margin-bottom: -1px;
167 }`.split('\n').map((x) => x.trim()).join('');
168
169 // handling copying or linking necessary assets
170 const assetOperations = packs.map(async (pack) => {
171 const dir = join(assetsDir, pack.id);
172
173 if (pack.mode === 'images') {
174 await linkDirs(resolve(pack.path, pack.images.directory), dir);
175 } else if (pack.mode === 'sprite') {
176 const filename = basename(pack.sprite.file);
177 await mkdirp(dir);
178 await copy(resolve(pack.path, pack.sprite.file), join(dir, filename));
179 } else { // pack.mode === 'font'
180 const fontFiles = [
181 pack.font.eot,
182 pack.font.svg,
183 pack.font.woff,
184 pack.font.ttf,
185 pack.font.woff2,
186 ].filter(Boolean);
187
188 await mkdirp(dir);
189 await Promise.all(fontFiles.map(async (file) => {
190 const filename = basename(file);
191 copy(resolve(pack.path, file), join(dir, filename));
192 }));
193 }
194 });
195
196 await Promise.all([
197 ...assetOperations,
198 // store CSS styles
199 writeFile(join(assetsDir, 'styles.css'), cssFile, { encoding: 'utf8' }),
200 // persist metadata to disk
201 writeFile(tableFile, JSON.stringify(table)),
202 writeFile(aliasesFile, JSON.stringify(aliases)),
203 writeFile(asciiFile, JSON.stringify(ascii)),
204 writeFile(charactersFile, JSON.stringify(characters)),
205 writeFile(categoriesFile, JSON.stringify(categoriesInfo)),
206 writeFile(packsFile, JSON.stringify(packsInfo)),
207 // link customizations to public/uploads/emoji
208 linkDirs(
209 join(nconf.get('upload_path'), 'emoji'),
210 join(assetsDir, 'customizations')
211 ),
212 ]);
213
214 clearCache();
215}