diff --git a/package.json b/package.json index 56d0364..3df9149 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "emoji-cheat-sheet-generator", + "name": "emoji-cheat-sheet", "version": "0.0.0-dev", "private": true, "author": "ikatyang", @@ -7,6 +7,7 @@ "homepage": "https://github.com/ikatyang/emoji-cheat-sheet", "repository": "https://github.com/ikatyang/emoji-cheat-sheet/tree/generator", "scripts": { + "lint": "tslint -p ./tsconfig.json", "generate": "node ./scripts/generate.js" }, "dependencies": { @@ -16,6 +17,7 @@ "devDependencies": { "@types/cheerio": "0.22.2", "@types/jest": "20.0.2", + "@types/node": "8.0.13", "@types/request": "0.0.47", "jest": "20.0.4", "jest-playback": "1.0.0", diff --git a/src/create-cheat-sheet.ts b/src/create-cheat-sheet.ts new file mode 100644 index 0000000..2a5a235 --- /dev/null +++ b/src/create-cheat-sheet.ts @@ -0,0 +1,157 @@ +import $ = require('cheerio'); +import request = require('request'); + +// tslint:disable-next-line:no-var-requires +const package_json = require('../package.json'); + +const repo_name = package_json.name; +const repo_author = package_json.author; + +const uncategorized = 'Uncategorized'; + +const api_url = 'https://api.github.com/emojis'; +const sheet_url = 'http://www.emoji-cheat-sheet.com'; + +const travis_repo_url = `https://travis-ci.org/${repo_author}/${repo_name}`; +const travis_badge_url = `https://travis-ci.org/${repo_author}/${repo_name}.svg?branch=master`; + +const url_descriptions = [ + ['GitHub Emoji API', api_url], + ['Emoji Cheat Sheet', sheet_url], +].map(([site_name, site_url]) => `[${site_name}](${site_url})`).join(' and '); + +// tslint:disable-next-line:max-line-length +const description = `This cheat sheet is automatically generated from ${url_descriptions}`; + +const toc_name = 'Table of Contents'; + +const top_name = 'top'; +const top_href = '#table-of-contents'; + +const column_divisions = 2; + +type Url = string; + +export interface Urls { + [site_name: string]: Url; +} + +export interface EmojiTable { + [category: string]: string[]; +} + +export async function create_cheat_sheet() { + const api_html = await get_html(api_url); + const sheet_html = await get_html(sheet_url); + + const api_emojis = Object.keys(JSON.parse(api_html)); + const emoji_table: EmojiTable = {}; + + const $html = $.load(sheet_html).root(); + $html.find('h2').each((_outer_index, category_element) => { + const emojis: string[] = []; + const category = $(category_element).text(); + $html.find(`#emoji-${category.toLowerCase()} li .name`).each((_inner_index, emoji_element) => { + const emoji = $(emoji_element).text(); + const index = api_emojis.indexOf(emoji); + if (index !== -1) { + api_emojis.splice(index, 1); + emojis.push(emoji); + } + }); + emoji_table[category] = emojis; + }); + + if (api_emojis.length > 0) { + emoji_table[uncategorized] = api_emojis; + } + + return create_table(emoji_table); +} + +function create_table(emoji_table: EmojiTable) { + const categories = Object.keys(emoji_table); + return format(` + + # ${repo_name} + + [![build](${travis_badge_url})](${travis_repo_url}) + + ${description} + + ## ${toc_name} + + ${categories.map(category => `- [${category}](#${category.toLowerCase()})`).join('\n')} + + ${ + categories.map(category => { + const emojis = emoji_table[category]; + return format(` + + ### ${category} + + ${create_table_head()} + ${create_table_content(emojis)} + + `); + }).join(('\n').repeat(2)) + } + + `); +} + +function create_table_content(emojis: string[]) { + let table_content = ''; + for (let i = 0; i < emojis.length; i += column_divisions) { + const row_emojis = emojis.slice(i, i + column_divisions); + while (row_emojis.length < column_divisions) { + row_emojis.push(''); + } + table_content += `${format(` + + | [${top_name}](${top_href}) |${ + row_emojis.map( + emoji => emoji.length !== 0 + ? ` :${emoji}: | \`:${emoji}:\` ` + : ' | ', + ).join(' | ') + }| + + `)}\n`; + } + return table_content; +} + +function create_table_head() { + return format(` + + | |${(' ico | emoji |').repeat(column_divisions)} + | - |${(' --- | ----- |').repeat(column_divisions)} + + `); +} + +function format(str: string) { + return str.trim().replace(/^ +/mg, ''); +} + +async function get_html(url: string) { + return new Promise((resolve, reject) => { + const options = {url}; + if (url === api_url) { + Object.assign(options, { + headers: {'User-Agent': 'https://github.com/ikatyang/emoji-cheat-sheet'}, + }); + } + request.get(options, (error, response, html) => { + if (error || response.statusCode !== 200) { + const error_message = Boolean(error) + ? error + : `Unexpected response status code: ${response.statusCode}`; + reject(error_message); + } else { + resolve(html); + } + }); + }); +} diff --git a/src/generate.ts b/src/generate.ts deleted file mode 100644 index c9d954f..0000000 --- a/src/generate.ts +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/env node - -const fs = require('fs'); -const path = require('path'); -const $ = require('cheerio'); -const request = require('request'); -const markdown = require('./markdown'); - -const title = 'emoji-cheat-sheet'; -const apiUrl = 'https://api.github.com/emojis'; -const sheetUrl = 'http://www.emoji-cheat-sheet.com'; - -const outDir = path.resolve(process.cwd(), './generated'); -const outFile = path.join(outDir, 'README.md'); - -const columnDivisions = 2; - -const getHTML = (url) => new Promise((resolve, reject) => { - const options = { url }; - if (url === apiUrl) { - Object.assign(options, { - headers: { 'User-Agent': 'https://github.com/ikatyang/emoji-cheat-sheet' }, - }); - } - request.get(options, (error, response, html) => { - if (error || response.statusCode !== 200) { - reject(error || `Unexpected response status code: ${response.statusCode}`); - } else { - resolve(html); - } - }); -}); - -Promise.all([getHTML(apiUrl), getHTML(sheetUrl)]).then(([apiHTML, sheetHTML]) => { - const apiEmojis = Object.keys(JSON.parse(apiHTML)); - const emojiTable = {}; - const $html = $.load(sheetHTML).root(); - $html.find('h2').each((_, categoryElement) => { - const emojis = []; - const category = $(categoryElement).text(); - $html.find(`#emoji-${category.toLowerCase()} li .name`).each((_, emojiElement) => { - const emoji = $(emojiElement).text(); - const index = apiEmojis.indexOf(emoji); - if (index !== -1) { - apiEmojis.splice(index, 1); - emojis.push(emoji); - } - }); - emojiTable[category] = emojis; - }); - if (apiEmojis.length > 0) { - emojiTable['Uncategorized'] = apiEmojis; - } - if (fs.existsSync(outDir)) { - if (!fs.statSync(outDir).isDirectory()) { - throw `OutDir '${outDir}' should be a directory.`; - } - } else { - fs.mkdirSync(outDir); - } - fs.writeFileSync(outFile, markdown.create({ - 'GitHub Emoji API': apiUrl, - 'Emoji Cheat Sheet': sheetUrl, - }, title, emojiTable, columnDivisions)); -}); diff --git a/src/markdown.ts b/src/markdown.ts deleted file mode 100644 index 11ff9ad..0000000 --- a/src/markdown.ts +++ /dev/null @@ -1,60 +0,0 @@ -const format = str => str.trim().replace(/^ +/mg, ''); - -module.exports = class Markdown { - - static create(urls, title, emojiTable, columnDivisions) { - const categories = Object.keys(emojiTable); - const urlDescriptions = Object.keys(urls).map((site) => `[${site}](${urls[site]})`).join(' and '); - return format(` - - # ${title} - - [![build](https://travis-ci.org/ikatyang/emoji-cheat-sheet.svg?branch=generator)](https://travis-ci.org/ikatyang/emoji-cheat-sheet) - - This cheat sheet is auto-generated from ${urlDescriptions} using [emoji-cheat-sheet-generator](https://github.com/ikatyang/emoji-cheat-sheet/tree/generator). - - ## Table of Contents - - ${categories.map(category => `- [${category}](#${category.toLowerCase()})`).join('\n')} - - ${ - categories.map(category => { - const emojis = emojiTable[category]; - return format(` - - ### ${category} - - ${this.createTable(emojis, columnDivisions)} - - `); - }).join(('\n').repeat(2)) - } - - `); - } - - static createTableHead(columnDivisions) { - return format(` - - | |${(' ico | emoji |').repeat(columnDivisions)} - | - |${(' --- | ----- |').repeat(columnDivisions)} - - `); - } - - static createTable(emojis, columnDivisions) { - let table = this.createTableHead(columnDivisions) + '\n'; - for (let i = 0; i < emojis.length; i += columnDivisions) { - const rowEmojis = emojis.slice(i, i + columnDivisions); - while (rowEmojis.length < columnDivisions) - rowEmojis.push(''); - table += format(` - - | [top](#table-of-contents) |${rowEmojis.map((emoji) => emoji ? ` :${emoji}: | \`:${emoji}:\` ` : ' | ').join(' | ')}| - - `) + '\n'; - } - return table; - } - -}; diff --git a/yarn.lock b/yarn.lock index 9fea5a5..87850a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -47,7 +47,7 @@ version "20.0.2" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-20.0.2.tgz#86c751121fb53dbd39bb1a08c45083da13f2dc67" -"@types/node@*": +"@types/node@*", "@types/node@8.0.13": version "8.0.13" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.13.tgz#530f0f9254209b0335bf5cc6387822594ef47093"