,
// 列表项/引用内部的换行保持
,与 tiptap 富文本回写行为对齐
breaks: true,
linkify: false,
})
applyResumeDialectPlugins(md, options)
// icon:/svg: 渲染规则仅在预览渲染实例注册(编辑器解析实例中保持文本)
md.use(iconsPlugin)
md.use(rendererCompatPlugin)
return md
}
/**
* 将简历方言插件注入到任意 markdown-it 实例。
*
* 供富文本编辑器(tiptap-markdown)解析 markdown 时复用同一套方言:
* 布局容器 / 段落逐行 / 列表收紧 / 强调兼容 / CJK 标点强调。
* 刻意不包含 icons 渲染(icon:/svg: 在编辑器内保持为文本,与历史行为一致)
* 和 rendererCompat(渲染契约仅对最终 HTML 输出有意义)。
*/
export function applyResumeDialectPlugins(md: any, options: ITransformOptions = {}) {
// tiptap-markdown 每次解析都会重复调用 parse.setup,防止规则重复注册
if ((md as any).__resumeDialectApplied) return md
;(md as any).__resumeDialectApplied = true
md.use(containersPlugin)
if (options.tightenLists !== false) md.use(tightenListsPlugin)
if (options.paragraphPerLine !== false) md.use(paragraphPerLinePlugin)
md.use(emphasisCompatPlugin)
md.use(markdownItCJKFriendly)
return md
}
/**
* 将 markdown 转换为 HTML
* @param template markdown 文本
* @param options 转换选项
*/
export function markdownToHTML(template: string, options?: ITransformOptions): string {
const op = { ...defaultOptions, ...(options || {}) }
if (op.svgMap) {
svgLoaderManager.setSvgMap(op.svgMap)
}
const md = createMarkdownRenderer(op)
// 压缩标签间的装饰性换行,恢复 v1 的紧凑输出。
// 消费方 CSS(.markdown-transform-html)带有 white-space: pre-line,
// markdown-it 风格的块间换行会被渲染成真实空行,导致块间距整体变大。
// pre 内部换行不受影响(内容换行不紧跟在 > 后);
后的换行一并去掉,
// 避免 pre-line 下出现双倍换行。
return md
.render(template ?? "")
.replace(/(
]*>)\n+/g, "$1")
.replace(/>\n+(?=<)/g, ">")
}