90 lines
3.1 KiB
JavaScript
90 lines
3.1 KiB
JavaScript
/**
|
|
* Rehype plugin to prepend base path to absolute URLs
|
|
*
|
|
* Transforms:
|
|
* /img/foo.png → /BMAD-METHOD/img/foo.png (when base is /BMAD-METHOD/)
|
|
* /downloads/file.zip → /BMAD-METHOD/downloads/file.zip
|
|
* /llms.txt → /BMAD-METHOD/llms.txt
|
|
*
|
|
* Only affects absolute paths (/) - relative paths and external URLs are unchanged.
|
|
* Does NOT process .md links (those are handled by rehype-markdown-links).
|
|
*/
|
|
|
|
import { visit } from 'unist-util-visit';
|
|
|
|
/**
|
|
* Create a rehype plugin that prepends the base path to absolute URLs.
|
|
*
|
|
* @param {Object} options - Plugin options
|
|
* @param {string} options.base - The base path to prepend (e.g., '/BMAD-METHOD/')
|
|
* @returns {function} A HAST tree transformer
|
|
*/
|
|
export default function rehypeBasePaths(options = {}) {
|
|
const base = options.base || '/';
|
|
|
|
// Normalize base: ensure it ends with / and doesn't have double slashes
|
|
const normalizedBase = base === '/' ? '/' : base.endsWith('/') ? base : base + '/';
|
|
|
|
return (tree) => {
|
|
visit(tree, 'element', (node) => {
|
|
// Process img tags with src attribute
|
|
if (node.tagName === 'img' && node.properties?.src) {
|
|
const src = node.properties.src;
|
|
|
|
if (typeof src === 'string' && src.startsWith('/') && !src.startsWith('//')) {
|
|
// Don't transform if already has the base path
|
|
if (normalizedBase !== '/' && !src.startsWith(normalizedBase)) {
|
|
node.properties.src = normalizedBase + src.slice(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process iframe tags with src attribute
|
|
if (node.tagName === 'iframe' && node.properties?.src) {
|
|
const src = node.properties.src;
|
|
|
|
if (typeof src === 'string' && src.startsWith('/') && !src.startsWith('//')) {
|
|
// Don't transform if already has the base path
|
|
if (normalizedBase !== '/' && !src.startsWith(normalizedBase)) {
|
|
node.properties.src = normalizedBase + src.slice(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process anchor tags with href attribute
|
|
if (node.tagName === 'a' && node.properties?.href) {
|
|
const href = node.properties.href;
|
|
|
|
if (typeof href !== 'string') {
|
|
return;
|
|
}
|
|
|
|
// Only transform absolute paths starting with / (but not //)
|
|
if (!href.startsWith('/') || href.startsWith('//')) {
|
|
return;
|
|
}
|
|
|
|
// Skip if already has the base path
|
|
if (normalizedBase !== '/' && href.startsWith(normalizedBase)) {
|
|
return;
|
|
}
|
|
|
|
// Skip .md links - those are handled by rehype-markdown-links
|
|
// Extract path portion (before ? and #)
|
|
const firstDelimiter = Math.min(
|
|
href.indexOf('?') === -1 ? Infinity : href.indexOf('?'),
|
|
href.indexOf('#') === -1 ? Infinity : href.indexOf('#'),
|
|
);
|
|
const pathPortion = firstDelimiter === Infinity ? href : href.substring(0, firstDelimiter);
|
|
|
|
if (pathPortion.endsWith('.md')) {
|
|
return; // Let rehype-markdown-links handle this
|
|
}
|
|
|
|
// Prepend base path
|
|
node.properties.href = normalizedBase + href.slice(1);
|
|
}
|
|
});
|
|
};
|
|
}
|