starlight-action

A GitHub Action that builds a Starlight documentation site from a folder of Markdown files. Zero config required - point it at your docs/ directory and get a deployed site with auto-generated sidebar, frontmatter injection, and README landing page support.

Overview

  • Language: TypeScript
  • Repo: peteretelej/starlight-action
  • Install: uses: peteretelej/starlight-action@v1 (in GitHub Actions workflow)
  • Status: Stable (v1.0)

Architecture

The action runs as a single Node.js entry point (src/index.ts) compiled with @vercel/ncc into dist/index.js. It executes an 8-step pipeline:

  1. scaffold.ts - Creates a temporary Astro/Starlight project in os.tmpdir(). Writes a package.json with pinned Astro (^5.0.0) and Starlight (~0.34.0) versions, runs npm install, creates src/content/docs/ and public/ directories, and writes the Astro 5 content collection definition (content.config.ts). Optionally includes a theme package.

  2. copy-docs.ts - Recursively copies all Markdown files and assets from the user’s docs directory into src/content/docs/. Optionally copies README.md as the index page and a logo file to public/.

  3. copy-css.ts - Parses comma-separated CSS file paths from the custom_css input, validates extensions and existence, copies files into src/styles/, and handles duplicate basenames by prefixing with the parent directory name.

  4. frontmatter.ts - Walks every .md file in the copied docs. If a file lacks a title in its frontmatter, injects one derived from (in priority order): the first # heading, or the filename converted to title case. Handles files with existing frontmatter but no title, and files with no frontmatter at all.

  5. readme-links.ts - When readme: true, rewrites relative links in the README that point into the docs folder. Uses remark’s AST (unified/remark-parse/remark-stringify/unist-util-visit) to transform Markdown links into site-relative URLs, image references into relative paths, and HTML src/poster attributes in video/img tags.

  6. sidebar.ts - Generates the Starlight sidebar configuration from the directory tree. Reads frontmatter order fields for sorting, extracts title fields for labels, converts folder names to title-case labels, and builds a recursive sidebar structure. Items with explicit order sort first (ascending), then alphabetically.

  7. config.ts - Generates astro.config.mjs. Builds the Starlight config object with title, description, sidebar, logo, GitHub social link, and custom CSS. Supports deep-merging a user-provided JSON config file. Handles theme plugin imports (named or default exports) with optional theme options.

  8. build.ts - Runs npx astro build, verifies dist/ exists, creates an uncompressed tar archive matching the actions/upload-pages-artifact format, and uploads it via @actions/artifact.

cache.ts - npm cache management using @actions/cache. Keys the cache by a SHA-256 hash of the generated package.json, so cache hits occur when the Astro/Starlight version pins haven’t changed.

Key Design Decisions

Zero-config by default, escape hatches for everything: The action works with just a docs folder path. But it also exposes config (JSON merge), custom_css (comma-separated paths), theme/theme_plugin/theme_options (npm theme packages), and base (path override) for full control.

Scaffold-from-scratch approach: Instead of maintaining a template repo or using create astro, the action generates a fresh project at runtime. This avoids version drift between the action and its template, and means updates to Astro/Starlight versions are a one-line change in scaffold.ts.

Remark AST for link rewriting: README links are rewritten using remark’s AST rather than regex. This correctly handles edge cases like links inside code blocks, nested formatting, and HTML video tags with src/poster attributes.

Sidebar from filesystem: The sidebar is generated by walking the docs directory tree rather than requiring manual configuration. Frontmatter order fields provide explicit ordering, but the default alphabetical sort means new pages appear in the sidebar automatically.

GitHub Pages artifact format: The build output is packaged as an uncompressed tar matching what actions/upload-pages-artifact produces, so it works directly with actions/deploy-pages without needing a separate upload step.

Development

npm install
npm run build          # ncc build src/index.ts -o dist
npm test               # vitest
npm run check          # tsc --noEmit
npm run test:e2e       # local end-to-end test via scripts/local-e2e.ts