151 lines
5.2 KiB
Shell
Executable file
151 lines
5.2 KiB
Shell
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Build the combined V1 + V2 documentation site (VitePress).
|
|
#
|
|
# V2 (from the current checkout, sources in docs/) is placed under /v2/.
|
|
# V1 (content from the v1.x branch, VitePress shell in docs/v1/) is placed at the root.
|
|
#
|
|
# Usage:
|
|
# scripts/build-docs-site.sh [output-dir]
|
|
#
|
|
# Default output directory: tmp/docs-combined
|
|
#
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
OUTPUT_DIR="$(cd "$REPO_ROOT" && realpath -m "${1:-tmp/docs-combined}")"
|
|
V1_WORKTREE="$REPO_ROOT/.worktrees/v1-docs"
|
|
V1_CONTENT="$REPO_ROOT/docs/v1/content"
|
|
V1_GITHUB="https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x"
|
|
|
|
cleanup() {
|
|
echo "Cleaning up worktree..."
|
|
cd "$REPO_ROOT"
|
|
git worktree remove --force "$V1_WORKTREE" 2>/dev/null || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
rm -rf "$OUTPUT_DIR"
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 1: Build V2 site from the current checkout
|
|
# ---------------------------------------------------------------------------
|
|
echo "=== Building V2 site ==="
|
|
|
|
cd "$REPO_ROOT"
|
|
pnpm install
|
|
pnpm -r --filter='./packages/**' build
|
|
pnpm docs:build
|
|
|
|
mkdir -p "$OUTPUT_DIR/v2"
|
|
cp -r "$REPO_ROOT/docs/.vitepress/dist/." "$OUTPUT_DIR/v2/"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 2: Build V1 site from the v1.x branch
|
|
# ---------------------------------------------------------------------------
|
|
echo "=== Building V1 site ==="
|
|
|
|
git fetch origin v1.x
|
|
|
|
git worktree remove --force "$V1_WORKTREE" 2>/dev/null || true
|
|
rm -rf "$V1_WORKTREE"
|
|
# FETCH_HEAD (set by the fetch above) rather than origin/v1.x: the remote-tracking ref
|
|
# does not exist in single-branch or refspec-restricted clones.
|
|
git worktree add "$V1_WORKTREE" FETCH_HEAD --detach
|
|
|
|
cd "$V1_WORKTREE"
|
|
npm install
|
|
npm install --no-save typedoc@^0.28.14 typedoc-plugin-markdown@^4.9.0 typedoc-vitepress-theme@^1.1.0
|
|
|
|
rm -rf "$V1_CONTENT"
|
|
mkdir -p "$V1_CONTENT"
|
|
|
|
# Same entry points as the previous typedoc HTML setup for v1, but rendered to
|
|
# markdown (one page per module) for the VitePress shell in docs/v1/.
|
|
cat > typedoc.v1-site.json << TYPEDOC_EOF
|
|
{
|
|
"name": "MCP TypeScript SDK",
|
|
"entryPoints": [
|
|
"src/client/index.ts",
|
|
"src/server/index.ts",
|
|
"src/shared/protocol.ts",
|
|
"src/shared/transport.ts",
|
|
"src/types.ts",
|
|
"src/inMemory.ts",
|
|
"src/validation/index.ts",
|
|
"src/experimental/index.ts"
|
|
],
|
|
"tsconfig": "tsconfig.json",
|
|
"plugin": ["typedoc-plugin-markdown", "typedoc-vitepress-theme"],
|
|
"outputFileStrategy": "modules",
|
|
"readme": "none",
|
|
"docsRoot": "$V1_CONTENT",
|
|
"out": "$V1_CONTENT/api",
|
|
"exclude": [
|
|
"**/*.test.ts",
|
|
"**/__fixtures__/**",
|
|
"**/__mocks__/**",
|
|
"src/examples/**"
|
|
],
|
|
"skipErrorChecking": true
|
|
}
|
|
TYPEDOC_EOF
|
|
|
|
npx typedoc --options typedoc.v1-site.json
|
|
|
|
# Copy the v1 markdown content (build copy only — the v1.x branch stays untouched).
|
|
cp docs/*.md "$V1_CONTENT/"
|
|
cp README.md "$V1_CONTENT/index.md"
|
|
|
|
# The v1 site serves the shared favicon at its own root (see docs/v1/.vitepress/config.mts).
|
|
mkdir -p "$V1_CONTENT/public"
|
|
cp "$REPO_ROOT/docs/public/favicon.svg" "$V1_CONTENT/public/favicon.svg"
|
|
|
|
# Rewrite links that don't resolve on the site:
|
|
# - source files -> GitHub
|
|
# - README links into docs/ -> site-local pages (docs/*.md sit next to index.md in content/)
|
|
sed -i "s|(src/examples/|(${V1_GITHUB}/src/examples/|g" "$V1_CONTENT/index.md"
|
|
sed -i "s|(LICENSE)|(${V1_GITHUB}/LICENSE)|g" "$V1_CONTENT/index.md"
|
|
sed -i "s|(docs/|(./|g" "$V1_CONTENT/index.md"
|
|
sed -i "s|(\.\./src/examples/|(${V1_GITHUB}/src/examples/|g" "$V1_CONTENT"/*.md
|
|
|
|
# Mechanical {@linkcode} -> backticks transform, mirroring the v2 docs transform.
|
|
# (The v1 docs currently contain none; this keeps the build robust if tags appear.)
|
|
node -e '
|
|
const fs = require("fs");
|
|
for (const f of process.argv.slice(1)) {
|
|
const src = fs.readFileSync(f, "utf8");
|
|
const out = src.replace(/\{@linkcode\s+([^}|]+?)(?:\s*\|\s*([^}]+?))?\s*\}/gs, (_m, path, label) =>
|
|
"`" + (label !== undefined ? label.replace(/\s+/g, " ").trim() : path.replace(/\s+/g, " ").trim().split(/[.#!/]/).pop()) + "`"
|
|
);
|
|
if (out !== src) fs.writeFileSync(f, out);
|
|
}
|
|
' "$V1_CONTENT"/*.md
|
|
|
|
# The v1.x guide pages start at "##" — the old typedoc shell supplied the page title,
|
|
# VitePress does not. Prepend a title heading (build copy only) so pages don't open
|
|
# with an orphaned section gap. index.md (the README) already has one.
|
|
for f in "$V1_CONTENT"/*.md; do
|
|
name="$(basename "$f" .md)"
|
|
[ "$name" = "index" ] && continue
|
|
head -n 1 "$f" | grep -q '^# ' && continue
|
|
case "$name" in
|
|
faq) title="FAQ" ;;
|
|
*) title="$(printf '%s' "${name:0:1}" | tr '[:lower:]' '[:upper:]')${name:1}" ;;
|
|
esac
|
|
if head -n 1 "$f" | grep -qi "^## *${title} *$"; then
|
|
# The page's first section heading already is the title — promote it.
|
|
sed -i '1s/^## */# /' "$f"
|
|
else
|
|
{ printf '# %s\n\n' "$title"; cat "$f"; } > "$f.tmp" && mv "$f.tmp" "$f"
|
|
fi
|
|
done
|
|
|
|
cd "$REPO_ROOT"
|
|
pnpm exec vitepress build docs/v1
|
|
|
|
cp -r "$REPO_ROOT/docs/v1/.vitepress/dist/." "$OUTPUT_DIR/"
|
|
|
|
echo "=== Combined docs generated at $OUTPUT_DIR ==="
|