MFMをテキストに戻す (#6131)

* Disable Nyaize in quote

* mfmを文字列に戻す、nyaizeにmfmを使用

* Revert "Disable Nyaize in quote"

This reverts commit 1b238905a5535267d32d7e1aec8afd8bb07b0619.

* refactor

* use return type as string
This commit is contained in:
Oni-Men 2020-03-06 22:51:50 +09:00 committed by GitHub
parent 20ac7e62e9
commit a471e4b783
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 36 deletions

112
src/mfm/toString.ts Normal file
View file

@ -0,0 +1,112 @@
import { MfmForest, MfmTree } from './prelude';
import { nyaize } from '../misc/nyaize';
export type RestoreOptions = {
doNyaize?: boolean;
};
export function toString(tokens: MfmForest | null, opts?: RestoreOptions): string {
if (tokens === null) return '';
function appendChildren(children: MfmForest, opts?: RestoreOptions): string {
return children.map(t => handlers[t.node.type](t, opts)).join('');
}
const handlers: { [key: string]: (token: MfmTree, opts?: RestoreOptions) => string } = {
bold(token, opts) {
return `**${appendChildren(token.children, opts)}**`;
},
big(token, opts) {
return `***${appendChildren(token.children, opts)}***`;
},
small(token, opts) {
return `<small>${appendChildren(token.children, opts)}</small>`;
},
strike(token, opts) {
return `~~${appendChildren(token.children, opts)}~~`;
},
italic(token, opts) {
return `<i>${appendChildren(token.children, opts)}</i>`;
},
motion(token, opts) {
return `<motion>${appendChildren(token.children, opts)}</motion>`;
},
spin(token, opts) {
return `<spin>${appendChildren(token.children, opts)}</spin>`;
},
jump(token, opts) {
return `<jump>${appendChildren(token.children, opts)}</jump>`;
},
flip(token, opts) {
return `<flip>${appendChildren(token.children, opts)}</flip>`;
},
blockCode(token) {
return `\`\`\`${token.node.props.lang || ''}\n${token.node.props.code}\n\`\`\`\n`;
},
center(token, opts) {
return `<center>${appendChildren(token.children, opts)}</center>`;
},
emoji(token) {
return (token.node.props.emoji ? token.node.props.emoji : `:${token.node.props.name}:`);
},
hashtag(token) {
return `#${token.node.props.hashtag}`;
},
inlineCode(token) {
return `\`${token.node.props.code}\``;
},
mathInline(token) {
return `\\(${token.node.props.formula}\\)`;
},
mathBlock(token) {
return `\\[${token.node.props.formula}\\]`;
},
link(token, opts) {
return `[${appendChildren(token.children, opts)}](${token.node.props.url})`;
},
mention(token) {
return token.node.props.canonical;
},
quote(token) {
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;
},
url(token) {
return `<${token.node.props.url}>`;
},
search(token, opts) {
const query = token.node.props.query;
return `${(opts && opts.doNyaize ? nyaize(query) : query)} [search]\n`;
}
};
return appendChildren(tokens, { doNyaize: (opts && opts.doNyaize) || false }).trim();
}

View file

@ -1,8 +1,5 @@
import rndstr from 'rndstr';
export function nyaize(text: string): string {
const [toNyaize, exclusionMap] = exclude(text);
const nyaized = toNyaize
return text
// ja-JP
.replace(/な/g, 'にゃ').replace(/ナ/g, 'ニャ').replace(/ナ/g, 'ニャ')
// en-US
@ -13,34 +10,4 @@ export function nyaize(text: string): string {
))
.replace(/(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm, '다냥')
.replace(/(야(?=\?))|(야$)|(야(?= ))/gm, '냥');
return replaceExceptions(nyaized, exclusionMap);
}
function exclude(text: string): [string, Record<string, string>] {
const map: Record<string, string> = {};
function substitute(match: string): string {
let randomstr: string;
do {
randomstr = rndstr({ length: 16, chars: '🀀-🀫' });
} while(Object.prototype.hasOwnProperty.call(map, randomstr));
map[randomstr] = match;
return randomstr;
}
const replaced = text
.replace(/```(.+?)?\n([\s\S]+?)```(\n|$)/gm, match => substitute(match)) // code block
.replace(/`([^`\n]+?)`/g, match => substitute(match)) // inline code
.replace(/(https?:\/\/.*?)(?= |$)/gm, match => substitute(match)) // URL
.replace(/:([a-z0-9_+-]+):/gim, match => substitute(match)) // emoji
.replace(/#([^\s.,!?'"#:\/\[\]【】]+)/gm, match => substitute(match)) // hashtag
.replace(/@\w([\w-]*\w)?(?:@[\w.\-]+\w)?/gm, match => substitute(match)); // mention
return [replaced, map];
}
function replaceExceptions(text: string, map: Record<string, string>): string {
for (const rule in map) {
if (Object.prototype.hasOwnProperty.call(map, rule)) {
text = text.replace(rule, map[rule]);
}
}
return text;
}

View file

@ -1,12 +1,13 @@
import { EntityRepository, Repository, In } from 'typeorm';
import { Note } from '../entities/note';
import { User } from '../entities/user';
import { nyaize } from '../../misc/nyaize';
import { Emojis, Users, PollVotes, DriveFiles, NoteReactions, Followings, Polls } from '..';
import { ensure } from '../../prelude/ensure';
import { SchemaType } from '../../misc/schema';
import { awaitAll } from '../../prelude/await-all';
import { convertLegacyReaction, convertLegacyReactions } from '../../misc/reaction-lib';
import { toString } from '../../mfm/toString';
import { parse } from '../../mfm/parse';
export type PackedNote = SchemaType<typeof packedNoteSchema>;
@ -217,7 +218,8 @@ export class NoteRepository extends Repository<Note> {
});
if (packed.user.isCat && packed.text) {
packed.text = nyaize(packed.text);
const tokens = packed.text ? parse(packed.text) : [];
packed.text = toString(tokens, { doNyaize: true });
}
if (!opts.skipHide) {