74 lines
1.8 KiB
TypeScript
74 lines
1.8 KiB
TypeScript
import { visit } from 'unist-util-visit'
|
|
import { Node } from 'unist'
|
|
|
|
interface LinkNode extends Node {
|
|
type: 'link'
|
|
url: string
|
|
children: Node[]
|
|
}
|
|
|
|
interface Options {
|
|
locale?: string
|
|
}
|
|
|
|
/**
|
|
* Detects internal blog post links:
|
|
* - Relative paths (no http/https)
|
|
* - Not absolute paths (doesn't start with /)
|
|
* - Ends with .md
|
|
*/
|
|
function isInternalBlogLink(url: string): boolean {
|
|
return (
|
|
!url.startsWith('http://') &&
|
|
!url.startsWith('https://') &&
|
|
!url.startsWith('/') &&
|
|
url.includes('.md')
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Transforms internal .md links to blog routes:
|
|
* - tech/article.md → /[locale]/blog/tech/article
|
|
* - article.md#section → /[locale]/blog/article#section
|
|
* - nested/path/post.md?ref=foo → /[locale]/blog/nested/path/post?ref=foo
|
|
*/
|
|
function transformToBlogPath(url: string, locale: string = 'en'): string {
|
|
// Split into path, hash, and query
|
|
const hashIndex = url.indexOf('#')
|
|
const queryIndex = url.indexOf('?')
|
|
|
|
let path = url
|
|
let hash = ''
|
|
let query = ''
|
|
|
|
if (hashIndex !== -1) {
|
|
path = url.substring(0, hashIndex)
|
|
hash = url.substring(hashIndex)
|
|
}
|
|
|
|
if (queryIndex !== -1 && queryIndex < (hashIndex === -1 ? url.length : hashIndex)) {
|
|
path = url.substring(0, queryIndex)
|
|
query = url.substring(queryIndex, hashIndex === -1 ? url.length : hashIndex)
|
|
}
|
|
|
|
// Remove .md extension
|
|
const cleanPath = path.replace(/\.md$/, '')
|
|
|
|
// Build final URL with locale prefix
|
|
return `/${locale}/blog/${cleanPath}${query}${hash}`
|
|
}
|
|
|
|
export function remarkInternalLinks(options: Options = {}) {
|
|
const locale = options.locale || 'en'
|
|
|
|
return (tree: Node) => {
|
|
visit(tree, 'link', (node: Node) => {
|
|
const linkNode = node as LinkNode
|
|
|
|
if (isInternalBlogLink(linkNode.url)) {
|
|
linkNode.url = transformToBlogPath(linkNode.url, locale)
|
|
}
|
|
})
|
|
}
|
|
}
|