/**
* 列表收紧插件(tightenLists)
*
* v1 的列表永远是「紧凑」渲染:
内容。
* 标准 markdown 中,列表项之间有空行(模板和用户数据里非常常见)
* 会渲染成「松散」列表:内容
,视觉上多出段落间距。
*
* 本插件把列表项内的段落解包为裸 inline 内容,保持 v1 的紧凑结构。
* 同一列表项内的多个段落之间插入
,避免内容粘连。
* 引用块内的段落不受影响(markdown-it 的引用渲染更符合预期)。
*/
function tightenListsRule(state: any) {
const tokens = state.tokens
let liDepth = 0
let quoteDepth = 0
const unwraps: Array<{ index: number; insertBreak: boolean }> = []
for (let i = 0; i < tokens.length; i++) {
const type = tokens[i].type
if (type === "list_item_open") {
if (liDepth === 0) quoteDepth = 0 // 新的顶层列表项重置引用状态
liDepth++
} else if (type === "list_item_close") {
liDepth--
} else if (type === "blockquote_open") {
quoteDepth++
} else if (type === "blockquote_close") {
quoteDepth--
} else if (liDepth > 0 && quoteDepth === 0 && type === "paragraph_open") {
if (tokens[i + 2]?.type === "paragraph_close") {
unwraps.push({ index: i, insertBreak: tokens[i - 1]?.type === "inline" })
}
}
}
for (let k = unwraps.length - 1; k >= 0; k--) {
const { index, insertBreak } = unwraps[k]
const inline = tokens[index + 1]
const replacement: any[] = [inline]
if (insertBreak) {
// 同一列表项内的第二个及之后的段落,用硬换行分隔
const br = new state.Token("hardbreak", "br", 0)
replacement.unshift(br)
}
tokens.splice(index, 3, ...replacement)
}
}
export function tightenListsPlugin(md: any) {
md.core.ruler.after("block", "resume_tighten_lists", tightenListsRule)
}