| import { visit } from 'unist-util-visit' |
| import type { Plugin } from 'unified' |
| import type { Root, Text } from 'mdast' |
|
|
| |
| export const remarkFootnotes: Plugin<[], Root> = () => { |
| return (tree: Root) => { |
| |
| visit(tree, 'text', (node: Text, index, parent) => { |
| if (!parent || typeof index !== 'number') return |
|
|
| const text = node.value |
| const footnoteRegex = /\[\^([^\]]+)\]/g |
| let match |
| const replacements: any[] = [] |
| let lastIndex = 0 |
|
|
| while ((match = footnoteRegex.exec(text)) !== null) { |
| const [fullMatch, id] = match |
| const startIndex = match.index! |
|
|
| |
| if (startIndex > lastIndex) { |
| replacements.push({ |
| type: 'text', |
| value: text.slice(lastIndex, startIndex) |
| }) |
| } |
|
|
| |
| const nextIndex = startIndex + fullMatch.length |
| const remainingText = text.slice(nextIndex) |
| const hasConsecutiveFootnote = /^\[\^[^\]]+\]/.test(remainingText) |
|
|
| |
| const footnoteHtml = `<sup><a href="#footnote-${id}" class="footnote-ref">${id}</a></sup>` |
|
|
| |
| const htmlWithSpacing = hasConsecutiveFootnote |
| ? footnoteHtml + ' ' |
| : footnoteHtml |
|
|
| replacements.push({ |
| type: 'html', |
| value: htmlWithSpacing |
| }) |
|
|
| lastIndex = startIndex + fullMatch.length |
| } |
|
|
| |
| if (lastIndex < text.length) { |
| replacements.push({ |
| type: 'text', |
| value: text.slice(lastIndex) |
| }) |
| } |
|
|
| |
| if (replacements.length > 1) { |
| parent.children.splice(index, 1, ...replacements) |
| } |
| }) |
| } |
| } |
|
|