| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import MarkdownIt from 'markdown-it'
- import subscript from 'markdown-it-sub'
- import superscript from 'markdown-it-sup'
- import footnote from 'markdown-it-footnote'
- import taskLists from 'markdown-it-task-lists'
- import abbr from 'markdown-it-abbr'
- import container from 'markdown-it-container'
- import DOMPurify from 'dompurify'
- import highlightJs from 'highlight.js'
- import 'highlight.js/styles/github.css'
- highlightJs.configure({
- ignoreUnescapedHTML: true, // 防止XSS
- throwUnescapedHTML: true, // 安全检测
- languages: ['javascript', 'typescript', 'html', 'css', 'json', 'bash']
- })
- // 创建 markdown-it 实例
- const md = new MarkdownIt({
- html: true, // 启用html标签
- linkify: true, // 自动转换URL为链接
- typographer: true, // 启用排版美化
- highlight: (code, language) => {
- // 安全处理未转义内容
- const safeStr: any = md.utils.escapeHtml(code)
- if (language && highlightJs.getLanguage(language)) {
- try {
- return `<pre class="hljs"><code>${highlightJs.highlight(safeStr, { language: language, ignoreIllegals: true }).value
- }</code></pre>`
- } catch (__) {
- }
- }
- return `<pre class="hljs"><code>${safeStr}</code></pre>`
- }
- })
- md.use(subscript);
- md.use(superscript);
- md.use(footnote);
- md.use(taskLists);
- md.use(abbr);
- md.use(container);
- // 解析 Markdown 文本
- export const parseMarkdown = (markdownText: any) => {
- let rawHtml = md.render(markdownText)
- return DOMPurify.sanitize(rawHtml)
- }
- export const extractPlainText = (markdown: string) => {
- const md = new MarkdownIt({
- // 禁用所有HTML标签渲染
- html: false,
- // 禁用自动链接识别
- linkify: false,
- // 禁用自动换行转换
- breaks: false,
- // 禁用typographer转换(如引号转换)
- typographer: false
- });
- // 自定义渲染器,只返回文本内容
- const originalRender = md.renderer.rules.text;
- md.renderer.rules.text = function (tokens, idx, options, env, self) {
- return originalRender ? originalRender(tokens, idx, options, env, self) : tokens[idx].content;
- };
- let openFnc = function () {
- return '';
- };
- // 处理各种token类型
- md.renderer.rules.link_open = md.renderer.rules.link_close = openFnc;
- md.renderer.rules.strong_open = md.renderer.rules.strong_close = openFnc;
- md.renderer.rules.em_open = md.renderer.rules.em_close = openFnc;
- md.renderer.rules.heading_open = md.renderer.rules.heading_close = openFnc;
- md.renderer.rules.paragraph_open = md.renderer.rules.paragraph_close = openFnc;
- md.renderer.rules.list_item_open = md.renderer.rules.list_item_close = openFnc;
- md.renderer.rules.ordered_list_open = md.renderer.rules.ordered_list_close = openFnc;
- md.renderer.rules.bullet_list_open = md.renderer.rules.bullet_list_close = openFnc;
- md.renderer.rules.code_block = md.renderer.rules.fence = openFnc;
- md.renderer.rules.blockquote_open = md.renderer.rules.blockquote_close = openFnc;
- // 处理图片(完全忽略)
- md.renderer.rules.image = function () {
- return '';
- };
- // 渲染并清理结果
- return md.render(markdown)
- .replace(/\s+/g, ' ')
- .replace(/<[^>]*>/g, '')
- .trim();
- }
|