UNPKG

@mintlify/common

Version:

Commonly shared code within Mintlify

130 lines (129 loc) 5.27 kB
import { visit } from 'unist-util-visit'; import { buildMetaAttributes } from './buildMetaAttributes.js'; import { parseMetaString } from './parseMetaString.js'; export const FOCUS_CLASS_NAME = 'line-focus'; export const HIGHLIGHT_CLASS_NAME = 'line-highlight'; const exampleNames = ['RequestExample', 'ResponseExample']; const flowElementType = 'mdxJsxFlowElement'; function isElement(node, key = 'type', element = 'element') { return node != undefined && node[key] === element; } function addCodeBlocks(tree) { visit(tree, (node, i, parent) => { var _a, _b, _c; if (parent == null || i == null || !isElement(node) || !isElement(node, 'tagName', 'pre')) { return; } const code = node.children[0]; if (!isElement(code, 'tagName', 'code')) return; const isFlowElement = isElement(parent, 'type', flowElementType); const parentName = isFlowElement ? parent.name : undefined; let properties = Object.entries(code.properties); let meta; if (parentName && exampleNames.includes(parentName)) { const parentType = parentName.slice(0, -7); meta = parseMetaString(parentType); if (!((_a = code.data) === null || _a === void 0 ? void 0 : _a.meta)) { const data = (_b = code.data) !== null && _b !== void 0 ? _b : {}; data.meta = i === 0 ? parentType : `${parentType} ${i + 1}`; code.data = data; } } if (((_c = code.data) === null || _c === void 0 ? void 0 : _c.meta) && typeof code.data.meta === 'string') { meta = parseMetaString(code.data.meta); } const attributes = buildMetaAttributes(meta !== null && meta !== void 0 ? meta : {}); const lineNumber = addLineHighlightAndFocus(code, meta === null || meta === void 0 ? void 0 : meta.highlight, meta === null || meta === void 0 ? void 0 : meta.focus); if (lineNumber) { properties = properties.filter(([key]) => key !== 'numberOfLines'); attributes.push({ type: 'mdxJsxAttribute', name: 'numberOfLines', value: lineNumber.toString(), }); } const wrapElement = { type: flowElementType, name: 'CodeBlock', attributes: [ ...attributes, ...properties .filter(([_key, val]) => val != null) .map(([key, val]) => ({ type: 'mdxJsxAttribute', name: key, value: Array.isArray(val) ? val.join(' ') : val === null || val === void 0 ? void 0 : val.toString(), })), ], data: { _mdxExplicitJsx: true }, children: [], }; wrapElement.children = [node]; parent.children[i] = wrapElement; }); tree.children = [...tree.children]; } function addLineHighlightAndFocus(codeElement, highlightLines, focusLines) { let lineNumber = 0; // remove last empty line span if it exists const lastChild = codeElement.children[codeElement.children.length - 1]; if (lastChild && lastChild.type === 'element' && lastChild.tagName === 'span' && lastChild.properties.class && lastChild.children.length === 0) { const classValue = lastChild.properties.class; const hasLineClass = typeof classValue === 'string' ? classValue.includes('line') : Array.isArray(classValue) && classValue.includes('line'); if (hasLineClass) { codeElement.children.pop(); } } visit(codeElement, 'element', (span, _, spanParent) => { if (!spanParent || spanParent.type !== 'element' || spanParent.tagName !== 'code' || span.tagName !== 'span' || !span.properties.class) { return; } const classValue = span.properties.class; const hasLineClass = typeof classValue === 'string' ? classValue.includes('line') : Array.isArray(classValue) && classValue.includes('line'); if (!hasLineClass) { return; } lineNumber++; if (highlightLines && highlightLines.length && highlightLines.includes(lineNumber)) { addClassToSpan(span, HIGHLIGHT_CLASS_NAME); } if (focusLines && focusLines.length && focusLines.includes(lineNumber)) { addClassToSpan(span, FOCUS_CLASS_NAME); } }); if (lineNumber > 0) { codeElement.properties.numberOfLines = lineNumber; } return lineNumber; } function addClassToSpan(span, className) { const currentClass = span.properties.class; if (typeof currentClass === 'string') { span.properties.class = currentClass + ' ' + className; } else if (Array.isArray(currentClass)) { span.properties.class = [...currentClass, className]; } else { span.properties.class = className; } } export function rehypeCodeBlocks() { return addCodeBlocks; } export * from './parseMetaString.js'; export * from './metaOptions.js'; export * from './buildMetaAttributes.js';