Files
supabase/apps/www/lib/toc.ts
Francesco Sansalvadore 2feda5ee19 cms www blog (#38045)
* show cms blog posts in www
* remove contentlayer from www
* outputFileTracingExcludes
* update remotePatterns
* fetch cms posts server-side with revalidation
* add cms env vars to turbo.json
* add www env vars to turbo.json
* include cms posts in www sitemap
* add migration to remove image from cms post
* update cms meta image mapping in www
2025-09-03 14:49:28 +02:00

41 lines
1.1 KiB
TypeScript

type TocItem = { content: string; slug: string; lvl: number }
function stripFencedCodeBlocks(markdown: string): string {
const segments = markdown.split('```')
let acc = ''
for (let i = 0; i < segments.length; i++) {
if (i % 2 === 0) acc += segments[i]
}
return acc
}
function slugify(input: string): string {
return input
.trim()
.toLowerCase()
.replace(/[`~!@#$%^&*()+=|{}\[\]\\:\";'<>?,./]+/g, '')
.replace(/\s+/g, '-')
}
export async function generateTocFromMarkdown(markdown: string, maxDepth: number) {
const noCode = stripFencedCodeBlocks(markdown)
const lines = noCode.split(/\r?\n/)
const items: TocItem[] = []
for (const line of lines) {
const m = /^(#{1,6})\s+(.*)$/.exec(line)
if (!m) continue
const depth = m[1].length
if (depth > maxDepth) continue
const text = m[2].trim()
if (!text) continue
items.push({ content: text, slug: slugify(text), lvl: depth })
}
const content = items
.map((h) => `${' '.repeat(Math.max(0, h.lvl - 1))}- [${h.content}](#${h.slug})`)
.join('\n')
return { content, json: items }
}