// rehype plugin to post-process citations and footnotes at build-time // - Normalizes the bibliography into
) const nestedWithId = getChildren(it).find((n) => isElement(n) && getAttr(n, 'id')); if (nestedWithId) setAttr(li, 'id', getAttr(nestedWithId, 'id')); ol.children.push(li); } } root.children = [ol]; } // For existing structures, try to promote ids from children when missing for (const li of getChildren(ol)) { if (!isElement(li) || li.tagName !== 'li') continue; if (!getAttr(li, 'id')) { const nestedWithId = getChildren(li).find((n) => isElement(n) && getAttr(n, 'id')); if (nestedWithId) setAttr(li, 'id', getAttr(nestedWithId, 'id')); } // Remove default footnote backrefs anywhere inside (to avoid duplication) // But preserve KaTeX elements removeFootnoteBackrefAnchors(li); } setAttr(root, 'data-built-footnotes', '1'); // Collect id set const idSet = new Set(); for (const li of getChildren(ol)) { if (!isElement(li) || li.tagName !== 'li') continue; const id = getAttr(li, 'id'); if (id) idSet.add(String(id)); } return { root, ol, idSet }; }; const { root: footRoot, ol: footOl, idSet: footIdSet } = cleanupFootnotes(); // Collect in-text anchors pointing to footnotes const { idToBacklinks: footIdToBacklinks } = collectBacklinksForIdSet(footIdSet, 'footctx'); // Append backlinks into footnote list items (identical pattern to references) appendBackrefsBlock(footOl, footIdToBacklinks, 'Back to footnote call'); }; }