diff --git a/.circleci/config.yml b/.circleci/config.yml index c24acc6c63..df36b0304f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -81,6 +81,17 @@ jobs: name: Validate llms.txt command: yarn validate-llms-txt + validate-markdown: + executor: + name: default + steps: + - checkout + - attach_workspace: + at: . + - run: + name: Validate markdown files + command: yarn validate-markdown + test-nginx: docker: - image: heroku/heroku:24-build @@ -155,3 +166,6 @@ workflows: - validate-llms-txt: requires: - build + - validate-markdown: + requires: + - build diff --git a/README.md b/README.md index 0cb8da6992..49e93b19a6 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,41 @@ To run the docs site locally, run `bin/dev` from the root directory. Alternative View the [contribution guide](CONTRIBUTING.md) for information on how to write content and contribute to Ably docs. +## Markdown Static Files + +The build process generates both HTML and Markdown versions of each documentation page. This provides a more token-efficient format for LLM crawlers and API clients. + +### Content Negotiation + +The site supports content negotiation via the `Accept` header: + +```bash +# Request markdown version +curl -H "Accept: text/markdown" https://ably.com/docs/channels + +# Request HTML version (default) +curl https://ably.com/docs/channels +``` + +Markdown files are located at `/docs/{page-path}/index.md` alongside their HTML counterparts at `/docs/{page-path}/index.html`. + +### Build Process + +1. **Source**: Content is written in Textile or MDX format +2. **HTML Generation**: Gatsby converts source files to static HTML +3. **Markdown Generation**: The `generateMarkdown` post-build hook converts HTML to clean Markdown +4. **Compression**: Both HTML and Markdown files are gzip compressed + +### Validation + +Validate markdown generation after building: + +```bash +yarn validate-markdown +``` + +This ensures all HTML pages have corresponding Markdown files and reports any issues. + ## Support If you have any questions or suggestions, please [raise an issue](https://github.com/ably/docs/issues). diff --git a/bin/validate-markdown.ts b/bin/validate-markdown.ts new file mode 100755 index 0000000000..3e5ef75262 --- /dev/null +++ b/bin/validate-markdown.ts @@ -0,0 +1,119 @@ +#!/usr/bin/env node + +/** + * Validates that markdown files exist for all HTML pages in the public directory. + * This script ensures the markdown generation process completed successfully. + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import fastGlob from 'fast-glob'; + +const publicDir = path.join(process.cwd(), 'public', 'docs'); + +// Constants for content validation (must match generateMarkdown.ts) +const REDIRECT_PAGE_MAX_SIZE = 1000; // Maximum size in bytes for redirect pages + +interface ValidationResult { + totalPages: number; + markdownFound: number; + markdownMissing: number; + redirectPages: number; + missingFiles: string[]; +} + +const validateMarkdownFiles = async (): Promise => { + // Find all index.html files in the docs directory + const htmlFiles = await fastGlob('**/index.html', { + cwd: publicDir, + absolute: false, + }); + + const result: ValidationResult = { + totalPages: htmlFiles.length, + markdownFound: 0, + markdownMissing: 0, + redirectPages: 0, + missingFiles: [], + }; + + for (const htmlFile of htmlFiles) { + // Get the directory of the HTML file + const dir = path.dirname(htmlFile); + + // Check if this is a redirect page (skip validation for these) + const htmlPath = path.join(publicDir, htmlFile); + const htmlContent = fs.readFileSync(htmlPath, 'utf8'); + + if (htmlContent.length < REDIRECT_PAGE_MAX_SIZE && /