diff --git a/Dockerfile b/Dockerfile index e1f462b5e..8c9503e44 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,8 +25,6 @@ COPY . ./ RUN mkdir -p __tests__/browser/__image_snapshots__/__diff_output__ -RUN make emojis - EXPOSE 9966 CMD ["test.browser"] diff --git a/Dockerfile.legacy b/Dockerfile.legacy index 9e408ddfb..37f275265 100644 --- a/Dockerfile.legacy +++ b/Dockerfile.legacy @@ -32,8 +32,6 @@ COPY . ./ RUN mkdir -p __tests__/browser/__image_snapshots__/__diff_output__ -RUN make emojis - EXPOSE 9966 CMD ["test.browser"] diff --git a/Makefile b/Makefile index 485120fb8..ca13857a5 100644 --- a/Makefile +++ b/Makefile @@ -6,14 +6,6 @@ DOCKER_WORKSPACE := "/markdown" MOUNTS = --volume ${PWD}:${DOCKER_WORKSPACE} \ --volume ${DOCKER_WORKSPACE}/node_modules -emojis: example/public/img/emojis ## Install our emojis. - -example/public/img/emojis: node_modules/@readme/emojis - rm -rf example/img/emojis - rm -rf example/public/img/emojis - mkdir -p example/public/img/emojis - cp node_modules/@readme/emojis/src/img/*.png example/public/img/emojis/ - ifeq ($(USE_LEGACY), true) dockerfile = -f Dockerfile.legacy endif diff --git a/__tests__/__snapshots__/index.test.js.snap b/__tests__/__snapshots__/index.test.js.snap index ba04fa5cb..71115eb9c 100644 --- a/__tests__/__snapshots__/index.test.js.snap +++ b/__tests__/__snapshots__/index.test.js.snap @@ -73,7 +73,7 @@ Object { `; exports[`emojis 1`] = ` -"

\\":joy:\\"
+"

😂

:unknown-emoji:

" `; diff --git a/__tests__/flavored-compilers/gemoji.test.js b/__tests__/flavored-compilers/gemoji.test.js new file mode 100644 index 000000000..16be2915a --- /dev/null +++ b/__tests__/flavored-compilers/gemoji.test.js @@ -0,0 +1,10 @@ +import { mdast, md } from '../../index'; + +describe('gemoji compiler', () => { + it('writes an gemojis back to shortcodes', () => { + const doc = ':poop:'; + const tree = mdast(doc); + + expect(md(tree)).toMatch(doc); + }); +}); diff --git a/__tests__/gemoji-parser.test.js b/__tests__/gemoji-parser.test.js index bf50b5d22..c8847cd17 100644 --- a/__tests__/gemoji-parser.test.js +++ b/__tests__/gemoji-parser.test.js @@ -3,9 +3,35 @@ const unified = require('unified'); const parser = require('../processor/parse/gemoji-parser'); -test('should output an image node for a known emoji', () => { +test('should output emoji', () => { const emoji = 'joy'; const markdown = `This is a gemoji :${emoji}:.`; + const ast = { + type: 'root', + children: [ + { + type: 'paragraph', + children: [ + { type: 'text', value: 'This is a gemoji ' }, + { + type: 'gemoji', + value: '😂', + name: emoji, + }, + { type: 'text', value: '.' }, + ], + }, + ], + }; + + expect(unified().use(remarkParse).use(parser).data('settings', { position: false }).parse(markdown)).toStrictEqual( + ast, + ); +}); + +test('should output an image node for a custom readme emoji', () => { + const emoji = 'owlbert'; + const markdown = `This is a gemoji :${emoji}:.`; const ast = { type: 'root', children: [ diff --git a/assets/img/emojis/owlbert-books.png b/assets/img/emojis/owlbert-books.png new file mode 100644 index 000000000..bb3e40f0c Binary files /dev/null and b/assets/img/emojis/owlbert-books.png differ diff --git a/assets/img/emojis/owlbert-mask.png b/assets/img/emojis/owlbert-mask.png new file mode 100644 index 000000000..92987a2ec Binary files /dev/null and b/assets/img/emojis/owlbert-mask.png differ diff --git a/assets/img/emojis/owlbert-reading.png b/assets/img/emojis/owlbert-reading.png new file mode 100644 index 000000000..954e0a1ac Binary files /dev/null and b/assets/img/emojis/owlbert-reading.png differ diff --git a/assets/img/emojis/owlbert-thinking.png b/assets/img/emojis/owlbert-thinking.png new file mode 100644 index 000000000..bf0663c2f Binary files /dev/null and b/assets/img/emojis/owlbert-thinking.png differ diff --git a/assets/img/emojis/owlbert.png b/assets/img/emojis/owlbert.png new file mode 100644 index 000000000..89a305b36 Binary files /dev/null and b/assets/img/emojis/owlbert.png differ diff --git a/lib/gemoji.js b/lib/gemoji.js new file mode 100644 index 000000000..e8a859fa2 --- /dev/null +++ b/lib/gemoji.js @@ -0,0 +1,16 @@ +const { nameToEmoji } = require('gemoji'); + +const owlmoji = ['owlbert-books', 'owlbert-mask', 'owlbert', 'owlbert-reading', 'owlbert-thinking']; + +class Emoji { + static kind = name => { + if (name in nameToEmoji) return 'gemoji'; + else if (name.match(/^fa-/)) return 'fontawesome'; + else if (owlmoji.includes(name)) return 'owlmoji'; + return null; + }; + + static nameToEmoji = nameToEmoji; +} + +module.exports = Emoji; diff --git a/package-lock.json b/package-lock.json index 9c0210066..c340f12b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@readme/syntax-highlighter": "^13.0.0", "copy-to-clipboard": "^3.3.3", "emoji-regex": "^10.3.0", + "gemoji": "^8.1.0", "hast-util-sanitize": "^4.0.0", "lodash.escape": "^4.0.1", "lodash.kebabcase": "^4.1.1", @@ -12671,6 +12672,15 @@ "node": ">= 4.0.0" } }, + "node_modules/gemoji": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/gemoji/-/gemoji-8.1.0.tgz", + "integrity": "sha512-HA4Gx59dw2+tn+UAa7XEV4ufUKI4fH1KgcbenVA9YKSj1QJTT0xh5Mwv5HMFNN3l2OtUe3ZIfuRwSyZS5pLIWw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -38125,6 +38135,11 @@ "globule": "^1.0.0" } }, + "gemoji": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/gemoji/-/gemoji-8.1.0.tgz", + "integrity": "sha512-HA4Gx59dw2+tn+UAa7XEV4ufUKI4fH1KgcbenVA9YKSj1QJTT0xh5Mwv5HMFNN3l2OtUe3ZIfuRwSyZS5pLIWw==" + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", diff --git a/package.json b/package.json index 30c96511a..83c8accd8 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ ], "scripts": { "build": "webpack --mode production", - "heroku-postbuild": "make emojis && webpack --mode production --config ./webpack.dev.js", + "heroku-postbuild": "webpack --mode production --config ./webpack.dev.js", "lint": "npm run lint:js && npm run lint:css", "lint:css": "stylelint '{components,styles}/**/*.{css,scss}'", "lint:js": "eslint --ext ts,tsx,js,jsx .", @@ -28,10 +28,10 @@ "watch": "webpack -w --progress --mode production" }, "dependencies": { - "@readme/emojis": "^6.0.0", "@readme/syntax-highlighter": "^13.0.0", "copy-to-clipboard": "^3.3.3", "emoji-regex": "^10.3.0", + "gemoji": "^8.1.0", "hast-util-sanitize": "^4.0.0", "lodash.escape": "^4.0.1", "lodash.kebabcase": "^4.1.1", diff --git a/processor/compile/gemoji.js b/processor/compile/gemoji.js new file mode 100644 index 000000000..3010fb368 --- /dev/null +++ b/processor/compile/gemoji.js @@ -0,0 +1,6 @@ +module.exports = function GemojiCompiler() { + const { Compiler } = this; + const { visitors } = Compiler.prototype; + + visitors.gemoji = node => `:${node.name}:`; +}; diff --git a/processor/compile/index.js b/processor/compile/index.js index e55cb7d52..fd111b06f 100644 --- a/processor/compile/index.js +++ b/processor/compile/index.js @@ -3,6 +3,7 @@ export { default as codeTabsCompiler } from './code-tabs'; export { default as divCompiler } from './div'; export { default as escapeCompiler } from './escape'; export { default as figureCompiler } from './figure'; +export { default as gemojiCompiler } from './gemoji'; export { default as htmlBlockCompiler } from './html-block'; export { default as iconCompiler } from './i'; export { default as imageCompiler } from './image'; diff --git a/processor/parse/gemoji-parser.js b/processor/parse/gemoji-parser.js index 523c33010..a7ddcc76b 100644 --- a/processor/parse/gemoji-parser.js +++ b/processor/parse/gemoji-parser.js @@ -1,9 +1,7 @@ -const Emoji = require('@readme/emojis').emoji; +const Emoji = require('../../lib/gemoji'); const { insertInlineTokenizerBefore } = require('./utils'); -const emojis = new Emoji(); - const colon = ':'; function tokenize(eat, value, silent) { @@ -11,46 +9,50 @@ function tokenize(eat, value, silent) { if (value.charAt(0) !== colon) return false; const pos = value.indexOf(colon, 1); - if (pos === -1) return false; - const subvalue = value.slice(1, pos); + const name = value.slice(1, pos); // Exit with true in silent if (silent) return true; - const match = colon + subvalue + colon; - - if (subvalue.substr(0, 3) === 'fa-') { - return eat(match)({ - type: 'i', - data: { - hName: 'i', - hProperties: { - className: ['fa', subvalue], + const match = colon + name + colon; + + switch (Emoji.kind(name)) { + case 'gemoji': + return eat(match)({ + type: 'gemoji', + value: Emoji.nameToEmoji[name], + name, + }); + case 'fontawesome': + return eat(match)({ + type: 'i', + data: { + hName: 'i', + hProperties: { + className: ['fa', name], + }, }, - }, - }); - } - - if (emojis.is(subvalue)) { - return eat(match)({ - type: 'image', - title: `:${subvalue}:`, - alt: `:${subvalue}:`, - url: `/public/img/emojis/${subvalue}.png`, - data: { - hProperties: { - className: 'emoji', - align: 'absmiddle', - height: '20', - width: '20', + }); + case 'owlmoji': + return eat(match)({ + type: 'image', + title: `:${name}:`, + alt: `:${name}:`, + url: `/public/img/emojis/${name}.png`, + data: { + hProperties: { + className: 'emoji', + align: 'absmiddle', + height: '20', + width: '20', + }, }, - }, - }); + }); + default: + return false; } - - return false; } function locate(value, fromIndex) {