mirror of
https://github.com/ikatyang/emoji-cheat-sheet.git
synced 2026-02-05 22:55:18 +01:00
build: update infra (#652)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
2031
scripts/__snapshots__/generate.test.ts.snap
Normal file
2031
scripts/__snapshots__/generate.test.ts.snap
Normal file
File diff suppressed because one or more lines are too long
196
scripts/fetch.js
196
scripts/fetch.js
@@ -1,196 +0,0 @@
|
||||
const request = require("request");
|
||||
|
||||
/**
|
||||
* @typedef {string} EmojiLiteral
|
||||
* @returns {Promise<{ [githubEmojiId: string]: EmojiLiteral | [string] }>}
|
||||
*/
|
||||
async function getGithubEmojiIdMap() {
|
||||
return Object.fromEntries(
|
||||
Object.entries(
|
||||
/** @type {{ [id: string]: string }} */ (await fetchJson(
|
||||
"https://api.github.com/emojis",
|
||||
{
|
||||
headers: {
|
||||
"User-Agent": "https://github.com/ikatyang/emoji-cheat-sheet"
|
||||
}
|
||||
}
|
||||
))
|
||||
).map(([id, url]) => [
|
||||
id,
|
||||
url.includes("/unicode/")
|
||||
? getLast(url.split("/"))
|
||||
.split(".png")[0]
|
||||
.split("-")
|
||||
.map(codePointText =>
|
||||
String.fromCodePoint(Number.parseInt(codePointText, 16))
|
||||
)
|
||||
.join("")
|
||||
: [getLast(url.split("/")).split(".png")[0]] // github's custom emoji
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
async function getUnicodeEmojiCategoryIterator() {
|
||||
return getUnicodeEmojiCategoryIteratorFromText(
|
||||
await fetch("https://unicode.org/emoji/charts/full-emoji-list.txt")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
*/
|
||||
function* getUnicodeEmojiCategoryIteratorFromText(text) {
|
||||
const lines = text.split("\n");
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("@@")) {
|
||||
const value = line.substring(2);
|
||||
yield { type: "category", value };
|
||||
} else if (line.startsWith("@")) {
|
||||
const value = line.substring(1);
|
||||
yield { type: "subcategory", value };
|
||||
} else if (line.length) {
|
||||
const value = line
|
||||
.split("\t")[0]
|
||||
.split(" ")
|
||||
.map(_ => String.fromCodePoint(parseInt(_, 16)))
|
||||
.join("");
|
||||
yield { type: "emoji", value };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getCategorizeGithubEmojiIds() {
|
||||
const githubEmojiIdMap = await getGithubEmojiIdMap();
|
||||
/** @type {{ [emojiLiteral: string]: string[] }} */
|
||||
const emojiLiteralToGithubEmojiIdsMap = {};
|
||||
/** @type {{ [githubSpecificEmojiUri: string]: string[] }} */
|
||||
const githubSpecificEmojiUriToGithubEmojiIdsMap = {};
|
||||
for (const [emojiId, emojiLiteral] of Object.entries(githubEmojiIdMap)) {
|
||||
if (Array.isArray(emojiLiteral)) {
|
||||
const [uri] = emojiLiteral;
|
||||
if (!githubSpecificEmojiUriToGithubEmojiIdsMap[uri]) {
|
||||
githubSpecificEmojiUriToGithubEmojiIdsMap[uri] = [];
|
||||
}
|
||||
githubSpecificEmojiUriToGithubEmojiIdsMap[uri].push(emojiId);
|
||||
delete githubEmojiIdMap[emojiId];
|
||||
continue;
|
||||
}
|
||||
if (!emojiLiteralToGithubEmojiIdsMap[emojiLiteral]) {
|
||||
emojiLiteralToGithubEmojiIdsMap[emojiLiteral] = [];
|
||||
}
|
||||
emojiLiteralToGithubEmojiIdsMap[emojiLiteral].push(emojiId);
|
||||
}
|
||||
/** @type {{ [category: string]: { [subcategory: string]: Array<string[]> } }} */
|
||||
const categorizedEmojiIds = {};
|
||||
const categoryStack = [];
|
||||
for (const { type, value } of await getUnicodeEmojiCategoryIterator()) {
|
||||
switch (type) {
|
||||
case "category": {
|
||||
while (categoryStack.length) categoryStack.pop();
|
||||
const title = toTitleCase(value);
|
||||
categoryStack.push(title);
|
||||
categorizedEmojiIds[title] = {};
|
||||
break;
|
||||
}
|
||||
case "subcategory": {
|
||||
if (categoryStack.length > 1) categoryStack.pop();
|
||||
const title = toTitleCase(value);
|
||||
categoryStack.push(title);
|
||||
categorizedEmojiIds[categoryStack[0]][title] = [];
|
||||
break;
|
||||
}
|
||||
case "emoji": {
|
||||
const key = value.replace(/[\ufe00-\ufe0f\u200d]/g, "");
|
||||
if (key in emojiLiteralToGithubEmojiIdsMap) {
|
||||
const githubEmojiIds = emojiLiteralToGithubEmojiIdsMap[key];
|
||||
const [category, subcategory] = categoryStack;
|
||||
categorizedEmojiIds[category][subcategory].push(githubEmojiIds);
|
||||
for (const githubEmojiId of githubEmojiIds) {
|
||||
delete githubEmojiIdMap[githubEmojiId];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unexpected type ${JSON.stringify(type)}`);
|
||||
}
|
||||
}
|
||||
if (Object.keys(githubEmojiIdMap).length) {
|
||||
throw new Error(`Uncategorized emoji(s) found.`);
|
||||
}
|
||||
for (const category of Object.keys(categorizedEmojiIds)) {
|
||||
const subCategorizedEmojiIds = categorizedEmojiIds[category];
|
||||
const subcategories = Object.keys(subCategorizedEmojiIds);
|
||||
for (const subcategory of subcategories) {
|
||||
if (subCategorizedEmojiIds[subcategory].length === 0) {
|
||||
delete subCategorizedEmojiIds[subcategory];
|
||||
}
|
||||
}
|
||||
if (Object.keys(subCategorizedEmojiIds).length === 0) {
|
||||
delete categorizedEmojiIds[category];
|
||||
}
|
||||
}
|
||||
if (Object.keys(githubSpecificEmojiUriToGithubEmojiIdsMap).length) {
|
||||
categorizedEmojiIds["GitHub Custom Emoji"] = {
|
||||
"": Object.entries(githubSpecificEmojiUriToGithubEmojiIdsMap).map(
|
||||
([, v]) => v
|
||||
)
|
||||
};
|
||||
}
|
||||
return categorizedEmojiIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
*/
|
||||
function toTitleCase(str) {
|
||||
return str
|
||||
.replace(/-/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.replace(/[a-zA-Z]+/g, word => word[0].toUpperCase() + word.slice(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Array<T>} array
|
||||
*/
|
||||
function getLast(array) {
|
||||
return array[array.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {Partial<request.Options>} options
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
async function fetchJson(url, options = {}) {
|
||||
return JSON.parse(await fetch(url, options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {Partial<request.Options>} options
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async function fetch(url, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request.get(
|
||||
/** @type {request.Options} */ ({ url, ...options }),
|
||||
(error, response, html) => {
|
||||
if (!error && response.statusCode === 200) {
|
||||
resolve(html);
|
||||
} else {
|
||||
reject(
|
||||
error
|
||||
? error
|
||||
: `Unexpected response status code: ${response.statusCode}`
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getCategorizeGithubEmojiIds
|
||||
};
|
||||
160
scripts/fetch.ts
Normal file
160
scripts/fetch.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
type EmojiLiteral = string
|
||||
|
||||
async function getGithubEmojiIdMap(): Promise<{
|
||||
[githubEmojiId: string]: EmojiLiteral | [string]
|
||||
}> {
|
||||
return Object.fromEntries(
|
||||
Object.entries(
|
||||
await fetchJson<{ [id: string]: string }>(
|
||||
'https://api.github.com/emojis',
|
||||
{
|
||||
headers: {
|
||||
'User-Agent': 'https://github.com/ikatyang/emoji-cheat-sheet',
|
||||
},
|
||||
},
|
||||
),
|
||||
).map(([id, url]) => [
|
||||
id,
|
||||
url.includes('/unicode/')
|
||||
? getLast(url.split('/'))
|
||||
.split('.png')[0]
|
||||
.split('-')
|
||||
.map(codePointText =>
|
||||
String.fromCodePoint(Number.parseInt(codePointText, 16)),
|
||||
)
|
||||
.join('')
|
||||
: [getLast(url.split('/')).split('.png')[0]], // github's custom emoji
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
async function getUnicodeEmojiCategoryIterator() {
|
||||
return getUnicodeEmojiCategoryIteratorFromText(
|
||||
await fetchText('https://unicode.org/emoji/charts/full-emoji-list.txt'),
|
||||
)
|
||||
}
|
||||
|
||||
function* getUnicodeEmojiCategoryIteratorFromText(text: string) {
|
||||
const lines = text.split('\n')
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('@@')) {
|
||||
const value = line.substring(2)
|
||||
yield { type: 'category', value }
|
||||
} else if (line.startsWith('@')) {
|
||||
const value = line.substring(1)
|
||||
yield { type: 'subcategory', value }
|
||||
} else if (line.length) {
|
||||
const value = line
|
||||
.split('\t')[0]
|
||||
.split(' ')
|
||||
.map(_ => String.fromCodePoint(parseInt(_, 16)))
|
||||
.join('')
|
||||
yield { type: 'emoji', value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCategorizeGithubEmojiIds() {
|
||||
const githubEmojiIdMap = await getGithubEmojiIdMap()
|
||||
const emojiLiteralToGithubEmojiIdsMap: {
|
||||
[emojiLiteral: string]: string[]
|
||||
} = {}
|
||||
const githubSpecificEmojiUriToGithubEmojiIdsMap: {
|
||||
[githubSpecificEmojiUri: string]: string[]
|
||||
} = {}
|
||||
for (const [emojiId, emojiLiteral] of Object.entries(githubEmojiIdMap)) {
|
||||
if (Array.isArray(emojiLiteral)) {
|
||||
const [uri] = emojiLiteral
|
||||
if (!githubSpecificEmojiUriToGithubEmojiIdsMap[uri]) {
|
||||
githubSpecificEmojiUriToGithubEmojiIdsMap[uri] = []
|
||||
}
|
||||
githubSpecificEmojiUriToGithubEmojiIdsMap[uri].push(emojiId)
|
||||
delete githubEmojiIdMap[emojiId]
|
||||
continue
|
||||
}
|
||||
if (!emojiLiteralToGithubEmojiIdsMap[emojiLiteral]) {
|
||||
emojiLiteralToGithubEmojiIdsMap[emojiLiteral] = []
|
||||
}
|
||||
emojiLiteralToGithubEmojiIdsMap[emojiLiteral].push(emojiId)
|
||||
}
|
||||
const categorizedEmojiIds: {
|
||||
[category: string]: { [subcategory: string]: Array<string[]> }
|
||||
} = {}
|
||||
const categoryStack = []
|
||||
for (const { type, value } of await getUnicodeEmojiCategoryIterator()) {
|
||||
switch (type) {
|
||||
case 'category': {
|
||||
while (categoryStack.length) categoryStack.pop()
|
||||
const title = toTitleCase(value)
|
||||
categoryStack.push(title)
|
||||
categorizedEmojiIds[title] = {}
|
||||
break
|
||||
}
|
||||
case 'subcategory': {
|
||||
if (categoryStack.length > 1) categoryStack.pop()
|
||||
const title = toTitleCase(value)
|
||||
categoryStack.push(title)
|
||||
categorizedEmojiIds[categoryStack[0]][title] = []
|
||||
break
|
||||
}
|
||||
case 'emoji': {
|
||||
const key = value.replace(/[\ufe00-\ufe0f\u200d]/g, '')
|
||||
if (key in emojiLiteralToGithubEmojiIdsMap) {
|
||||
const githubEmojiIds = emojiLiteralToGithubEmojiIdsMap[key]
|
||||
const [category, subcategory] = categoryStack
|
||||
categorizedEmojiIds[category][subcategory].push(githubEmojiIds)
|
||||
for (const githubEmojiId of githubEmojiIds) {
|
||||
delete githubEmojiIdMap[githubEmojiId]
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unexpected type ${JSON.stringify(type)}`)
|
||||
}
|
||||
}
|
||||
if (Object.keys(githubEmojiIdMap).length) {
|
||||
throw new Error(`Uncategorized emoji(s) found.`)
|
||||
}
|
||||
for (const category of Object.keys(categorizedEmojiIds)) {
|
||||
const subCategorizedEmojiIds = categorizedEmojiIds[category]
|
||||
const subcategories = Object.keys(subCategorizedEmojiIds)
|
||||
for (const subcategory of subcategories) {
|
||||
if (subCategorizedEmojiIds[subcategory].length === 0) {
|
||||
delete subCategorizedEmojiIds[subcategory]
|
||||
}
|
||||
}
|
||||
if (Object.keys(subCategorizedEmojiIds).length === 0) {
|
||||
delete categorizedEmojiIds[category]
|
||||
}
|
||||
}
|
||||
if (Object.keys(githubSpecificEmojiUriToGithubEmojiIdsMap).length) {
|
||||
categorizedEmojiIds['GitHub Custom Emoji'] = {
|
||||
'': Object.entries(githubSpecificEmojiUriToGithubEmojiIdsMap).map(
|
||||
([, v]) => v,
|
||||
),
|
||||
}
|
||||
}
|
||||
return categorizedEmojiIds
|
||||
}
|
||||
|
||||
function toTitleCase(text: string) {
|
||||
return text
|
||||
.replace(/-/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/[a-zA-Z]+/g, word => word[0].toUpperCase() + word.slice(1))
|
||||
}
|
||||
|
||||
function getLast<T>(array: T[]) {
|
||||
return array[array.length - 1]
|
||||
}
|
||||
|
||||
async function fetchJson<T>(url: string, init?: RequestInit) {
|
||||
const response = await fetch(url, init)
|
||||
return (await response.json()) as T
|
||||
}
|
||||
|
||||
async function fetchText(url: string, init?: RequestInit) {
|
||||
const response = await fetch(url, init)
|
||||
return await response.text()
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
const { getCategorizeGithubEmojiIds } = require("./fetch");
|
||||
const { generateCheatSheet } = require("./markdown");
|
||||
|
||||
async function generate() {
|
||||
return generateCheatSheet(await getCategorizeGithubEmojiIds());
|
||||
}
|
||||
|
||||
if (require.main === /** @type {unknown} */ (module)) {
|
||||
generate().then(cheatSheet => console.log(cheatSheet));
|
||||
} else {
|
||||
module.exports = generate;
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
require("jest-playback").setup(__dirname);
|
||||
import { expect, test } from 'vitest'
|
||||
import setupPlayback from 'jest-playback'
|
||||
import { generate } from './generate.js'
|
||||
|
||||
const generate = require("./generate");
|
||||
await setupPlayback()
|
||||
|
||||
test("emoji-cheat-sheet", async () => {
|
||||
test('emoji-cheat-sheet', async () => {
|
||||
expect(await generate()).toMatchInlineSnapshot(`
|
||||
"# emoji-cheat-sheet
|
||||
|
||||
@@ -1594,5 +1596,5 @@ test("emoji-cheat-sheet", async () => {
|
||||
| [top](#github-custom-emoji) | :rage4: | \`:rage4:\` | :shipit: | \`:shipit:\` | [top](#table-of-contents) |
|
||||
| [top](#github-custom-emoji) | :suspect: | \`:suspect:\` | :trollface: | \`:trollface:\` | [top](#table-of-contents) |
|
||||
"
|
||||
`);
|
||||
});
|
||||
`)
|
||||
})
|
||||
10
scripts/generate.ts
Normal file
10
scripts/generate.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { getCategorizeGithubEmojiIds } from './fetch.js'
|
||||
import { generateCheatSheet } from './markdown.js'
|
||||
|
||||
export async function generate() {
|
||||
return generateCheatSheet(await getCategorizeGithubEmojiIds())
|
||||
}
|
||||
|
||||
if (process.argv[2] === 'run') {
|
||||
console.log(await generate())
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
const { name: repoName, repository } = require("../package.json");
|
||||
|
||||
const resource1 = "[GitHub Emoji API](https://api.github.com/emojis)";
|
||||
const resoruce2 =
|
||||
"[Unicode Full Emoji List](https://unicode.org/emoji/charts/full-emoji-list.html)";
|
||||
|
||||
const columns = 2;
|
||||
|
||||
const tocName = "Table of Contents";
|
||||
|
||||
/**
|
||||
* @typedef {Array<string[]>} GithubEmojiIds
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {{ [category: string]: { [subcategory: string]: GithubEmojiIds } }} categorizedGithubEmojiIds
|
||||
*/
|
||||
function generateCheatSheet(categorizedGithubEmojiIds) {
|
||||
const lineTexts = [];
|
||||
|
||||
lineTexts.push(`# ${repoName}`);
|
||||
lineTexts.push("");
|
||||
|
||||
lineTexts.push(
|
||||
`[](https://github.com/${repository}/actions?query=workflow%3A%22Up+to+Date%22)`
|
||||
);
|
||||
lineTexts.push("");
|
||||
|
||||
lineTexts.push(
|
||||
`This cheat sheet is automatically generated from ${resource1} and ${resoruce2}.`
|
||||
);
|
||||
lineTexts.push("");
|
||||
|
||||
const categories = Object.keys(categorizedGithubEmojiIds);
|
||||
|
||||
lineTexts.push(`## ${tocName}`);
|
||||
lineTexts.push("");
|
||||
lineTexts.push(...generateToc(categories));
|
||||
lineTexts.push("");
|
||||
|
||||
for (const category of categories) {
|
||||
lineTexts.push(`### ${category}`);
|
||||
lineTexts.push("");
|
||||
|
||||
const subcategorizeGithubEmojiIds = categorizedGithubEmojiIds[category];
|
||||
const subcategories = Object.keys(subcategorizeGithubEmojiIds);
|
||||
if (subcategories.length > 1) {
|
||||
lineTexts.push(...generateToc(subcategories));
|
||||
lineTexts.push("");
|
||||
}
|
||||
|
||||
for (const subcategory of subcategories) {
|
||||
if (subcategory) {
|
||||
lineTexts.push(`#### ${subcategory}`);
|
||||
lineTexts.push("");
|
||||
}
|
||||
|
||||
lineTexts.push(
|
||||
...generateTable(
|
||||
subcategorizeGithubEmojiIds[subcategory],
|
||||
`[top](#${getHeaderId(category)})`,
|
||||
`[top](#${getHeaderId(tocName)})`
|
||||
)
|
||||
);
|
||||
lineTexts.push("");
|
||||
}
|
||||
}
|
||||
|
||||
return lineTexts.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} headers
|
||||
*/
|
||||
function generateToc(headers) {
|
||||
return headers.map(header => `- [${header}](#${getHeaderId(header)})`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} header
|
||||
*/
|
||||
function getHeaderId(header) {
|
||||
return header
|
||||
.toLowerCase()
|
||||
.replace(/ /g, "-")
|
||||
.replace(/[^a-z0-9-]/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GithubEmojiIds} githubEmojiIds
|
||||
* @param {string} leftText
|
||||
* @param {string} rightText
|
||||
*/
|
||||
function generateTable(githubEmojiIds, leftText, rightText) {
|
||||
const lineTexts = [];
|
||||
|
||||
let header = "";
|
||||
let delimieter = "";
|
||||
|
||||
header += "| ";
|
||||
delimieter += "| - ";
|
||||
for (let i = 0; i < columns && i < githubEmojiIds.length; i++) {
|
||||
header += `| ico | shortcode `;
|
||||
delimieter += "| :-: | - ";
|
||||
}
|
||||
header += "| |";
|
||||
delimieter += "| - |";
|
||||
|
||||
lineTexts.push(header, delimieter);
|
||||
|
||||
for (let i = 0; i < githubEmojiIds.length; i += columns) {
|
||||
let lineText = `| ${leftText} `;
|
||||
for (let j = 0; j < columns; j++) {
|
||||
if (i + j < githubEmojiIds.length) {
|
||||
const emojiIds = githubEmojiIds[i + j];
|
||||
const emojiId = emojiIds[0];
|
||||
lineText += `| :${emojiId}: | \`:${emojiId}:\` `;
|
||||
for (let k = 1; k < emojiIds.length; k++) {
|
||||
lineText += `<br /> \`:${emojiIds[k]}:\` `;
|
||||
}
|
||||
} else if (githubEmojiIds.length > columns) {
|
||||
lineText += "| | ";
|
||||
}
|
||||
}
|
||||
lineText += `| ${rightText} |`;
|
||||
lineTexts.push(lineText);
|
||||
}
|
||||
|
||||
return lineTexts;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateCheatSheet
|
||||
};
|
||||
120
scripts/markdown.ts
Normal file
120
scripts/markdown.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { name as repoName, repository } from '../package.json'
|
||||
|
||||
const RESOURCE_1 = '[GitHub Emoji API](https://api.github.com/emojis)'
|
||||
const RESOURCE_2 =
|
||||
'[Unicode Full Emoji List](https://unicode.org/emoji/charts/full-emoji-list.html)'
|
||||
|
||||
const COLUMNS = 2
|
||||
|
||||
const TOC_NAME = 'Table of Contents'
|
||||
|
||||
type GithubEmojiIds = Array<string[]>
|
||||
|
||||
export function generateCheatSheet(categorizedGithubEmojiIds: {
|
||||
[category: string]: { [subCategory: string]: GithubEmojiIds }
|
||||
}) {
|
||||
const lineTexts = []
|
||||
|
||||
lineTexts.push(`# ${repoName}`)
|
||||
lineTexts.push('')
|
||||
|
||||
lineTexts.push(
|
||||
`[](https://github.com/${repository}/actions?query=workflow%3A%22Up+to+Date%22)`,
|
||||
)
|
||||
lineTexts.push('')
|
||||
|
||||
lineTexts.push(
|
||||
`This cheat sheet is automatically generated from ${RESOURCE_1} and ${RESOURCE_2}.`,
|
||||
)
|
||||
lineTexts.push('')
|
||||
|
||||
const categories = Object.keys(categorizedGithubEmojiIds)
|
||||
|
||||
lineTexts.push(`## ${TOC_NAME}`)
|
||||
lineTexts.push('')
|
||||
lineTexts.push(...generateToc(categories))
|
||||
lineTexts.push('')
|
||||
|
||||
for (const category of categories) {
|
||||
lineTexts.push(`### ${category}`)
|
||||
lineTexts.push('')
|
||||
|
||||
const subCategorizedGithubEmojiIds = categorizedGithubEmojiIds[category]
|
||||
const subCategories = Object.keys(subCategorizedGithubEmojiIds)
|
||||
if (subCategories.length > 1) {
|
||||
lineTexts.push(...generateToc(subCategories))
|
||||
lineTexts.push('')
|
||||
}
|
||||
|
||||
for (const subCategory of subCategories) {
|
||||
if (subCategory) {
|
||||
lineTexts.push(`#### ${subCategory}`)
|
||||
lineTexts.push('')
|
||||
}
|
||||
|
||||
lineTexts.push(
|
||||
...generateTable(
|
||||
subCategorizedGithubEmojiIds[subCategory],
|
||||
`[top](#${getHeaderId(category)})`,
|
||||
`[top](#${getHeaderId(TOC_NAME)})`,
|
||||
),
|
||||
)
|
||||
lineTexts.push('')
|
||||
}
|
||||
}
|
||||
|
||||
return lineTexts.join('\n')
|
||||
}
|
||||
|
||||
function generateToc(headers: string[]) {
|
||||
return headers.map(header => `- [${header}](#${getHeaderId(header)})`)
|
||||
}
|
||||
|
||||
function getHeaderId(header: string) {
|
||||
return header
|
||||
.toLowerCase()
|
||||
.replace(/ /g, '-')
|
||||
.replace(/[^a-z0-9-]/g, '')
|
||||
}
|
||||
|
||||
function generateTable(
|
||||
githubEmojiIds: GithubEmojiIds,
|
||||
leftText: string,
|
||||
rightText: string,
|
||||
) {
|
||||
const lineTexts = []
|
||||
|
||||
let header = ''
|
||||
let delimiter = ''
|
||||
|
||||
header += '| '
|
||||
delimiter += '| - '
|
||||
for (let i = 0; i < COLUMNS && i < githubEmojiIds.length; i++) {
|
||||
header += `| ico | shortcode `
|
||||
delimiter += '| :-: | - '
|
||||
}
|
||||
header += '| |'
|
||||
delimiter += '| - |'
|
||||
|
||||
lineTexts.push(header, delimiter)
|
||||
|
||||
for (let i = 0; i < githubEmojiIds.length; i += COLUMNS) {
|
||||
let lineText = `| ${leftText} `
|
||||
for (let j = 0; j < COLUMNS; j++) {
|
||||
if (i + j < githubEmojiIds.length) {
|
||||
const emojiIds = githubEmojiIds[i + j]
|
||||
const emojiId = emojiIds[0]
|
||||
lineText += `| :${emojiId}: | \`:${emojiId}:\` `
|
||||
for (let k = 1; k < emojiIds.length; k++) {
|
||||
lineText += `<br /> \`:${emojiIds[k]}:\` `
|
||||
}
|
||||
} else if (githubEmojiIds.length > COLUMNS) {
|
||||
lineText += '| | '
|
||||
}
|
||||
}
|
||||
lineText += `| ${rightText} |`
|
||||
lineTexts.push(lineText)
|
||||
}
|
||||
|
||||
return lineTexts
|
||||
}
|
||||
Reference in New Issue
Block a user