diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2020-11-07 23:41:21 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2020-11-07 23:41:21 +0900 |
| commit | 31aa00856647433c3d4d2f2eb5840d2322e9ffa0 (patch) | |
| tree | 8db6409403a83af5ca4eac9417e449e3daebc549 | |
| parent | 絵文字ピッカーでエンターしたときに検索結果の先頭の... (diff) | |
| download | sharkey-31aa00856647433c3d4d2f2eb5840d2322e9ffa0.tar.gz sharkey-31aa00856647433c3d4d2f2eb5840d2322e9ffa0.tar.bz2 sharkey-31aa00856647433c3d4d2f2eb5840d2322e9ffa0.zip | |
Improve MFM
MFMの構文を調整 + 新しいアニメーション追加
Resolve #6816
| -rw-r--r-- | src/client/components/mfm.ts | 102 | ||||
| -rw-r--r-- | src/client/components/misskey-flavored-markdown.vue | 114 | ||||
| -rw-r--r-- | src/client/pages/reversi/game.board.vue | 2 | ||||
| -rw-r--r-- | src/client/style.scss | 99 | ||||
| -rw-r--r-- | src/mfm/language.ts | 61 | ||||
| -rw-r--r-- | src/mfm/to-html.ts | 44 | ||||
| -rw-r--r-- | src/mfm/to-string.ts | 37 | ||||
| -rw-r--r-- | test/mfm.ts | 167 |
8 files changed, 193 insertions, 433 deletions
diff --git a/src/client/components/mfm.ts b/src/client/components/mfm.ts index e1216614a6..aa9ff0952d 100644 --- a/src/client/components/mfm.ts +++ b/src/client/components/mfm.ts @@ -77,9 +77,57 @@ export default defineComponent({ }, genEl(token.children)); } - case 'big': { - return h('strong', { - style: `display: inline-block; font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: anime-tada 1s linear infinite both;' : ''), + case 'fn': { + // TODO: CSSを文字列で組み立てていくと token.node.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる + let style; + switch (token.node.props.name) { + case 'tada': { + style = `font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: tada 1s linear infinite both;' : ''); + break; + } + case 'jelly': { + const speed = token.node.props.args.speed || '1s'; + style = (this.$store.state.device.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : ''); + break; + } + case 'twitch': { + const speed = token.node.props.args.speed || '0.5s'; + style = this.$store.state.device.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : ''; + break; + } + case 'shake': { + const speed = token.node.props.args.speed || '0.5s'; + style = this.$store.state.device.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : ''; + break; + } + case 'spin': { + const direction = + token.node.props.args.left ? 'reverse' : + token.node.props.args.alternate ? 'alternate' : + 'normal'; + const anime = + token.node.props.args.x ? 'mfm-spinX' : + token.node.props.args.y ? 'mfm-spinY' : + 'mfm-spin'; + const speed = token.node.props.args.speed || '1.5s'; + style = this.$store.state.device.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : ''; + break; + } + case 'jump': { + style = this.$store.state.device.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : ''; + break; + } + case 'flip': { + const transform = + (token.node.props.args.h && token.node.props.args.v) ? 'scale(-1, -1)' : + token.node.props.args.v ? 'scaleY(-1)' : + 'scaleX(-1)'; + style = `transform: ${transform};`; + break; + } + } + return h('span', { + style: 'display: inline-block;' + style, }, genEl(token.children)); } @@ -95,48 +143,6 @@ export default defineComponent({ }, genEl(token.children))]; } - case 'motion': { - return h('span', { - style: 'display: inline-block;' + (this.$store.state.device.animatedMfm ? 'animation: anime-rubberBand 1s linear infinite both;' : ''), - }, genEl(token.children)); - } - - case 'spin': { - const direction = - token.node.props.attr == 'left' ? 'reverse' : - token.node.props.attr == 'alternate' ? 'alternate' : - 'normal'; - const style = this.$store.state.device.animatedMfm - ? `animation: anime-spin 1.5s linear infinite; animation-direction: ${direction};` : ''; - return h('span', { - style: 'display: inline-block;' + style - }, genEl(token.children)); - } - - case 'jump': { - return h('span', { - style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-jump 0.75s linear infinite;' : 'display: inline-block;' - }, genEl(token.children)); - } - - case 'flip': { - return h('span', { - style: 'display: inline-block; transform: scaleX(-1);' - }, genEl(token.children)); - } - - case 'twitch': { - return h('span', { - style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-twitch 0.5s ease infinite;' : 'display: inline-block;' - }, genEl(token.children)); - } - - case 'shake': { - return h('span', { - style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-shake 0.5s ease infinite;' : 'display: inline-block;' - }, genEl(token.children)); - } - case 'url': { return [h(MkUrl, { key: Math.random(), @@ -198,12 +204,6 @@ export default defineComponent({ } } - case 'title': { - return [h('div', { - class: 'title' - }, genEl(token.children))]; - } - case 'emoji': { return [h(MkEmoji, { key: Math.random(), diff --git a/src/client/components/misskey-flavored-markdown.vue b/src/client/components/misskey-flavored-markdown.vue index a7ef718f60..c922eb1678 100644 --- a/src/client/components/misskey-flavored-markdown.vue +++ b/src/client/components/misskey-flavored-markdown.vue @@ -13,6 +13,115 @@ export default defineComponent({ }); </script> +<style lang="scss"> +@keyframes mfm-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +@keyframes mfm-spinX { + 0% { transform: perspective(128px) rotateX(0deg); } + 100% { transform: perspective(128px) rotateX(360deg); } +} + +@keyframes mfm-spinY { + 0% { transform: perspective(128px) rotateY(0deg); } + 100% { transform: perspective(128px) rotateY(360deg); } +} + +@keyframes mfm-jump { + 0% { transform: translateY(0); } + 25% { transform: translateY(-16px); } + 50% { transform: translateY(0); } + 75% { transform: translateY(-8px); } + 100% { transform: translateY(0); } +} + +// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`; +// let css = ''; +// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } +@keyframes mfm-twitch { + 0% { transform: translate(7px, -2px) } + 5% { transform: translate(-3px, 1px) } + 10% { transform: translate(-7px, -1px) } + 15% { transform: translate(0px, -1px) } + 20% { transform: translate(-8px, 6px) } + 25% { transform: translate(-4px, -3px) } + 30% { transform: translate(-4px, -6px) } + 35% { transform: translate(-8px, -8px) } + 40% { transform: translate(4px, 6px) } + 45% { transform: translate(-3px, 1px) } + 50% { transform: translate(2px, -10px) } + 55% { transform: translate(-7px, 0px) } + 60% { transform: translate(-2px, 4px) } + 65% { transform: translate(3px, -8px) } + 70% { transform: translate(6px, 7px) } + 75% { transform: translate(-7px, -2px) } + 80% { transform: translate(-7px, -8px) } + 85% { transform: translate(9px, 3px) } + 90% { transform: translate(-3px, -2px) } + 95% { transform: translate(-10px, 2px) } + 100% { transform: translate(-2px, -6px) } +} + +// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`; +// let css = ''; +// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } +@keyframes mfm-shake { + 0% { transform: translate(-3px, -1px) rotate(-8deg) } + 5% { transform: translate(0px, -1px) rotate(-10deg) } + 10% { transform: translate(1px, -3px) rotate(0deg) } + 15% { transform: translate(1px, 1px) rotate(11deg) } + 20% { transform: translate(-2px, 1px) rotate(1deg) } + 25% { transform: translate(-1px, -2px) rotate(-2deg) } + 30% { transform: translate(-1px, 2px) rotate(-3deg) } + 35% { transform: translate(2px, 1px) rotate(6deg) } + 40% { transform: translate(-2px, -3px) rotate(-9deg) } + 45% { transform: translate(0px, -1px) rotate(-12deg) } + 50% { transform: translate(1px, 2px) rotate(10deg) } + 55% { transform: translate(0px, -3px) rotate(8deg) } + 60% { transform: translate(1px, -1px) rotate(8deg) } + 65% { transform: translate(0px, -1px) rotate(-7deg) } + 70% { transform: translate(-1px, -3px) rotate(6deg) } + 75% { transform: translate(0px, -2px) rotate(4deg) } + 80% { transform: translate(-2px, -1px) rotate(3deg) } + 85% { transform: translate(1px, -3px) rotate(-10deg) } + 90% { transform: translate(1px, 0px) rotate(3deg) } + 95% { transform: translate(-2px, 0px) rotate(-3deg) } + 100% { transform: translate(2px, 1px) rotate(2deg) } +} + +@keyframes mfm-rubberBand { + from { + transform: scale3d(1, 1, 1); + } + + 30% { + transform: scale3d(1.25, 0.75, 1); + } + + 40% { + transform: scale3d(0.75, 1.25, 1); + } + + 50% { + transform: scale3d(1.15, 0.85, 1); + } + + 65% { + transform: scale3d(0.95, 1.05, 1); + } + + 75% { + transform: scale3d(1.05, 0.95, 1); + } + + to { + transform: scale3d(1, 1, 1); + } +} +</style> + <style lang="scss" scoped> .havbbuyv { white-space: pre-wrap; @@ -42,10 +151,5 @@ export default defineComponent({ word-break: break-all; padding: 4px 6px; } - - ::v-deep(.title) { - text-align: center; - border-bottom: solid 1px var(--divider); - } } </style> diff --git a/src/client/pages/reversi/game.board.vue b/src/client/pages/reversi/game.board.vue index 96ea86547d..6559396aca 100644 --- a/src/client/pages/reversi/game.board.vue +++ b/src/client/pages/reversi/game.board.vue @@ -11,7 +11,7 @@ <Mfm :key="'past-turn-of:' + turnUser().name" :text="$t('_reversi.pastTurnOf', { name: turnUser().name })" :plain="true" :custom-emojis="turnUser().emojis"/> </p> <p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn()">{{ $t('_reversi.opponentTurn') }}<MkEllipsis/></p> - <p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn()" style="animation: anime-tada 1s linear infinite both;">{{ $t('_reversi.myTurn') }}</p> + <p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn()" style="animation: tada 1s linear infinite both;">{{ $t('_reversi.myTurn') }}</p> <p class="result" v-if="game.isEnded && logPos == logs.length"> <template v-if="game.winner"> <Mfm :key="'won'" :text="$t('_reversi.won', { name: game.winner.name })" :plain="true" :custom-emojis="game.winner.emojis"/> diff --git a/src/client/style.scss b/src/client/style.scss index 07abbe0814..9715bde10b 100644 --- a/src/client/style.scss +++ b/src/client/style.scss @@ -486,74 +486,7 @@ hr { 90% { opacity: 0; transform: scale(0.5); } } -@keyframes anime-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -@keyframes anime-jump { - 0% { transform: translateY(0); } - 25% { transform: translateY(-16px); } - 50% { transform: translateY(0); } - 75% { transform: translateY(-8px); } - 100% { transform: translateY(0); } -} - -// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`; -// let css = ''; -// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } -@keyframes anime-twitch { - 0% { transform: translate(7px, -2px) } - 5% { transform: translate(-3px, 1px) } - 10% { transform: translate(-7px, -1px) } - 15% { transform: translate(0px, -1px) } - 20% { transform: translate(-8px, 6px) } - 25% { transform: translate(-4px, -3px) } - 30% { transform: translate(-4px, -6px) } - 35% { transform: translate(-8px, -8px) } - 40% { transform: translate(4px, 6px) } - 45% { transform: translate(-3px, 1px) } - 50% { transform: translate(2px, -10px) } - 55% { transform: translate(-7px, 0px) } - 60% { transform: translate(-2px, 4px) } - 65% { transform: translate(3px, -8px) } - 70% { transform: translate(6px, 7px) } - 75% { transform: translate(-7px, -2px) } - 80% { transform: translate(-7px, -8px) } - 85% { transform: translate(9px, 3px) } - 90% { transform: translate(-3px, -2px) } - 95% { transform: translate(-10px, 2px) } - 100% { transform: translate(-2px, -6px) } -} - -// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`; -// let css = ''; -// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } -@keyframes anime-shake { - 0% { transform: translate(-3px, -1px) rotate(-8deg) } - 5% { transform: translate(0px, -1px) rotate(-10deg) } - 10% { transform: translate(1px, -3px) rotate(0deg) } - 15% { transform: translate(1px, 1px) rotate(11deg) } - 20% { transform: translate(-2px, 1px) rotate(1deg) } - 25% { transform: translate(-1px, -2px) rotate(-2deg) } - 30% { transform: translate(-1px, 2px) rotate(-3deg) } - 35% { transform: translate(2px, 1px) rotate(6deg) } - 40% { transform: translate(-2px, -3px) rotate(-9deg) } - 45% { transform: translate(0px, -1px) rotate(-12deg) } - 50% { transform: translate(1px, 2px) rotate(10deg) } - 55% { transform: translate(0px, -3px) rotate(8deg) } - 60% { transform: translate(1px, -1px) rotate(8deg) } - 65% { transform: translate(0px, -1px) rotate(-7deg) } - 70% { transform: translate(-1px, -3px) rotate(6deg) } - 75% { transform: translate(0px, -2px) rotate(4deg) } - 80% { transform: translate(-2px, -1px) rotate(3deg) } - 85% { transform: translate(1px, -3px) rotate(-10deg) } - 90% { transform: translate(1px, 0px) rotate(3deg) } - 95% { transform: translate(-2px, 0px) rotate(-3deg) } - 100% { transform: translate(2px, 1px) rotate(2deg) } -} - -@keyframes anime-tada { +@keyframes tada { from { transform: scale3d(1, 1, 1); } @@ -580,33 +513,3 @@ hr { transform: scale3d(1, 1, 1); } } - -@keyframes anime-rubberBand { - from { - transform: scale3d(1, 1, 1); - } - - 30% { - transform: scale3d(1.25, 0.75, 1); - } - - 40% { - transform: scale3d(0.75, 1.25, 1); - } - - 50% { - transform: scale3d(1.15, 0.85, 1); - } - - 65% { - transform: scale3d(0.95, 1.05, 1); - } - - 75% { - transform: scale3d(1.05, 0.95, 1); - } - - to { - transform: scale3d(1, 1, 1); - } -} diff --git a/src/mfm/language.ts b/src/mfm/language.ts index 61d6422558..8e15ca43b9 100644 --- a/src/mfm/language.ts +++ b/src/mfm/language.ts @@ -23,7 +23,6 @@ export const mfmLanguage = P.createLanguage({ root: r => P.alt(r.block, r.inline).atLeast(1), plain: r => P.alt(r.emoji, r.text).atLeast(1), block: r => P.alt( - r.title, r.quote, r.search, r.blockCode, @@ -37,14 +36,6 @@ export const mfmLanguage = P.createLanguage({ return P.makeFailure(i, 'not newline'); } }), - title: r => r.startOfLine.then(P((input, i) => { - const text = input.substr(i); - const match = text.match(/^([【\[]([^【\[】\]\n]+?)[】\]])(\n|$)/); - if (!match) return P.makeFailure(i, 'not a title'); - const q = match[2].trim(); - const contents = r.inline.atLeast(1).tryParse(q); - return P.makeSuccess(i + match[0].length, createTree('title', contents, {})); - })), quote: r => r.startOfLine.then(P((input, i) => { const text = input.substr(i); if (!text.match(/^>[\s\S]+?/)) return P.makeFailure(i, 'not a quote'); @@ -67,17 +58,10 @@ export const mfmLanguage = P.createLanguage({ return P.makeSuccess(i + match[0].length, createLeaf('blockCode', { code: match[2], lang: match[1] ? match[1].trim() : null })); })), inline: r => P.alt( - r.big, r.bold, r.small, r.italic, r.strike, - r.motion, - r.spin, - r.jump, - r.flip, - r.twitch, - r.shake, r.inlineCode, r.mathInline, r.mention, @@ -85,9 +69,9 @@ export const mfmLanguage = P.createLanguage({ r.url, r.link, r.emoji, + r.fn, r.text ), - big: r => P.regexp(/^\*\*\*([\s\S]+?)\*\*\*/, 1).map(x => createTree('big', r.inline.atLeast(1).tryParse(x), {})), bold: r => { const asterisk = P.regexp(/\*\*([\s\S]+?)\*\*/, 1); const underscore = P.regexp(/__([a-zA-Z0-9\s]+?)__/, 1); @@ -107,25 +91,6 @@ export const mfmLanguage = P.createLanguage({ return P.alt(xml, underscore).map(x => createTree('italic', r.inline.atLeast(1).tryParse(x), {})); }, strike: r => P.regexp(/~~([^\n~]+?)~~/, 1).map(x => createTree('strike', r.inline.atLeast(1).tryParse(x), {})), - motion: r => { - const paren = P.regexp(/\(\(\(([\s\S]+?)\)\)\)/, 1); - const xml = P.regexp(/<motion>(.+?)<\/motion>/, 1); - return P.alt(paren, xml).map(x => createTree('motion', r.inline.atLeast(1).tryParse(x), {})); - }, - spin: r => { - return P((input, i) => { - const text = input.substr(i); - const match = text.match(/^<spin(\s[a-z]+?)?>(.+?)<\/spin>/i); - if (!match) return P.makeFailure(i, 'not a spin'); - return P.makeSuccess(i + match[0].length, { - content: match[2], attr: match[1] ? match[1].trim() : null - }); - }).map(x => createTree('spin', r.inline.atLeast(1).tryParse(x.content), { attr: x.attr })); - }, - jump: r => P.regexp(/<jump>(.+?)<\/jump>/, 1).map(x => createTree('jump', r.inline.atLeast(1).tryParse(x), {})), - flip: r => P.regexp(/<flip>(.+?)<\/flip>/, 1).map(x => createTree('flip', r.inline.atLeast(1).tryParse(x), {})), - twitch: r => P.regexp(/<twitch>(.+?)<\/twitch>/, 1).map(x => createTree('twitch', r.inline.atLeast(1).tryParse(x), {})), - shake: r => P.regexp(/<shake>(.+?)<\/shake>/, 1).map(x => createTree('shake', r.inline.atLeast(1).tryParse(x), {})), center: r => r.startOfLine.then(P.regexp(/<center>([\s\S]+?)<\/center>/, 1).map(x => createTree('center', r.inline.atLeast(1).tryParse(x), {}))), inlineCode: () => P.regexp(/`([^´\n]+?)`/, 1).map(x => createLeaf('inlineCode', { code: x })), mathBlock: r => r.startOfLine.then(P.regexp(/\\\[([\s\S]+?)\\\]/, 1).map(x => createLeaf('mathBlock', { formula: x.trim() }))), @@ -192,5 +157,29 @@ export const mfmLanguage = P.createLanguage({ const code = P.regexp(emojiRegex).map(x => createLeaf('emoji', { emoji: x })); return P.alt(name, code); }, + fn: r => { + return P.seqObj( + P.string('['), ['fn', P.regexp(/[^\s\n\[\]]+/)] as any, P.string(' '), P.optWhitespace, ['text', P.regexp(/[^\n\[\]]+/)] as any, P.string(']'), + ).map((x: any) => { + let name = x.fn; + const args = {}; + const separator = x.fn.indexOf('.'); + if (separator > -1) { + name = x.fn.substr(0, separator); + for (const arg of x.fn.substr(separator + 1).split(',')) { + const kv = arg.split('='); + if (kv.length === 1) { + args[kv[0]] = true; + } else { + args[kv[0]] = kv[1]; + } + } + } + return createTree('fn', r.inline.atLeast(1).tryParse(x.text), { + name, + args + }); + }); + }, text: () => P.any.map(x => createLeaf('text', { text: x })) }); diff --git a/src/mfm/to-html.ts b/src/mfm/to-html.ts index 36680e374e..ab3f7c3d16 100644 --- a/src/mfm/to-html.ts +++ b/src/mfm/to-html.ts @@ -25,12 +25,6 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione return el; }, - big(token) { - const el = doc.createElement('strong'); - appendChildren(token.children, el); - return el; - }, - small(token) { const el = doc.createElement('small'); appendChildren(token.children, el); @@ -49,42 +43,12 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione return el; }, - motion(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - spin(token) { + fn(token) { const el = doc.createElement('i'); appendChildren(token.children, el); return el; }, - jump(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - twitch(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - shake(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - flip(token) { - const el = doc.createElement('span'); - appendChildren(token.children, el); - return el; - }, - blockCode(token) { const pre = doc.createElement('pre'); const inner = doc.createElement('code'); @@ -157,12 +121,6 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione return el; }, - title(token) { - const el = doc.createElement('h1'); - appendChildren(token.children, el); - return el; - }, - text(token) { const el = doc.createElement('span'); const nodes = (token.node.props.text as string).split(/\r\n|\r|\n/).map(x => doc.createTextNode(x) as Node); diff --git a/src/mfm/to-string.ts b/src/mfm/to-string.ts index 6b8dcf2c39..b70b99cbda 100644 --- a/src/mfm/to-string.ts +++ b/src/mfm/to-string.ts @@ -18,10 +18,6 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin return `**${appendChildren(token.children, opts)}**`; }, - big(token, opts) { - return `***${appendChildren(token.children, opts)}***`; - }, - small(token, opts) { return `<small>${appendChildren(token.children, opts)}</small>`; }, @@ -34,30 +30,11 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin return `<i>${appendChildren(token.children, opts)}</i>`; }, - motion(token, opts) { - return `<motion>${appendChildren(token.children, opts)}</motion>`; - }, - - spin(token, opts) { - const attr = token.node.props?.attr; - const post = attr ? ` ${attr}` : ''; - return `<spin${post}>${appendChildren(token.children, opts)}</spin>`; - }, - - jump(token, opts) { - return `<jump>${appendChildren(token.children, opts)}</jump>`; - }, - - twitch(token, opts) { - return `<twitch>${appendChildren(token.children, opts)}</twitch>`; - }, - - shake(token, opts) { - return `<shake>${appendChildren(token.children, opts)}</shake>`; - }, - - flip(token, opts) { - return `<flip>${appendChildren(token.children, opts)}</flip>`; + fn(token, opts) { + const name = token.node.props?.name; + const args = token.node.props?.args || {}; + const argsStr = Object.entries(args).map(([k, v]) => v === true ? k : `${k}=${v}`).join(','); + return `[${name}${argsStr !== '' ? '.' + argsStr : ''} ${appendChildren(token.children, opts)}]`; }, blockCode(token) { @@ -104,10 +81,6 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin return `${appendChildren(token.children, {doNyaize: false}).replace(/^/gm,'>').trim()}\n`; }, - title(token, opts) { - return `[${appendChildren(token.children, opts)}]\n`; - }, - text(token, opts) { return (opts && opts.doNyaize) ? nyaize(token.node.props.text) : token.node.props.text; }, diff --git a/test/mfm.ts b/test/mfm.ts index 69c340bc0b..6244263a30 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -227,16 +227,6 @@ describe('MFM', () => { }); }); - it('big', () => { - const tokens = parse('***Strawberry*** Pasta'); - assert.deepStrictEqual(tokens, [ - tree('big', [ - text('Strawberry') - ], {}), - text(' Pasta'), - ]); - }); - it('small', () => { const tokens = parse('<small>smaller</small>'); assert.deepStrictEqual(tokens, [ @@ -246,133 +236,6 @@ describe('MFM', () => { ]); }); - it('flip', () => { - const tokens = parse('<flip>foo</flip>'); - assert.deepStrictEqual(tokens, [ - tree('flip', [ - text('foo') - ], {}), - ]); - }); - - describe('spin', () => { - it('text', () => { - const tokens = parse('<spin>foo</spin>'); - assert.deepStrictEqual(tokens, [ - tree('spin', [ - text('foo') - ], { - attr: null - }), - ]); - }); - - it('emoji', () => { - const tokens = parse('<spin>:foo:</spin>'); - assert.deepStrictEqual(tokens, [ - tree('spin', [ - leaf('emoji', { name: 'foo' }) - ], { - attr: null - }), - ]); - }); - - it('with attr', () => { - const tokens = parse('<spin left>:foo:</spin>'); - assert.deepStrictEqual(tokens, [ - tree('spin', [ - leaf('emoji', { name: 'foo' }) - ], { - attr: 'left' - }), - ]); - }); -/* - it('multi', () => { - const tokens = parse('<spin>:foo:</spin><spin>:foo:</spin>'); - assert.deepStrictEqual(tokens, [ - tree('spin', [ - leaf('emoji', { name: 'foo' }) - ], { - attr: null - }), - tree('spin', [ - leaf('emoji', { name: 'foo' }) - ], { - attr: null - }), - ]); - }); - - it('nested', () => { - const tokens = parse('<spin><spin>:foo:</spin></spin>'); - assert.deepStrictEqual(tokens, [ - tree('spin', [ - tree('spin', [ - leaf('emoji', { name: 'foo' }) - ], { - attr: null - }), - ], { - attr: null - }), - ]); - }); -*/ - }); - - it('jump', () => { - const tokens = parse('<jump>:foo:</jump>'); - assert.deepStrictEqual(tokens, [ - tree('jump', [ - leaf('emoji', { name: 'foo' }) - ], {}), - ]); - }); - - describe('motion', () => { - it('by triple brackets', () => { - const tokens = parse('(((foo)))'); - assert.deepStrictEqual(tokens, [ - tree('motion', [ - text('foo') - ], {}), - ]); - }); - - it('by triple brackets (with other texts)', () => { - const tokens = parse('bar(((foo)))bar'); - assert.deepStrictEqual(tokens, [ - text('bar'), - tree('motion', [ - text('foo') - ], {}), - text('bar'), - ]); - }); - - it('by <motion> tag', () => { - const tokens = parse('<motion>foo</motion>'); - assert.deepStrictEqual(tokens, [ - tree('motion', [ - text('foo') - ], {}), - ]); - }); - - it('by <motion> tag (with other texts)', () => { - const tokens = parse('bar<motion>foo</motion>bar'); - assert.deepStrictEqual(tokens, [ - text('bar'), - tree('motion', [ - text('foo') - ], {}), - text('bar'), - ]); - }); - }); - describe('mention', () => { it('local', () => { const tokens = parse('@himawari foo'); @@ -1310,30 +1173,6 @@ describe('MFM', () => { it('小さい字', () => { assert.deepStrictEqual(toString(parse('<small>小さい字</small>')), '<small>小さい字</small>'); }); - it('モーション', () => { - assert.deepStrictEqual(toString(parse('<motion>モーション</motion>')), '<motion>モーション</motion>'); - }); - it('モーション2', () => { - assert.deepStrictEqual(toString(parse('(((モーション)))')), '<motion>モーション</motion>'); - }); - it('ビッグ+', () => { - assert.deepStrictEqual(toString(parse('*** ビッグ+ ***')), '*** ビッグ+ ***'); - }); - it('回転', () => { - assert.deepStrictEqual(toString(parse('<spin>回転</spin>')), '<spin>回転</spin>'); - }); - it('右回転', () => { - assert.deepStrictEqual(toString(parse('<spin right>右回転</spin>')), '<spin right>右回転</spin>'); - }); - it('左回転', () => { - assert.deepStrictEqual(toString(parse('<spin left>左回転</spin>')), '<spin left>左回転</spin>'); - }); - it('往復回転', () => { - assert.deepStrictEqual(toString(parse('<spin alternate>往復回転</spin>')), '<spin alternate>往復回転</spin>'); - }); - it('ジャンプ', () => { - assert.deepStrictEqual(toString(parse('<jump>ジャンプ</jump>')), '<jump>ジャンプ</jump>'); - }); it('コードブロック', () => { assert.deepStrictEqual(toString(parse('```\nコードブロック\n```')), '```\nコードブロック\n```'); }); @@ -1352,12 +1191,6 @@ describe('MFM', () => { it('詳細なしリンク', () => { assert.deepStrictEqual(toString(parse('?[詳細なしリンク](http://example.com)')), '?[詳細なしリンク](http://example.com)'); }); - it('【タイトル】', () => { - assert.deepStrictEqual(toString(parse('【タイトル】')), '[タイトル]'); - }); - it('[タイトル]', () => { - assert.deepStrictEqual(toString(parse('[タイトル]')), '[タイトル]'); - }); it('インライン数式', () => { assert.deepStrictEqual(toString(parse('\\(インライン数式\\)')), '\\(インライン数式\\)'); }); |