From 69975c2fdd1cfa12d86eb51ce0769f17ffd826a5 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 26 Apr 2020 11:48:09 +0900 Subject: chore: Use kebab-case for file names --- src/mfm/from-html.ts | 79 +++++++++++ src/mfm/fromHtml.ts | 79 ----------- src/mfm/to-html.ts | 187 +++++++++++++++++++++++++++ src/mfm/to-string.ts | 116 +++++++++++++++++ src/mfm/toHtml.ts | 187 --------------------------- src/mfm/toString.ts | 116 ----------------- src/models/repositories/note.ts | 2 +- src/remote/activitypub/misc/get-note-html.ts | 2 +- src/remote/activitypub/misc/html-to-mfm.ts | 2 +- src/remote/activitypub/models/person.ts | 2 +- src/remote/activitypub/renderer/person.ts | 2 +- 11 files changed, 387 insertions(+), 387 deletions(-) create mode 100644 src/mfm/from-html.ts delete mode 100644 src/mfm/fromHtml.ts create mode 100644 src/mfm/to-html.ts create mode 100644 src/mfm/to-string.ts delete mode 100644 src/mfm/toHtml.ts delete mode 100644 src/mfm/toString.ts (limited to 'src') diff --git a/src/mfm/from-html.ts b/src/mfm/from-html.ts new file mode 100644 index 0000000000..1eca3fc6ce --- /dev/null +++ b/src/mfm/from-html.ts @@ -0,0 +1,79 @@ +import { parseFragment, DefaultTreeDocumentFragment } from 'parse5'; +import { urlRegex } from './prelude'; + +export function fromHtml(html: string, hashtagNames?: string[]): string { + const dom = parseFragment(html) as DefaultTreeDocumentFragment; + + let text = ''; + + for (const n of dom.childNodes) { + analyze(n); + } + + return text.trim(); + + function getText(node: any): string { + if (node.nodeName === '#text') return node.value; + + if (node.childNodes) { + return node.childNodes.map((n: any) => getText(n)).join(''); + } + + return ''; + } + + function analyze(node: any) { + switch (node.nodeName) { + case '#text': + text += node.value; + break; + + case 'br': + text += '\n'; + break; + + case 'a': + const txt = getText(node); + const rel = node.attrs.find((x: any) => x.name === 'rel'); + const href = node.attrs.find((x: any) => x.name === 'href'); + + // ハッシュタグ + if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) { + text += txt; + // メンション + } else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) { + const part = txt.split('@'); + + if (part.length === 2) { + //#region ホスト名部分が省略されているので復元する + const acct = `${txt}@${(new URL(href.value)).hostname}`; + text += acct; + //#endregion + } else if (part.length === 3) { + text += txt; + } + // その他 + } else { + text += (!href || (txt === href.value && txt.match(urlRegex))) ? txt : `[${txt}](${href.value})`; + } + break; + + case 'p': + text += '\n\n'; + if (node.childNodes) { + for (const n of node.childNodes) { + analyze(n); + } + } + break; + + default: + if (node.childNodes) { + for (const n of node.childNodes) { + analyze(n); + } + } + break; + } + } +} diff --git a/src/mfm/fromHtml.ts b/src/mfm/fromHtml.ts deleted file mode 100644 index 1eca3fc6ce..0000000000 --- a/src/mfm/fromHtml.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { parseFragment, DefaultTreeDocumentFragment } from 'parse5'; -import { urlRegex } from './prelude'; - -export function fromHtml(html: string, hashtagNames?: string[]): string { - const dom = parseFragment(html) as DefaultTreeDocumentFragment; - - let text = ''; - - for (const n of dom.childNodes) { - analyze(n); - } - - return text.trim(); - - function getText(node: any): string { - if (node.nodeName === '#text') return node.value; - - if (node.childNodes) { - return node.childNodes.map((n: any) => getText(n)).join(''); - } - - return ''; - } - - function analyze(node: any) { - switch (node.nodeName) { - case '#text': - text += node.value; - break; - - case 'br': - text += '\n'; - break; - - case 'a': - const txt = getText(node); - const rel = node.attrs.find((x: any) => x.name === 'rel'); - const href = node.attrs.find((x: any) => x.name === 'href'); - - // ハッシュタグ - if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) { - text += txt; - // メンション - } else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) { - const part = txt.split('@'); - - if (part.length === 2) { - //#region ホスト名部分が省略されているので復元する - const acct = `${txt}@${(new URL(href.value)).hostname}`; - text += acct; - //#endregion - } else if (part.length === 3) { - text += txt; - } - // その他 - } else { - text += (!href || (txt === href.value && txt.match(urlRegex))) ? txt : `[${txt}](${href.value})`; - } - break; - - case 'p': - text += '\n\n'; - if (node.childNodes) { - for (const n of node.childNodes) { - analyze(n); - } - } - break; - - default: - if (node.childNodes) { - for (const n of node.childNodes) { - analyze(n); - } - } - break; - } - } -} diff --git a/src/mfm/to-html.ts b/src/mfm/to-html.ts new file mode 100644 index 0000000000..1292292154 --- /dev/null +++ b/src/mfm/to-html.ts @@ -0,0 +1,187 @@ +import { JSDOM } from 'jsdom'; +import config from '../config'; +import { intersperse } from '../prelude/array'; +import { MfmForest, MfmTree } from './prelude'; +import { IMentionedRemoteUsers } from '../models/entities/note'; + +export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) { + if (tokens == null) { + return null; + } + + const { window } = new JSDOM(''); + + const doc = window.document; + + function appendChildren(children: MfmForest, targetElement: any): void { + for (const child of children.map(t => handlers[t.node.type](t))) targetElement.appendChild(child); + } + + const handlers: { [key: string]: (token: MfmTree) => any } = { + bold(token) { + const el = doc.createElement('b'); + appendChildren(token.children, el); + 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); + return el; + }, + + strike(token) { + const el = doc.createElement('del'); + appendChildren(token.children, el); + return el; + }, + + italic(token) { + const el = doc.createElement('i'); + appendChildren(token.children, el); + return el; + }, + + motion(token) { + const el = doc.createElement('i'); + appendChildren(token.children, el); + return el; + }, + + spin(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; + }, + + 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'); + inner.innerHTML = token.node.props.code; + pre.appendChild(inner); + return pre; + }, + + center(token) { + const el = doc.createElement('div'); + appendChildren(token.children, el); + return el; + }, + + emoji(token) { + return doc.createTextNode(token.node.props.emoji ? token.node.props.emoji : `\u200B:${token.node.props.name}:\u200B`); + }, + + hashtag(token) { + const a = doc.createElement('a'); + a.href = `${config.url}/tags/${token.node.props.hashtag}`; + a.textContent = `#${token.node.props.hashtag}`; + a.setAttribute('rel', 'tag'); + return a; + }, + + inlineCode(token) { + const el = doc.createElement('code'); + el.textContent = token.node.props.code; + return el; + }, + + mathInline(token) { + const el = doc.createElement('code'); + el.textContent = token.node.props.formula; + return el; + }, + + mathBlock(token) { + const el = doc.createElement('code'); + el.textContent = token.node.props.formula; + return el; + }, + + link(token) { + const a = doc.createElement('a'); + a.href = token.node.props.url; + appendChildren(token.children, a); + return a; + }, + + mention(token) { + const a = doc.createElement('a'); + const { username, host, acct } = token.node.props; + switch (host) { + case 'github.com': + a.href = `https://github.com/${username}`; + break; + case 'twitter.com': + a.href = `https://twitter.com/${username}`; + break; + default: + const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host); + a.href = remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${config.url}/${acct}`; + a.className = 'u-url mention'; + break; + } + a.textContent = acct; + return a; + }, + + quote(token) { + const el = doc.createElement('blockquote'); + appendChildren(token.children, el); + 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); + + for (const x of intersperse('br', nodes)) { + el.appendChild(x === 'br' ? doc.createElement('br') : x); + } + + return el; + }, + + url(token) { + const a = doc.createElement('a'); + a.href = token.node.props.url; + a.textContent = token.node.props.url; + return a; + }, + + search(token) { + const a = doc.createElement('a'); + a.href = `https://www.google.com/?#q=${token.node.props.query}`; + a.textContent = token.node.props.content; + return a; + } + }; + + appendChildren(tokens, doc.body); + + return `

${doc.body.innerHTML}

`; +} diff --git a/src/mfm/to-string.ts b/src/mfm/to-string.ts new file mode 100644 index 0000000000..65090b103d --- /dev/null +++ b/src/mfm/to-string.ts @@ -0,0 +1,116 @@ +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 `${appendChildren(token.children, opts)}`; + }, + + strike(token, opts) { + return `~~${appendChildren(token.children, opts)}~~`; + }, + + italic(token, opts) { + return `${appendChildren(token.children, opts)}`; + }, + + motion(token, opts) { + return `${appendChildren(token.children, opts)}`; + }, + + spin(token, opts) { + return `${appendChildren(token.children, opts)}`; + }, + + jump(token, opts) { + return `${appendChildren(token.children, opts)}`; + }, + + flip(token, opts) { + return `${appendChildren(token.children, opts)}`; + }, + + blockCode(token) { + return `\`\`\`${token.node.props.lang || ''}\n${token.node.props.code}\n\`\`\`\n`; + }, + + center(token, opts) { + return `
${appendChildren(token.children, opts)}
`; + }, + + 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) { + if (token.node.props.silent) { + return `?[${appendChildren(token.children, opts)}](${token.node.props.url})`; + } else { + 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(); +} diff --git a/src/mfm/toHtml.ts b/src/mfm/toHtml.ts deleted file mode 100644 index 1292292154..0000000000 --- a/src/mfm/toHtml.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { JSDOM } from 'jsdom'; -import config from '../config'; -import { intersperse } from '../prelude/array'; -import { MfmForest, MfmTree } from './prelude'; -import { IMentionedRemoteUsers } from '../models/entities/note'; - -export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) { - if (tokens == null) { - return null; - } - - const { window } = new JSDOM(''); - - const doc = window.document; - - function appendChildren(children: MfmForest, targetElement: any): void { - for (const child of children.map(t => handlers[t.node.type](t))) targetElement.appendChild(child); - } - - const handlers: { [key: string]: (token: MfmTree) => any } = { - bold(token) { - const el = doc.createElement('b'); - appendChildren(token.children, el); - 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); - return el; - }, - - strike(token) { - const el = doc.createElement('del'); - appendChildren(token.children, el); - return el; - }, - - italic(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - motion(token) { - const el = doc.createElement('i'); - appendChildren(token.children, el); - return el; - }, - - spin(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; - }, - - 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'); - inner.innerHTML = token.node.props.code; - pre.appendChild(inner); - return pre; - }, - - center(token) { - const el = doc.createElement('div'); - appendChildren(token.children, el); - return el; - }, - - emoji(token) { - return doc.createTextNode(token.node.props.emoji ? token.node.props.emoji : `\u200B:${token.node.props.name}:\u200B`); - }, - - hashtag(token) { - const a = doc.createElement('a'); - a.href = `${config.url}/tags/${token.node.props.hashtag}`; - a.textContent = `#${token.node.props.hashtag}`; - a.setAttribute('rel', 'tag'); - return a; - }, - - inlineCode(token) { - const el = doc.createElement('code'); - el.textContent = token.node.props.code; - return el; - }, - - mathInline(token) { - const el = doc.createElement('code'); - el.textContent = token.node.props.formula; - return el; - }, - - mathBlock(token) { - const el = doc.createElement('code'); - el.textContent = token.node.props.formula; - return el; - }, - - link(token) { - const a = doc.createElement('a'); - a.href = token.node.props.url; - appendChildren(token.children, a); - return a; - }, - - mention(token) { - const a = doc.createElement('a'); - const { username, host, acct } = token.node.props; - switch (host) { - case 'github.com': - a.href = `https://github.com/${username}`; - break; - case 'twitter.com': - a.href = `https://twitter.com/${username}`; - break; - default: - const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host); - a.href = remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${config.url}/${acct}`; - a.className = 'u-url mention'; - break; - } - a.textContent = acct; - return a; - }, - - quote(token) { - const el = doc.createElement('blockquote'); - appendChildren(token.children, el); - 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); - - for (const x of intersperse('br', nodes)) { - el.appendChild(x === 'br' ? doc.createElement('br') : x); - } - - return el; - }, - - url(token) { - const a = doc.createElement('a'); - a.href = token.node.props.url; - a.textContent = token.node.props.url; - return a; - }, - - search(token) { - const a = doc.createElement('a'); - a.href = `https://www.google.com/?#q=${token.node.props.query}`; - a.textContent = token.node.props.content; - return a; - } - }; - - appendChildren(tokens, doc.body); - - return `

${doc.body.innerHTML}

`; -} diff --git a/src/mfm/toString.ts b/src/mfm/toString.ts deleted file mode 100644 index 65090b103d..0000000000 --- a/src/mfm/toString.ts +++ /dev/null @@ -1,116 +0,0 @@ -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 `${appendChildren(token.children, opts)}`; - }, - - strike(token, opts) { - return `~~${appendChildren(token.children, opts)}~~`; - }, - - italic(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - motion(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - spin(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - jump(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - flip(token, opts) { - return `${appendChildren(token.children, opts)}`; - }, - - blockCode(token) { - return `\`\`\`${token.node.props.lang || ''}\n${token.node.props.code}\n\`\`\`\n`; - }, - - center(token, opts) { - return `
${appendChildren(token.children, opts)}
`; - }, - - 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) { - if (token.node.props.silent) { - return `?[${appendChildren(token.children, opts)}](${token.node.props.url})`; - } else { - 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(); -} diff --git a/src/models/repositories/note.ts b/src/models/repositories/note.ts index d29a48b7ec..3c5500f493 100644 --- a/src/models/repositories/note.ts +++ b/src/models/repositories/note.ts @@ -6,7 +6,7 @@ import { ensure } from '../../prelude/ensure'; import { SchemaType } from '../../misc/schema'; import { awaitAll } from '../../prelude/await-all'; import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '../../misc/reaction-lib'; -import { toString } from '../../mfm/toString'; +import { toString } from '../../mfm/to-string'; import { parse } from '../../mfm/parse'; import { Emoji } from '../entities/emoji'; import { concat } from '../../prelude/array'; diff --git a/src/remote/activitypub/misc/get-note-html.ts b/src/remote/activitypub/misc/get-note-html.ts index dba915fee9..6990a4ae5e 100644 --- a/src/remote/activitypub/misc/get-note-html.ts +++ b/src/remote/activitypub/misc/get-note-html.ts @@ -1,5 +1,5 @@ import { Note } from '../../../models/entities/note'; -import { toHtml } from '../../../mfm/toHtml'; +import { toHtml } from '../../../mfm/to-html'; import { parse } from '../../../mfm/parse'; export default function(note: Note) { diff --git a/src/remote/activitypub/misc/html-to-mfm.ts b/src/remote/activitypub/misc/html-to-mfm.ts index 5d3cf0b774..5cca04df21 100644 --- a/src/remote/activitypub/misc/html-to-mfm.ts +++ b/src/remote/activitypub/misc/html-to-mfm.ts @@ -1,6 +1,6 @@ import { IObject } from '../type'; import { extractApHashtagObjects } from '../models/tag'; -import { fromHtml } from '../../../mfm/fromHtml'; +import { fromHtml } from '../../../mfm/from-html'; export function htmlToMfm(html: string, tag?: IObject | IObject[]) { const hashtagNames = extractApHashtagObjects(tag).map(x => x.name).filter((x): x is string => x != null); diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts index 91b1c5cd60..4b8fa9a551 100644 --- a/src/remote/activitypub/models/person.ts +++ b/src/remote/activitypub/models/person.ts @@ -4,7 +4,7 @@ import config from '../../../config'; import Resolver from '../resolver'; import { resolveImage } from './image'; import { isCollectionOrOrderedCollection, isCollection, IPerson, getApId, getOneApHrefNullable, IObject, isPropertyValue, IApPropertyValue } from '../type'; -import { fromHtml } from '../../../mfm/fromHtml'; +import { fromHtml } from '../../../mfm/from-html'; import { htmlToMfm } from '../misc/html-to-mfm'; import { resolveNote, extractEmojis } from './note'; import { registerOrFetchInstanceDoc } from '../../../services/register-or-fetch-instance-doc'; diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts index af0e446ac1..56ff10319a 100644 --- a/src/remote/activitypub/renderer/person.ts +++ b/src/remote/activitypub/renderer/person.ts @@ -2,7 +2,7 @@ import renderImage from './image'; import renderKey from './key'; import config from '../../../config'; import { ILocalUser } from '../../../models/entities/user'; -import { toHtml } from '../../../mfm/toHtml'; +import { toHtml } from '../../../mfm/to-html'; import { parse } from '../../../mfm/parse'; import { getEmojis } from './note'; import renderEmoji from './emoji'; -- cgit v1.2.3-freya