diff --git a/src/components/Main/MainView/MessageInput/composables/usePostMessage.ts b/src/components/Main/MainView/MessageInput/composables/usePostMessage.ts index 131d01259..626815557 100644 --- a/src/components/Main/MainView/MessageInput/composables/usePostMessage.ts +++ b/src/components/Main/MainView/MessageInput/composables/usePostMessage.ts @@ -1,6 +1,5 @@ import type { ChannelId } from '/@/types/entity-ids' import apis, { buildFilePathForPost, formatResizeError } from '/@/lib/apis' -import { replace as embedInternalLink } from '/@/lib/markdown/internalLinkEmbedder' import useChannelPath from '/@/composables/useChannelPath' import { computed, ref, unref } from 'vue' import { nullUuid } from '/@/lib/basic/uuid' @@ -93,23 +92,10 @@ const usePostMessage = ( bothChannelsMapInitialFetchPromise.value ]) - const embededText = embedInternalLink(state.text, { - getUser: findUserByName, - getGroup: getUserGroupByName, - getChannel: path => { - try { - const id = channelPathToId(path.split('/'), channelTree.value) - return { id } - } catch { - return undefined - } - } - }) - const dummyFileUrls = state.attachments.map(() => buildFilePathForPost(nullUuid) ) - const dummyText = createContent(embededText, dummyFileUrls) + const dummyText = createContent(state.text, dummyFileUrls) if (countLength(dummyText) > MESSAGE_MAX_LENGTH) { addErrorToast('メッセージが長すぎます') return @@ -124,7 +110,7 @@ const usePostMessage = ( }) await apis.postMessage(cId, { - content: createContent(embededText, fileUrls) + content: createContent(state.text, fileUrls) }) clearState() diff --git a/src/lib/markdown/internalLinkEmbedder.ts b/src/lib/markdown/internalLinkEmbedder.ts deleted file mode 100644 index da2724194..000000000 --- a/src/lib/markdown/internalLinkEmbedder.ts +++ /dev/null @@ -1,168 +0,0 @@ -/** - * https://github.com/traPtitech/traQ/blob/master/utils/message/replacer.goと同様 - */ - -const mentionRegex = /:?[@@]([^\s@@]{0,31}[^\s@@:])/g -const userStartsRegex = /^[@@]([a-zA-Z0-9_-]{1,32})/g -const channelRegex = /[##]([a-zA-Z0-9_/-]+)/g - -const backQuote = '`' -const dollar = '$' -const defaultCodeTokenLength = 3 - -export type ReplaceGetters = UserAndGroupGetters & ChannelGetter - -interface UserAndGroupGetters { - /** - * nameは大文字小文字を無視する - */ - getUser: (userName: string) => Readonly | undefined - /** - * nameは大文字小文字を無視する - */ - getGroup: (groupName: string) => Readonly | undefined -} -interface ChannelGetter { - /** - * nameは大文字小文字を無視する - */ - getChannel: (channelPath: string) => Readonly | undefined -} - -export interface Entity { - id: string -} - -/** - * コードブロックとLaTeXブロック内でない箇所の内部リンク埋め込みを行う - * replacer.goのReplaceと同様のコード - */ -export const replace = (m: string, getters: Readonly) => { - let inCodeBlock = false - let inLatexBlock = false - let codeTokenLength = defaultCodeTokenLength - - const lines = m.split('\n') - const newLines = lines.map(line => { - if (!inLatexBlock && line.startsWith('`'.repeat(codeTokenLength))) { - // `の数が一致するものと組み合うようにする - if (!inCodeBlock) { - codeTokenLength = countPrefix(line, backQuote) - } else { - codeTokenLength = defaultCodeTokenLength - } - - inCodeBlock = !inCodeBlock - } - if (!inCodeBlock && line.startsWith('$$')) { - inLatexBlock = !inLatexBlock - } - if (inCodeBlock || inLatexBlock) { - return line - } - // 「```」のブロックでも「$$」ブロック内でもないときに置換 - - let newLine = '' - // 「`」「$」で囲まれていないところの始めの文字のindex - let noExpressionStartIndex = 0 - const chs = [...line] - for (let i = 0; i < chs.length; i++) { - const ch = chs[i] - if (ch !== backQuote && ch !== dollar) { - continue - } - - // 囲まれていない場所が終了したのでその箇所は置換する - newLine += replaceAll( - chs.slice(noExpressionStartIndex, i).join(''), - getters - ) - - if (ch === dollar) { - // 「`」は「$」よりも優先されるので - // 「$ ` $」のように「`」がペアの「$」より前にあるときは - // 「$」のペアとして処理しない - const backQuoteI = chs.indexOf(backQuote, i + 1) - const dollarI = chs.indexOf(dollar, i + 1) - if (backQuoteI !== -1 && dollarI !== -1 && backQuoteI < dollarI) { - newLine += ch - noExpressionStartIndex = i + 1 - continue - } - } - const newI = chs.indexOf(ch, i + 1) - if (newI === -1) { - // 「$」/「`」のペアがないとき - newLine += ch - noExpressionStartIndex = i + 1 - continue - } - newLine += chs.slice(i, newI).join('') - i = newI - noExpressionStartIndex = newI - } - // 最後のペア以降の置換 - newLine += replaceAll(chs.slice(noExpressionStartIndex).join(''), getters) - return newLine - }) - return newLines.join('\n') -} - -const replaceAll = (m: string, getters: Readonly) => { - return replaceMention(replaceChannel(m, getters), getters) -} - -const replaceMention = (m: string, getters: Readonly) => { - return m.replace(mentionRegex, s => { - // 始まりが:なものを除外 - if (s.startsWith(':')) { - return s - } - - // .slice(1)は先頭の@を消すため - // 小文字化はgetter内で行う - const name = s.slice(1) - const uid = getters.getUser(name)?.id - if (uid) { - return `!{"type":"user","raw":"${s}","id":"${uid}"}` - } - const gid = getters.getGroup(name)?.id - if (gid) { - return `!{"type":"group","raw":"${s}","id":"${gid}"}` - } - - return s.replace(userStartsRegex, s => { - // .slice(1)は先頭の@を消すため - // 小文字化はgetter内で行う - const name = s.slice(1) - - const uid = getters.getUser(name)?.id - if (uid) { - return `!{"type":"user","raw":"${s}","id":"${uid}"}` - } - return s - }) - }) -} - -const replaceChannel = (m: string, getter: Readonly) => { - return m.replace(channelRegex, s => { - // .slice(1)は先頭の#を消すため - // 小文字化はgetter内で行う - const t = s.slice(1) - const cid = getter.getChannel(t)?.id - if (cid) { - return `!{"type":"channel","raw":"${s}","id":"${cid}"}` - } - return s - }) -} - -const countPrefix = (line: string, letter: string) => { - let count = 0 - for (const ch of line) { - if (ch !== letter) break - count++ - } - return count -}