From 1502bc669083f91e1b706f3a947f0c77ce1e8de3 Mon Sep 17 00:00:00 2001 From: mattyatea Date: Sat, 20 Jul 2024 10:11:56 +0900 Subject: [PATCH] =?UTF-8?q?Fix(Backend):=20MfmService.toHtml=20=E3=82=92?= =?UTF-8?q?=20JSDOM=20=E3=81=AB=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: riku6460 <17585784+riku6460@users.noreply.github.com> --- packages/backend/src/core/MfmService.ts | 49 +++++++++++++------------ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts index 9f196d87036b..a44636f701a9 100644 --- a/packages/backend/src/core/MfmService.ts +++ b/packages/backend/src/core/MfmService.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: syuilo and misskey-project , Type4ny-project + * SPDX-FileCopyrightText: syuilo and misskey-project, Type4ny-project * SPDX-License-Identifier: AGPL-3.0-only */ @@ -7,19 +7,16 @@ import { URL } from 'node:url'; import { Inject, Injectable } from '@nestjs/common'; import * as parse5 from 'parse5'; import { JSDOM } from 'jsdom'; -import serialize from 'w3c-xmlserializer'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { intersperse } from '@/misc/prelude/array.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; import { bindThis } from '@/decorators.js'; -import type { DefaultTreeAdapterMap } from 'parse5'; +import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js'; import type * as mfm from 'mfm-js'; -const treeAdapter = parse5.defaultTreeAdapter; -type Node = DefaultTreeAdapterMap['node']; -type ChildNode = DefaultTreeAdapterMap['childNode']; +const treeAdapter = TreeAdapter.defaultTreeAdapter; const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/; const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; @@ -49,7 +46,7 @@ export class MfmService { return text.trim(); - function getText(node: Node): string { + function getText(node: TreeAdapter.Node): string { if (treeAdapter.isTextNode(node)) return node.value; if (!treeAdapter.isElementNode(node)) return ''; if (node.nodeName === 'br') return '\n'; @@ -61,7 +58,7 @@ export class MfmService { return ''; } - function appendChildren(childNodes: ChildNode[]): void { + function appendChildren(childNodes: TreeAdapter.ChildNode[]): void { if (childNodes) { for (const n of childNodes) { analyze(n); @@ -69,16 +66,14 @@ export class MfmService { } } - function analyze(node: Node) { + function analyze(node: TreeAdapter.Node) { if (treeAdapter.isTextNode(node)) { text += node.value; return; } // Skip comment or document type node - if (!treeAdapter.isElementNode(node)) { - return; - } + if (!treeAdapter.isElementNode(node)) return; switch (node.nodeName) { case 'br': { @@ -86,7 +81,8 @@ export class MfmService { break; } - case 'a': { + case 'a': + { const txt = getText(node); const rel = node.attrs.find(x => x.name === 'rel'); const href = node.attrs.find(x => x.name === 'href'); @@ -134,7 +130,8 @@ export class MfmService { break; } - case 'h1': { + case 'h1': + { text += '【'; appendChildren(node.childNodes); text += '】\n'; @@ -142,14 +139,16 @@ export class MfmService { } case 'b': - case 'strong': { + case 'strong': + { text += '**'; appendChildren(node.childNodes); text += '**'; break; } - case 'small': { + case 'small': + { text += ''; appendChildren(node.childNodes); text += ''; @@ -157,7 +156,8 @@ export class MfmService { } case 's': - case 'del': { + case 'del': + { text += '~~'; appendChildren(node.childNodes); text += '~~'; @@ -165,7 +165,8 @@ export class MfmService { } case 'i': - case 'em': { + case 'em': + { text += ''; appendChildren(node.childNodes); text += ''; @@ -206,7 +207,8 @@ export class MfmService { case 'h3': case 'h4': case 'h5': - case 'h6': { + case 'h6': + { text += '\n\n'; appendChildren(node.childNodes); break; @@ -219,7 +221,8 @@ export class MfmService { case 'article': case 'li': case 'dt': - case 'dd': { + case 'dd': + { text += '\n'; appendChildren(node.childNodes); break; @@ -240,9 +243,9 @@ export class MfmService { return null; } - const { window } = new JSDOM() as unknown as { window: Window }; + const fragment = JSDOM.fragment(''); - const doc = window.document; + const doc = fragment.ownerDocument; const body = doc.createElement('p'); @@ -458,6 +461,6 @@ export class MfmService { appendChildren(nodes, body); - return serialize(body); + return body.outerHTML; } }