Resync initial event connections and render nested task blocks

This commit is contained in:
eezd committed 2026-10-20 18:59:54 +08:00
1 parent 2df1ab87df
commit f9cfb138ea
4 files changed
+52 -15

No files matched your search

+8
View File
@@ -65,6 +65,14 @@ describe('安全模式', () => {
})
describe('Typora 扩展', () => {
it('任务列表保留嵌套列表和后续段落,正确处理松散与紧凑列表', () => {
expect(normalize(renderMarkdown('- [ ] 父任务\n - 子任务\n\n 后续说明\n'))).toBe(normalize(
'<ul><li><p><input type="checkbox" disabled="" /> 父任务</p><ul><li>子任务</li></ul><p>后续说明</p></li></ul>',
))
expect(normalize(renderMarkdown('- [x] 已完成\n - [ ] 子任务\n- [ ] 下一项\n'))).toBe(normalize(
'<ul><li><input type="checkbox" disabled="" checked="" /> 已完成\n<ul><li><input type="checkbox" disabled="" /> 子任务</li></ul></li><li><input type="checkbox" disabled="" /> 下一项</li></ul>',
))
})
it('高亮、上下标、脚注引用', () => {
expect(renderMarkdown('==a== x^2^ H~2~O[^1]')).toBe('<p><mark>a</mark> x<sup>2</sup> H<sub>2</sub>O<sup class="footnote-ref"><a href="#fn-1">1</a></sup></p>\n')
})
+10 -10
View File
@@ -362,7 +362,7 @@ export function renderMarkdown(src: string, { parser = markdownParser, unsafe =
function blockChildren(node: SyntaxNode, withDefinitions = false): SyntaxNode[] {
const out: SyntaxNode[] = []
for (let ch = node.firstChild; ch; ch = ch.nextSibling) {
if (/Mark$/.test(ch.name) || ch.name === 'Task') continue
if (/Mark$/.test(ch.name)) continue
if (ch.name !== 'LinkReference' || withDefinitions) out.push(ch)
}
return out
@@ -403,6 +403,12 @@ export function renderMarkdown(src: string, { parser = markdownParser, unsafe =
const body = inline(node, node.from, node.to).trim()
return tight ? body + '\n' : `<p>${body}</p>\n`
}
case 'Task': {
const marker = node.getChild('TaskMarker')!
const checked = text(marker.from + 1, marker.from + 2) !== ' ' ? ' checked=""' : ''
const body = `<input type="checkbox" disabled=""${checked} /> ${inline(node, marker.to, node.to).trim()}`
return tight ? body + '\n' : `<p>${body}</p>\n`
}
case 'Blockquote':
return `<blockquote>\n${blocks(node)}</blockquote>\n`
case 'BulletList':
@@ -467,18 +473,12 @@ export function renderMarkdown(src: string, { parser = markdownParser, unsafe =
function listItem(item: SyntaxNode, tight: boolean): string {
const kids = blockChildren(item)
const task = item.getChild('Task')
if (task) {
const marker = task.getChild('TaskMarker')!
const checked = text(marker.from + 1, marker.from + 2) !== ' ' ? ' checked=""' : ''
const body = inline(task, marker.to, task.to).trim()
return `<li><input type="checkbox" disabled=""${checked} /> ${body}</li>\n`
}
if (!kids.length) return '<li></li>\n'
let body = ''
for (const k of kids) body += block(k, tight)
const startsInline = tight && kids[0].name === 'Paragraph'
const endsInline = tight && kids[kids.length - 1].name === 'Paragraph'
const startsInline = tight && (kids[0].name === 'Paragraph' || kids[0].name === 'Task')
const last = kids[kids.length - 1].name
const endsInline = tight && (last === 'Paragraph' || last === 'Task')
if (!startsInline) body = '\n' + body
if (endsInline) body = body.replace(/\n$/, '')
return `<li>${body}</li>\n`