fix(toc): include raw KaTeX from headings in toc

The KaTeX renderer usually renders the raw KaTeX into MathML.
This can not be properly displayed inside the toc and further
makes problems when trying to render a fallback, because then
parts could become duplicated. This commit fixes this by
stripping MathML code completely for the title processing,
leaving the raw KaTeX code intact. The only downside of this
approach is that the surrounding '$' get lost, but this seems
still better than nothing or duplicated content.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Erik Michelson
2026-07-27 18:02:54 +02:00
committed by Philip Molares
parent 230f901323
commit d16bdecab6
4 changed files with 45 additions and 1 deletions
@@ -46,6 +46,17 @@ describe('extract first heading', () => {
expect(extractFirstHeading(document)).toBe('Image Alt')
})
it('ignores MathML duplicated by KaTeX', () => {
const headline = new Element(`h${headlineIndex}`, {}, [
new Element('span', { class: 'katex-mathml' }, [
new Element('math', {}, [new Element('mi', {}, [new Text('alpha')])]),
]),
new Element('span', { class: 'katex-html', 'aria-hidden': 'true' }, [new Text('alpha')]),
])
const document = new Document([headline])
expect(extractFirstHeading(document)).toBe('alpha')
})
it('extracts only the first found headline', () => {
const headline1 = new Element(`h${headlineIndex}`, {}, [new Text(`headline${headlineIndex}`)])
const headline2 = new Element(`h${headlineIndex}`, {}, [new Text('headline1')])
@@ -43,6 +43,8 @@ function extractInnerTextFromTag(node: Element): string {
return ''
} else if (node.name === 'img') {
return findAttribute(node, 'alt')?.value ?? ''
} else if (node.name === 'math') {
return ''
} else {
return node.children.reduce((state, child) => {
return state + extractInnerTextFromNode(child)
+31
View File
@@ -183,4 +183,35 @@ describe('toc', () => {
`),
).toMatchSnapshot()
})
it('includes inline math in heading names', () => {
const callback = jest.fn()
const markdownIt = new MarkdownIt().use(toc, { callback })
markdownIt.inline.ruler.before('text', 'inlineMath', (state, silent) => {
if (state.src.slice(state.pos, state.pos + 8) !== '$\\alpha$') {
return false
}
if (!silent) {
const token = state.push('inline_math', '', 0)
token.content = '\\alpha'
}
state.pos += 8
return true
})
markdownIt.render('# $\\alpha$-foo')
expect(callback).toHaveBeenCalledWith({
children: [
{
children: [],
level: 1,
name: '\\alpha-foo',
},
],
level: 0,
name: '',
})
})
})
+1 -1
View File
@@ -37,6 +37,6 @@ export const defaultOptions: TocOptions = {
linkClass: '',
level: 1,
listType: 'ol',
allowedTokenTypes: ['text', 'code_inline'],
allowedTokenTypes: ['text', 'code_inline', 'math', 'inline_math', 'display_math'],
slugify: defaultSlugify,
}