@mintlify/common
Version:
Commonly shared code within Mintlify
49 lines (48 loc) • 2.02 kB
JavaScript
import { posix } from 'path';
import { visit } from 'unist-util-visit';
const isRelative = (url) => url.startsWith('./') || url.startsWith('../');
const resolveRelative = (baseDir, url) => {
// Preserve any fragment or query string verbatim.
const splitIndex = url.search(/[#?]/);
const pathPart = splitIndex === -1 ? url : url.slice(0, splitIndex);
const tail = splitIndex === -1 ? '' : url.slice(splitIndex);
const resolved = posix.normalize(posix.join(baseDir, pathPart));
const absolute = resolved.startsWith('/') && !resolved.startsWith('//') ? resolved : `/${resolved}`;
return absolute + tail;
};
const ATTR_BY_TAG = {
a: 'href',
Card: 'href',
img: 'src',
source: 'src',
};
export const remarkResolveRelativeLinks = (options = {}) => {
return (tree) => {
const { path } = options;
if (!path)
return;
const stripped = path.replace(/^\/+/, '').replace(/\.mdx?$/i, '');
const dir = posix.dirname(stripped);
const baseDir = dir === '.' || dir === '' ? '/' : `/${dir}`;
visit(tree, (node) => {
if (node.type === 'link' || node.type === 'image') {
const linkOrImg = node;
if (linkOrImg.url && isRelative(linkOrImg.url)) {
linkOrImg.url = resolveRelative(baseDir, linkOrImg.url);
}
return;
}
if (node.type !== 'mdxJsxFlowElement' && node.type !== 'mdxJsxTextElement') {
return;
}
const jsxNode = node;
const attrName = jsxNode.name ? ATTR_BY_TAG[jsxNode.name] : undefined;
if (!attrName)
return;
const attr = jsxNode.attributes.find((a) => a.type === 'mdxJsxAttribute' && a.name === attrName);
if (attr && 'value' in attr && typeof attr.value === 'string' && isRelative(attr.value)) {
attr.value = resolveRelative(baseDir, attr.value);
}
});
};
};