2017-06-28 23:03:24 -06:00
|
|
|
import { join, resolve, basename } from 'path';
|
2020-04-06 22:00:29 -06:00
|
|
|
import {
|
|
|
|
mkdirp,
|
|
|
|
copy,
|
|
|
|
remove,
|
|
|
|
writeFile,
|
|
|
|
symlink,
|
|
|
|
} from 'fs-extra';
|
2017-06-30 20:05:53 -06:00
|
|
|
import { uniq } from 'lodash';
|
2017-06-25 15:15:30 -06:00
|
|
|
|
|
|
|
import * as cssBuilders from './css-builders';
|
|
|
|
import { clearCache } from './parse';
|
2017-09-11 17:55:02 -06:00
|
|
|
import { getCustomizations } from './customizations';
|
2017-06-25 15:15:30 -06:00
|
|
|
|
2017-09-11 17:55:02 -06:00
|
|
|
const nconf = require.main.require('nconf');
|
2017-09-06 15:50:00 -06:00
|
|
|
const winston = require.main.require('winston');
|
2017-11-14 14:52:15 -07:00
|
|
|
const plugins = require.main.require('./src/plugins');
|
2017-06-25 15:15:30 -06:00
|
|
|
|
2018-09-23 15:14:27 -06:00
|
|
|
export const assetsDir = join(__dirname, '../emoji');
|
2017-06-25 15:15:30 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
const linkDirs = (sourceDir: string, destDir: string) => {
|
2017-06-25 15:15:30 -06:00
|
|
|
const type = (process.platform === 'win32') ? 'junction' : 'dir';
|
2020-04-06 22:00:29 -06:00
|
|
|
return symlink(sourceDir, destDir, type);
|
2017-06-25 15:15:30 -06:00
|
|
|
};
|
|
|
|
|
2017-06-25 23:41:29 -06:00
|
|
|
export const tableFile = join(assetsDir, 'table.json');
|
|
|
|
export const aliasesFile = join(assetsDir, 'aliases.json');
|
|
|
|
export const asciiFile = join(assetsDir, 'ascii.json');
|
2017-06-27 18:07:41 -06:00
|
|
|
export const charactersFile = join(assetsDir, 'characters.json');
|
2017-06-25 23:41:29 -06:00
|
|
|
export const categoriesFile = join(assetsDir, 'categories.json');
|
|
|
|
export const packsFile = join(assetsDir, 'packs.json');
|
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
export default async function build() {
|
2017-11-14 14:52:15 -07:00
|
|
|
winston.verbose('[emoji] Building emoji assets');
|
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
// fetch the emoji definitions
|
2021-01-30 13:40:26 -05:00
|
|
|
const { packs }: { packs: EmojiDefinition[] } = await plugins.hooks.fire('filter:emoji.packs', { packs: [] });
|
2020-04-06 22:00:29 -06:00
|
|
|
// filter out invalid ones
|
|
|
|
const filtered = packs.filter((pack) => {
|
|
|
|
if (pack && pack.id && pack.name && pack.mode && pack.dictionary && pack.path) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-09-06 15:50:00 -06:00
|
|
|
|
2020-12-24 14:27:47 -07:00
|
|
|
winston.warn('[emoji] pack invalid: ', pack.path || pack.id);
|
2020-04-06 22:00:29 -06:00
|
|
|
return false;
|
|
|
|
});
|
2017-06-30 20:05:53 -06:00
|
|
|
|
2021-02-03 21:35:21 -07:00
|
|
|
winston.verbose(`[emoji] Loaded packs: ${filtered.map(pack => pack.id).join(', ')}`);
|
2017-06-25 15:15:30 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
await remove(assetsDir);
|
|
|
|
await mkdirp(assetsDir);
|
2017-06-27 18:07:41 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
const customizations = await getCustomizations();
|
2017-06-25 23:41:29 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
const table: MetaData.Table = {};
|
|
|
|
const aliases: MetaData.Aliases = {};
|
|
|
|
const ascii: MetaData.Ascii = {};
|
|
|
|
const characters: MetaData.Characters = {};
|
2017-06-25 23:41:29 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
const categoriesInfo: MetaData.Categories = {};
|
|
|
|
const packsInfo: MetaData.Packs = [];
|
2017-06-25 15:15:30 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
packs.forEach((pack) => {
|
|
|
|
packsInfo.push({
|
|
|
|
name: pack.name,
|
|
|
|
id: pack.id,
|
|
|
|
attribution: pack.attribution,
|
|
|
|
license: pack.license,
|
|
|
|
});
|
2017-06-30 20:05:53 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
Object.keys(pack.dictionary).forEach((key) => {
|
|
|
|
const name = key.toLowerCase();
|
|
|
|
const emoji = pack.dictionary[key];
|
2017-09-11 17:55:02 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
if (!table[name]) {
|
2017-09-11 17:55:02 -06:00
|
|
|
table[name] = {
|
|
|
|
name,
|
2020-04-06 22:00:29 -06:00
|
|
|
character: emoji.character || `:${name}:`,
|
|
|
|
image: emoji.image || '',
|
|
|
|
pack: pack.id,
|
|
|
|
aliases: emoji.aliases || [],
|
|
|
|
keywords: emoji.keywords || [],
|
2017-09-11 17:55:02 -06:00
|
|
|
};
|
2020-04-06 22:00:29 -06:00
|
|
|
}
|
2017-09-11 17:55:02 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
if (!characters[emoji.character]) {
|
|
|
|
characters[emoji.character] = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (emoji.aliases) {
|
2017-09-11 17:55:02 -06:00
|
|
|
emoji.aliases.forEach((alias) => {
|
|
|
|
const a = alias.toLowerCase();
|
|
|
|
if (!aliases[a]) {
|
|
|
|
aliases[a] = name;
|
|
|
|
}
|
|
|
|
});
|
2020-04-06 22:00:29 -06:00
|
|
|
}
|
2017-09-11 17:55:02 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
if (emoji.ascii) {
|
2017-09-11 17:55:02 -06:00
|
|
|
emoji.ascii.forEach((str) => {
|
|
|
|
if (!ascii[str]) {
|
|
|
|
ascii[str] = name;
|
|
|
|
}
|
|
|
|
});
|
2020-04-06 22:00:29 -06:00
|
|
|
}
|
2017-09-11 17:55:02 -06:00
|
|
|
|
2020-04-06 22:00:29 -06:00
|
|
|
const categories = emoji.categories || ['other'];
|
|
|
|
categories.forEach((category) => {
|
|
|
|
categoriesInfo[category] = categoriesInfo[category] || [];
|
|
|
|
categoriesInfo[category].push(name);
|
2017-09-11 17:55:02 -06:00
|
|
|
});
|
2020-04-06 22:00:29 -06:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
Object.keys(categoriesInfo).forEach((category) => {
|
|
|
|
categoriesInfo[category] = uniq(categoriesInfo[category]);
|
|
|
|
});
|
|
|
|
|
|
|
|
customizations.emojis.forEach((emoji) => {
|
|
|
|
const name = emoji.name.toLowerCase();
|
|
|
|
|
|
|
|
table[name] = {
|
|
|
|
name,
|
|
|
|
character: `:${name}:`,
|
|
|
|
pack: 'customizations',
|
|
|
|
keywords: [],
|
|
|
|
image: emoji.image,
|
|
|
|
aliases: emoji.aliases,
|
|
|
|
};
|
|
|
|
|
|
|
|
emoji.aliases.forEach((alias) => {
|
|
|
|
const a = alias.toLowerCase();
|
|
|
|
if (!aliases[a]) {
|
|
|
|
aliases[a] = name;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
emoji.ascii.forEach((str) => {
|
|
|
|
if (!ascii[str]) {
|
|
|
|
ascii[str] = name;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
categoriesInfo.custom = categoriesInfo.custom || [];
|
|
|
|
categoriesInfo.custom.push(name);
|
|
|
|
});
|
|
|
|
customizations.adjuncts.forEach((adjunct) => {
|
|
|
|
const name = adjunct.name;
|
|
|
|
if (!table[name]) { return; }
|
|
|
|
|
|
|
|
table[name] = {
|
|
|
|
...table[name],
|
|
|
|
aliases: table[name].aliases.concat(adjunct.aliases),
|
|
|
|
};
|
|
|
|
|
|
|
|
adjunct.aliases.forEach((alias) => { aliases[alias] = name; });
|
|
|
|
adjunct.ascii.forEach((str) => { ascii[str] = name; });
|
|
|
|
});
|
|
|
|
|
|
|
|
// generate CSS styles
|
2021-02-03 21:35:21 -07:00
|
|
|
const css = packs.map(pack => cssBuilders[pack.mode](pack)).join('\n');
|
2020-04-06 22:00:29 -06:00
|
|
|
const cssFile = `${css}\n.emoji-customizations {
|
|
|
|
display: inline-block;
|
|
|
|
height: 23px;
|
|
|
|
margin-top: -1px;
|
|
|
|
margin-bottom: -1px;
|
2021-02-03 21:35:21 -07:00
|
|
|
}`.split('\n').map(x => x.trim()).join('');
|
2020-04-06 22:00:29 -06:00
|
|
|
|
|
|
|
// handling copying or linking necessary assets
|
|
|
|
const assetOperations = packs.map(async (pack) => {
|
|
|
|
const dir = join(assetsDir, pack.id);
|
|
|
|
|
|
|
|
if (pack.mode === 'images') {
|
|
|
|
await linkDirs(resolve(pack.path, pack.images.directory), dir);
|
|
|
|
} else if (pack.mode === 'sprite') {
|
|
|
|
const filename = basename(pack.sprite.file);
|
|
|
|
await mkdirp(dir);
|
|
|
|
await copy(resolve(pack.path, pack.sprite.file), join(dir, filename));
|
|
|
|
} else { // pack.mode === 'font'
|
|
|
|
const fontFiles = [
|
|
|
|
pack.font.eot,
|
|
|
|
pack.font.svg,
|
|
|
|
pack.font.woff,
|
|
|
|
pack.font.ttf,
|
|
|
|
pack.font.woff2,
|
|
|
|
].filter(Boolean);
|
|
|
|
|
|
|
|
await mkdirp(dir);
|
|
|
|
await Promise.all(fontFiles.map(async (file) => {
|
|
|
|
const filename = basename(file);
|
|
|
|
copy(resolve(pack.path, file), join(dir, filename));
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
await Promise.all([
|
|
|
|
...assetOperations,
|
|
|
|
// store CSS styles
|
|
|
|
writeFile(join(assetsDir, 'styles.css'), cssFile, { encoding: 'utf8' }),
|
|
|
|
// persist metadata to disk
|
|
|
|
writeFile(tableFile, JSON.stringify(table)),
|
|
|
|
writeFile(aliasesFile, JSON.stringify(aliases)),
|
|
|
|
writeFile(asciiFile, JSON.stringify(ascii)),
|
|
|
|
writeFile(charactersFile, JSON.stringify(characters)),
|
|
|
|
writeFile(categoriesFile, JSON.stringify(categoriesInfo)),
|
|
|
|
writeFile(packsFile, JSON.stringify(packsInfo)),
|
|
|
|
// link customizations to public/uploads/emoji
|
|
|
|
linkDirs(
|
|
|
|
join(nconf.get('upload_path'), 'emoji'),
|
|
|
|
join(assetsDir, 'customizations')
|
|
|
|
),
|
|
|
|
]);
|
|
|
|
|
|
|
|
clearCache();
|
2017-06-25 15:15:30 -06:00
|
|
|
}
|