diff --git a/src/index.ts b/src/index.ts index 16a2afc5e04191e03996555fa3b7691f38f999d1..b8fa44a6145a35cf04e19042bda33e0db456ca2b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,7 +46,8 @@ export { MfmCenter, // inline - MfmEmoji, + MfmUnicodeEmoji, + MfmEmojiCode, MfmBold, MfmSmall, MfmItalic, diff --git a/src/node.ts b/src/node.ts index 04556931f1f944c3d5a49e5fe58488f638b9b47c..39875c4dc7ddad3814674ab74b394fa326f447cc 100644 --- a/src/node.ts +++ b/src/node.ts @@ -45,14 +45,21 @@ export type MfmCenter = { children: MfmInline[]; }; -export type MfmInline = MfmEmoji | MfmBold | MfmSmall | MfmItalic | MfmStrike | MfmInlineCode | - MfmMathInline | MfmMention | MfmHashtag | MfmUrl | MfmLink | MfmFn | MfmText; +export type MfmInline = MfmUnicodeEmoji | MfmEmojiCode | MfmBold | MfmSmall | MfmItalic | MfmStrike | + MfmInlineCode | MfmMathInline | MfmMention | MfmHashtag | MfmUrl | MfmLink | MfmFn | MfmText; -export type MfmEmoji = { - type: 'emoji'; +export type MfmUnicodeEmoji = { + type: 'unicodeEmoji'; props: { - emoji?: string; - name?: string; + emoji: string; + }; + children?: []; +}; + +export type MfmEmojiCode = { + type: 'emojiCode'; + props: { + name: string; }; children?: []; }; diff --git a/src/parser.pegjs b/src/parser.pegjs index b1795f374e616d44520cd6a0e8c5acb093ed7944..d785ca9d599394cb2d7a1a68b435b56b189ba66b 100644 --- a/src/parser.pegjs +++ b/src/parser.pegjs @@ -42,7 +42,7 @@ fullParser = nodes:(&. n:(block / inline) { return n; })* { return mergeText(nodes); } plainParser - = nodes:(&. n:(emoji / text) { return n; })* { return mergeText(nodes); } + = nodes:(&. n:(emojiCode / unicodeEmoji / text) { return n; })* { return mergeText(nodes); } inlineParser = nodes:(&. n:inline { return n; })* { return mergeText(nodes); } @@ -135,7 +135,8 @@ center // inline - = emoji + = emojiCode + / unicodeEmoji / big / bold / small @@ -150,25 +151,24 @@ inline / fn / text -// inline: emoji +// inline: emoji code -emoji - = customEmoji / unicodeEmoji - -customEmoji - = ":" name:emojiName ":" +emojiCode + = ":" name:emojiCodeName ":" { - return createNode('emoji', { name: name }); + return createNode('emojiCode', { name: name }); } -emojiName +emojiCodeName = [a-z0-9_+-]i+ { return text(); } +// inline: unicode emoji + // NOTE: if the text matches one of the emojis, it will count the length of the emoji sequence and consume it. unicodeEmoji = &{ return matchUnicodeEmoji(); } (&{ return consumeDynamically(); } .)+ { - return createNode('emoji', { emoji: text() }); + return createNode('unicodeEmoji', { emoji: text() }); } // inline: big diff --git a/src/util.ts b/src/util.ts index 12a21e8c81af191106dddaa4615af1e032d76a93..c4323317cda3b0362ef7c225b684bcb9ea6f85f5 100644 --- a/src/util.ts +++ b/src/util.ts @@ -60,16 +60,11 @@ export function stringifyNode(node: MfmNode): string { return `<center>\n${ stringifyTree(node.children) }\n</center>`; } // inline - case 'emoji': { - if (node.props.name) { - return `:${ node.props.name }:`; - } - else if (node.props.emoji) { - return node.props.emoji; - } - else { - return ''; - } + case 'emojiCode': { + return `:${ node.props.name }:`; + } + case 'unicodeEmoji': { + return node.props.emoji; } case 'bold': { return `**${ stringifyTree(node.children) }**`; diff --git a/test/main.ts b/test/main.ts index 4c265542058439a3a61a283bcf9ef8c8e2386474..4ec7b0238f21ea189f59a6b7fa8f92db6dbcff83 100644 --- a/test/main.ts +++ b/test/main.ts @@ -2,7 +2,7 @@ import assert from 'assert'; import { inspect, parse, parsePlain, toString } from '../built/index'; import { createNode } from '../built/util'; import { - TEXT, CENTER, FN, UNI_EMOJI, MENTION, CUSTOM_EMOJI, HASHTAG, N_URL, BOLD, SMALL, ITALIC, STRIKE, QUOTE, MATH_BLOCK, SEARCH, CODE_BLOCK + TEXT, CENTER, FN, UNI_EMOJI, MENTION, EMOJI_CODE, HASHTAG, N_URL, BOLD, SMALL, ITALIC, STRIKE, QUOTE, MATH_BLOCK, SEARCH, CODE_BLOCK } from './node'; describe('text', () => { @@ -210,10 +210,10 @@ describe('center', () => { }); }); -describe('custom emoji', () => { +describe('emoji code', () => { it('basic', () => { const input = ':abc:'; - const output = [CUSTOM_EMOJI('abc')]; + const output = [EMOJI_CODE('abc')]; assert.deepStrictEqual(parse(input), output); }); }); diff --git a/test/node.ts b/test/node.ts index 15ad6b945f07edc3f980a67bff46a2cb7716c18a..7116e9a4f62be592f0a2b0a8866524a20582e700 100644 --- a/test/node.ts +++ b/test/node.ts @@ -1,7 +1,7 @@ import { - MfmBold, MfmCenter, MfmCodeBlock, MfmEmoji, MfmFn, MfmHashtag, MfmInline, + MfmBold, MfmCenter, MfmCodeBlock, MfmEmojiCode, MfmFn, MfmHashtag, MfmInline, MfmInlineCode, MfmItalic, MfmLink, MfmMathBlock, MfmMathInline, MfmMention, - MfmNode, MfmQuote, MfmSearch, MfmSmall, MfmStrike, MfmText, MfmUrl + MfmNode, MfmQuote, MfmSearch, MfmSmall, MfmStrike, MfmText, MfmUnicodeEmoji, MfmUrl } from '../built'; export const QUOTE = (children: MfmNode[]): MfmQuote => { return { type:'quote', children }; }; @@ -20,7 +20,7 @@ export const MENTION = (username: string, host: string | null, acct: string): Mf export const HASHTAG = (value: string): MfmHashtag => { return { type:'hashtag', props: { hashtag: value } }; }; export const N_URL = (value: string): MfmUrl => { return { type:'url', props: { url: value } }; }; export const LINK = (silent: boolean, url: string, children: MfmInline[]): MfmLink => { return { type:'link', props: { silent, url }, children }; }; -export const CUSTOM_EMOJI = (name: string): MfmEmoji => { return { type:'emoji', props: { name: name } }; }; +export const EMOJI_CODE = (name: string): MfmEmojiCode => { return { type:'emojiCode', props: { name: name } }; }; export const FN = (name: string, args: MfmFn['props']['args'], children: MfmFn['children']): MfmFn => { return { type:'fn', props: { name, args }, children }; }; -export const UNI_EMOJI = (value: string): MfmEmoji => { return { type:'emoji', props: { emoji: value } }; }; +export const UNI_EMOJI = (value: string): MfmUnicodeEmoji => { return { type:'unicodeEmoji', props: { emoji: value } }; }; export const TEXT = (value: string): MfmText => { return { type:'text', props: { text: value } }; };