mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 09:59:03 +08:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Feature: agent-readable markdown pages for the UI library docs. ## What is the current behavior? Library docs are HTML-only. `llms.txt` lists page titles, but there is no `.md` body an agent can fetch. ## What is the new behavior? Each docs page is also served as markdown: - Build-time MDX → markdown (`pnpm --filter library build:markdown`) - `GET /library/docs/{slug}.md` (and `Accept: text/markdown`) - HTML pages advertise `rel=alternate` `text/markdown` - `llms.txt` links to the `.md` URLs This is the base of a stack. The prompt-tab PR sits on top: https://github.com/supabase/supabase/pull/49566 ## Additional context Interactive previews are omitted from the markdown. `BlockItem` emits the production `npx shadcn add` command so agents still get an install path. ## To test 1. `pnpm --filter library dev` (generates markdown in `predev`). 2. Open http://localhost:3004/library/docs/nextjs/password-based-auth.md — markdown with the install command, file tree, and setup steps; no interactive previews. 3. Open the same path without `.md` — HTML docs unchanged (no prompt tab in this PR). 4. `curl -H 'Accept: text/markdown' http://localhost:3004/library/docs/nextjs/password-based-auth` should also return markdown. 5. http://localhost:3004/library/llms.txt — links should end in `.md`. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Documentation pages are available as Markdown through `.md` URLs and a dedicated endpoint. * Markdown is generated automatically during development and production builds. * Generated content preserves front matter, links, callouts, installation instructions, and supported documentation elements. * Installation commands support npm, pnpm, yarn, and bun for React and Vue projects. * **Bug Fixes** * Improved Markdown file handling, link rewriting, and content negotiation. * **Tests** * Added coverage for Markdown conversion, content negotiation, and installation commands. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Saxon Fletcher <SaxonF@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
66 lines
2.1 KiB
TypeScript
66 lines
2.1 KiB
TypeScript
import fs from 'node:fs/promises'
|
|
import path from 'node:path'
|
|
|
|
import { transformLibraryMdx } from './library-mdx-to-markdown'
|
|
|
|
const CONTENT_DIR = path.join(process.cwd(), 'content', 'docs')
|
|
const OUTPUT_DIR = path.join(process.cwd(), 'public', 'markdown', 'docs')
|
|
const MANIFEST_PATH = path.join(process.cwd(), 'public', 'markdown', 'manifest.json')
|
|
|
|
async function collectMdxFiles(dir: string): Promise<string[]> {
|
|
const entries = await fs.readdir(dir, { withFileTypes: true })
|
|
const files: string[] = []
|
|
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name)
|
|
if (entry.isDirectory()) {
|
|
files.push(...(await collectMdxFiles(fullPath)))
|
|
} else if (entry.name.endsWith('.mdx')) {
|
|
files.push(fullPath)
|
|
}
|
|
}
|
|
|
|
return files.sort((a, b) => a.localeCompare(b))
|
|
}
|
|
|
|
async function generate() {
|
|
const sources = await collectMdxFiles(CONTENT_DIR)
|
|
const slugs: string[] = []
|
|
|
|
// Wipe first so pages that were renamed or deleted don't leave stale markdown
|
|
// behind — public/markdown is served directly, and the files outlive the manifest.
|
|
await fs.rm(OUTPUT_DIR, { recursive: true, force: true })
|
|
await fs.mkdir(OUTPUT_DIR, { recursive: true })
|
|
|
|
for (const sourceFile of sources) {
|
|
const relativePath = path.relative(CONTENT_DIR, sourceFile)
|
|
const slug = relativePath.replace(/\.mdx$/, '').replace(/\\/g, '/')
|
|
const outPath = path.join(OUTPUT_DIR, `${slug}.md`)
|
|
const raw = await fs.readFile(sourceFile, 'utf8')
|
|
|
|
let output: string
|
|
try {
|
|
output = transformLibraryMdx(raw)
|
|
} catch (err) {
|
|
throw new Error(
|
|
`Failed to process ${sourceFile}: ${err instanceof Error ? err.message : err}`,
|
|
{ cause: err }
|
|
)
|
|
}
|
|
|
|
await fs.mkdir(path.dirname(outPath), { recursive: true })
|
|
await fs.writeFile(outPath, output)
|
|
slugs.push(slug)
|
|
}
|
|
|
|
await fs.mkdir(path.dirname(MANIFEST_PATH), { recursive: true })
|
|
await fs.writeFile(MANIFEST_PATH, `${JSON.stringify(slugs, null, 2)}\n`)
|
|
|
|
console.log(`Generated ${slugs.length} markdown files under public/markdown/docs/`)
|
|
}
|
|
|
|
generate().catch((error) => {
|
|
console.error(error)
|
|
process.exit(1)
|
|
})
|