import MarkdownIt from "markdown-it"; import hljs from "highlight.js"; import mila from "markdown-it-link-attributes"; import mdKatex from "@traptitech/markdown-it-katex"; /** * Markdown */ const MarkdownUtils = { mdi: null, mds: null, /** * 解析Markdown * @param {*} text * @returns */ formatMsg: (text) => { // 如果存在body标签,只取body中的内容 const bodyMatch = text.match(/
]*>([\s\S]*?)<\/body>/i); if (bodyMatch) { text = bodyMatch[1]; } // 使用正则一次性替换所有的link、script、style标签 text = text.replace(/<(link|script|style)[^>]*>[\s\S]*?<\/\1>|<(link|script|style)[^>]*\/?>/gi, ''); // 处理图片标签 const imgRegex = /` }, } const MarkdownPluginUtils = { // 配置选项 config: { maxItems: 200, maxTitleLength: 200, maxDescLength: 1000, buttonLabels: { task: '创建任务', subtask: '创建子任务' } }, // HTML转义函数 escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); }, // 验证输入 validateInput(value, maxLength) { if (!value) return ''; if (typeof value !== 'string') return ''; if (value.length > maxLength) { return value.substring(0, maxLength) + '...'; } return value; }, // 清除空推理 clearEmptyReasoning(text) { return text.replace(/:::\s*reasoning\s*[\r\n]*\s*:::/g, ''); }, // 修改初始化插件函数(推理) initReasoningPlugin(md) { md.block.ruler.before('fence', 'reasoning', (state, startLine, endLine, silent) => { const start = state.bMarks[startLine] + state.tShift[startLine]; const max = state.eMarks[startLine]; const firstLine = state.src.slice(start, max).trim(); // 检查是否匹配 :::reasoning 开始标记 const match = firstLine.match(/^:::\s*reasoning(?:\s+(\S+))?$/); if (!match) { return false; } if (silent) { return true; } let nextLine = startLine + 1; let content = []; // 查找结束标记 ::: while (nextLine < endLine) { const lineStart = state.bMarks[nextLine] + state.tShift[nextLine]; const lineMax = state.eMarks[nextLine]; const currentLine = state.src.slice(lineStart, lineMax); if (currentLine.trim() === ':::') { break; } content.push(state.getLines(nextLine, nextLine + 1, state.tShift[nextLine], true)); nextLine++; } // 创建外层容器 let token = state.push('reasoning_open', 'div', 1); token.attrs = [['class', 'apply-reasoning']]; // 创建标签 token = state.push('reasoning_label_open', 'div', 1); token.attrs = [['class', 'reasoning-label']]; token = state.push('text', '', 0); token.content = $A.L('思考过程'); state.push('reasoning_label_close', 'div', -1); // 创建内容容器 token = state.push('reasoning_content_open', 'div', 1); token.attrs = [['class', 'reasoning-content']]; // 处理内容 if (content.length > 0) { state.md.block.parse(content.join('\n'), state.md, state.env, state.tokens); } // 关闭内容容器 state.push('reasoning_content_close', 'div', -1); // 关闭外层容器 state.push('reasoning_close', 'div', -1); state.line = nextLine + 1; return true; }); }, // 修改初始化插件函数(创建任务) initCreateTaskPlugin(md) { md.block.ruler.before('fence', 'create-task', (state, startLine, endLine, silent) => { const start = state.bMarks[startLine] + state.tShift[startLine]; const max = state.eMarks[startLine]; const firstLine = state.src.slice(start, max).trim(); // 检查开始标记,并获取status值 const match = firstLine.match(/^:::\s*(create-task-list|create-subtask-list)(?:\s+(\S+))?$/); if (!match) { return false; } if (silent) { return true; } // 获取按钮标题和状态 const listType = match[1] === 'create-task-list' ? 'task' : 'subtask'; const buttonTitle = this.config.buttonLabels[listType] || ''; const status = match[2] || ''; let nextLine = startLine + 1; let content = []; // 查找结束标记 while (nextLine < endLine) { const lineStart = state.bMarks[nextLine] + state.tShift[nextLine]; const lineMax = state.eMarks[nextLine]; const line = state.src.slice(lineStart, lineMax); if (line.trim() === ':::') { break; } content.push(line); nextLine++; } // 解析任务 const tasks = []; let currentTask = null; let isCollectingDesc = false; let descLines = []; content.forEach(line => { const titleMatch = line.trim().match(/^title:\s*(.+)$/); const descMatch = line.trim().match(/^desc:\s*(.*)$/); if (titleMatch) { // 如果已经有一个任务在处理中,保存它 if (currentTask) { if (descLines.length > 0) { currentTask.desc = descLines.join('\n'); } tasks.push(currentTask); } // 开始新的任务 currentTask = {title: titleMatch[1]}; isCollectingDesc = false; descLines = []; } else if (descMatch) { isCollectingDesc = true; if (descMatch[1]) { descLines.push(descMatch[1]); } } else if (isCollectingDesc && line.trim() && !line.trim().startsWith('title:')) { // 收集多行描述,但不包括空行和新的title行 descLines.push(line.trim()); } }); // 处理最后一个任务 if (currentTask) { if (descLines.length > 0) { currentTask.desc = descLines.join('\n'); } tasks.push(currentTask); } // 生成HTML const showIndex = tasks.length > 1; const taskItems = tasks.slice(0, this.config.maxItems).map((task, index) => [ '${lang}${$A.L('复制')}${str}
/g, '\n').replace(/(^|\s+)```([\s\S]*)```/gm, '') if (/<\/(strong|s|em|u|ol|ul|li|blockquote|pre|img|a)>/i.test(tmp)) { return false } if (/]+?class="mention"[^>]*?>/i.test(tmp)) { return false } // const el = document.createElement('div') el.style.position = 'fixed' el.style.top = '0' el.style.left = '0' el.style.width = '10px' el.style.height = '10px' el.style.overflow = 'hidden' el.style.zIndex = '-9999' el.style.opacity = '0' el.innerHTML = html document.body.appendChild(el) const text = el.innerText document.body.removeChild(el) // if ( /(^|\s+)#+\s(.*)$/m.test(text) // 标题 || /(^|\s+)\*\*(.*)\*\*/m.test(text) // 粗体 || /(^|\s+)__(.*)__/m.test(text) // 粗体 || /(^|\s+)\*(.*)\*/m.test(text) // 斜体 || /(^|\s+)_(.*)_/m.test(text) // 斜体 || /(^|\s+)~~(.*)~~/m.test(text) // 删除线 || /(^|\s+)\[(.*?)\]\((.*?)\)/m.test(text) // 链接 || /(^|\s+)!\[(.*?)\]\((.*?)\)/m.test(text) // 图片 || /(^|\s+)`(.*?)`/m.test(text) // 行内代码 || /(^|\s+)```([\s\S]*?)```/m.test(text) // 代码块 ) { return true } return false }