UNPKG

@mintlify/common

Version:

Commonly shared code within Mintlify

72 lines (71 loc) 3.27 kB
import { slugifyWithCounter } from '@sindresorhus/slugify'; import { createMdxJsxAttribute, getTOCTitle, getUnicodeId } from '../../lib/remark-utils.js'; export const remarkExtractTableOfContents = (mdxExtracts) => { // slugifyWithCounter adds a counter (eg. slug, slug-2, slug-3) to the end of the slug if the header // already exists. No counter is added for the first occurence. const slugify = slugifyWithCounter(); return (tree) => { const contents = []; let hasTopLayer = false; for (let nodeIndex = 0; nodeIndex < tree.children.length; nodeIndex++) { let node = tree.children[nodeIndex]; if ((node.type === 'heading' && [1, 2, 3, 4].includes(node.depth)) || (node.type === 'mdxJsxFlowElement' && ['h1', 'h2', 'h3', 'h4'].includes(node.name)) || (node.name === 'Update' && node.attributes.some((attr) => node.type === 'mdxJsxFlowElement' && attr.name === 'label'))) { let level; if (node.name === 'Update') { level = 1; node.depth = 1; } else { level = node.depth ? node.depth : node.name.split('')[1]; } let title = getTOCTitle(node); const encodedTitle = getUnicodeId(title); let slug; // if encoded title is already percent-encoded, return it as is // slugify doesn't support percent-encoded characters, like Chinese, Korean, etc. if (/%[0-9A-F]{2}/.test(encodedTitle)) { slug = slugify(encodedTitle, { decamelize: false, preserveCharacters: ['%'], lowercase: false, }); } else { slug = slugify(encodedTitle, { decamelize: false }); } let mdxJsxAttributes; if (node.name === 'Update') { mdxJsxAttributes = [...node.attributes, createMdxJsxAttribute('id', slug)]; } else { mdxJsxAttributes = [ createMdxJsxAttribute('level', level), createMdxJsxAttribute('id', slug), ]; } node.attributes = mdxJsxAttributes; node.type = 'mdxJsxFlowElement'; node.name = node.name === 'Update' ? 'Update' : 'Heading'; const depth = node.depth; if (level <= 2) { hasTopLayer = true; contents.push({ title, slug, depth, children: [] }); } else { // Account if there is no first layer let arrToPushInto = contents; if (hasTopLayer) { arrToPushInto = contents[contents.length - 1].children; } arrToPushInto.push({ title, slug, depth, children: [] }); } } } if (mdxExtracts) { mdxExtracts.tableOfContents = contents; } }; };