1import { parse } from 'acorn'; 2import { visit } from 'unist-util-visit'; 3 4/** 5 * @typedef {import('@types/mdast').Root} Root - https://github.com/syntax-tree/mdast#root 6 * @typedef {import('@types/mdast').Heading} Heading - https://github.com/syntax-tree/mdast#heading 7 */ 8 9/** 10 * Find all headings within a MDX document, and export them as JS array. 11 * This uses the MDAST's `heading` and tries to guess the children's content. 12 * When the node has an ID, generated by `remark-slug`, the ID is added to the exported object. 13 * 14 * @param {object} options 15 * @param {string} [options.exportName="headings"] 16 */ 17export default function remarkExportHeadings(options = {}) { 18 const { exportName = 'headings' } = options; 19 20 /** @param {Root} tree */ 21 return tree => { 22 const headings = []; 23 24 /** @param {Heading} node */ 25 const visitor = node => { 26 if (node.children.length > 0) { 27 headings.push({ 28 id: node.data?.id, 29 depth: node.depth, 30 type: node.children.find(node => node.type !== 'text')?.type || 'text', 31 title: node.children.map(child => child.value).join(' '), 32 }); 33 } 34 }; 35 36 visit(tree, 'heading', visitor); 37 38 tree.children.push({ 39 type: 'mdxjsEsm', 40 data: { 41 estree: parse(`export const ${exportName} = ${JSON.stringify(headings)};`, { 42 sourceType: 'module', 43 ecmaVersion: 2022, 44 }), 45 }, 46 }); 47 }; 48} 49