# Diplodoc Platform — Documentation Reference Diplodoc is an open-source "Documentation as Code" platform for building, managing, and publishing technical documentation. It processes **Yandex Flavored Markdown (YFM)** — a CommonMark superset with extended elements including callouts, cuts, tabs, variables, conditional operators, and content reuse — and compiles it into static HTML sites. The platform supports multilingual projects, single-source publishing, OpenAPI integration, plugin extensions, and deployment to S3 or GitHub Pages. It is designed around the `@diplodoc/cli` npm package (`yfm` CLI command) and a YAML-driven project configuration system. Core functionality centers on the `yfm build` command which reads a project directory containing a `.yfm` config, a `toc.yaml` table of contents, markdown content files, and optional `presets.yaml` variable files — then outputs a ready-to-serve static HTML site. The platform's extension system (Extensions API) allows hook-based customization of every build stage via TypeScript, and the includer subsystem enables automatic documentation generation from OpenAPI specs, tarballs, or any external markdown-producing tool. Variables, conditional operators, and preset files support single-source multi-audience builds from one content repository. --- ## CLI Installation and Initial Setup Install the `@diplodoc/cli` package globally via npm. The `yfm` command is the primary interface for all build, publish, and lint operations. ```bash # Install globally (requires Node.js v22+) npm i @diplodoc/cli -g # Initialize a new project interactively yfm init # Minimal project structure created manually doc-folder/ ├── .yfm # Project configuration (YAML) ├── toc.yaml # Table of contents definition ├── presets.yaml # Variable presets (optional) └── index.yaml # Leading (landing) page ``` --- ## `yfm build` — Build Documentation to HTML Compile a documentation project from a source directory to static HTML. The `--input` and `--output` flags are required; all other settings can come from the `.yfm` config file. ```bash # Basic build: source → HTML output yfm build -i ./docs -o ./docs-html # Short form (input defaults to current directory) yfm -o ./docs-html # Build with variable preset selection yfm build -i ./docs -o ./docs-html --varsPreset external # Strict mode: treat warnings as errors yfm build -i ./docs -o ./docs-html --strict # Build to YFM intermediate format (for single-source branching) yfm build -i ./docs -o ./docs-md --output-format=md --apply-presets # Single-page build (all pages merged into one HTML file) yfm build -i ./docs -o ./docs-html --singlePage # Watch mode: incremental rebuild + browser live-reload yfm build -i ./docs -o ./docs-html --watch # Remove hidden TOC items from output yfm build -i ./docs -o ./docs-html --remove-hidden-toc-items # View all available flags yfm build --help ``` --- ## `.yfm` — Project Configuration File The `.yfm` file at the project root (YAML format) controls all build and viewer settings. Pass a custom path with `--config`. ```yaml # .yfm — complete example configuration allowHtml: true # Allow raw HTML in markdown (required for OpenAPI includer) langs: ['en', 'ru'] # Supported languages for multilingual projects breaks: true # Carriage return = line break (set false for two-space breaks) linkify: true # Auto-convert URL strings to links conditionsInCode: false # Do not evaluate {% if %} inside code blocks disableLiquid: false # Keep variable substitution enabled supportGithubAnchors: true # Also generate GitHub-compatible header anchors lang: en # Default locale for UI text needToSanitizeHtml: true # Sanitize generated HTML disableCsp: false # Inject CSP meta tags vars: # Inline variable definitions version: '2.0' product: MyApp search: provider: local # Built-in lunr.js search analytics: gtm: id: GTM-XXXXXXX mode: notification # Show cookie consent before sending events resources: style: - _assets/style/custom.css extensions: - name: mdit-plugins plugins: - '@diplodoc/transform/lib/plugins/checkbox' - github-vcs preprocess: mergeIncludes: true # S3 publish settings (used with --publish flag) storageEndpoint: https://storage.example.com storageBucket: my-docs-bucket storageKeyId: KEY_ID # or set YFM_STORAGE_KEY_ID env var storageSecretKey: SECRET # or set YFM_STORAGE_SECRET_KEY env var storagePrefix: v2.0 # Optional: organizes builds into versioned folders ``` --- ## `toc.yaml` — Table of Contents Defines the documentation structure and navigation hierarchy. Only files referenced in `toc.yaml` are included in the build. ```yaml # toc.yaml — complete structure example title: "{{ product }} Documentation" # Supports variable substitution href: index.yaml items: - name: Getting Started href: quickstart.md - name: Reference expanded: true # Section open by default (first-level only) items: - name: API Overview href: api/index.md - name: Configuration href: config.md when: version >= 2 # Conditional visibility based on variable - name: Secret Internals href: internal.md hidden: true # Accessible by direct URL only # Include another toc.yaml as a subsection - name: SDK Reference include: path: sdk/toc.yaml # path relative to doc root by default # Merge another toc.yaml at the same level (no wrapper section) - include: { path: changelog/toc.yaml } # Include with relative path using merge mode - include: { mode: merge, path: ../shared/toc.yaml } # Include with link mode: structure unchanged, links rewritten - name: Shared Guides include: path: shared/guides mode: link ``` --- ## `presets.yaml` — Variable Presets Define groups of variables to produce multiple documentation variants from a single source. Pass the preset name at build time with `--varsPreset`. ```yaml # presets.yaml default: product: MyApp version: '2.0' users: - Alice - Bob internal: audience: internal show_internal: true external: audience: external show_internal: false ``` ```bash # Build for external audience yfm build -i ./docs -o ./out --varsPreset external # Build for internal audience yfm build -i ./docs -o ./out --varsPreset internal # Override individual variables inline yfm build -i ./docs -o ./out --vars '{"version":"3.0"}' ``` --- ## `index.yaml` — Leading (Landing) Page Create a grid-style landing page linking to major documentation sections. Supports variable substitution and conditional visibility. ```yaml # index.yaml title: "{{ product }} Docs" description: "Full documentation for {{ product }} version {{ version }}." meta: title: "{{ product }} – Official Docs" noIndex: false links: - title: Getting Started description: Install and run your first build. href: quickstart.md - title: Configuration Reference description: All .yfm options documented. href: config.md - title: Internal Guide description: For internal teams only. href: internal.md when: audience == 'internal' # Hidden when building external preset - title: "{% if version >= '2.0' %}New API{% else %}Legacy API{% endif %}" description: "{{ link_description }}" href: api/index.md ``` --- ## YFM Syntax — Basic Markup Yandex Flavored Markdown extends CommonMark with superscript, monospace inline, and configurable anchor IDs on headers. ```markdown **Bold text** _Italic_ **_Bold italic_** ~~Strikethrough~~ Super^script^ ##Monospaced## # Page Title (h1) ## Section (h2) {#custom-anchor} ### Subsection (h3) #### Detail (h4) > Blockquote >> Nested blockquote Super\^not-a-script^ Red text ``` --- ## YFM Syntax — Notes (Callouts) Highlight important content with typed callout blocks. All four types support optional custom headers. ```markdown {% note info %} This is an informational note. {% endnote %} {% note tip %} This is a helpful tip. {% endnote %} {% note warning %} This is a warning — pay attention. {% endnote %} {% note alert %} This is a critical alert. {% endnote %} {% note info "Custom Header" %} A note with a custom title instead of the default. {% endnote %} {% note info "" %} A note with no header at all. {% endnote %} ``` --- ## YFM Syntax — Cuts (Collapsible Sections) and Tabs Interactive elements for hiding optional content and organizing mutually-exclusive instructions. ```markdown {% cut "Show advanced options" %} Any YFM content here — tables, code blocks, images... ```yaml advanced: option: value ``` {% endcut %} {% list tabs group=os %} - macOS ```bash brew install my-tool ``` - Linux ```bash sudo apt-get install my-tool ``` - Windows ```powershell choco install my-tool ``` {% endlist %} {% list tabs group=os %} - macOS Run: `my-tool start` - Linux Run: `sudo my-tool start` - Windows Run: `my-tool.exe start` {% endlist %} ``` --- ## YFM Syntax — Variables and Conditional Operators Use template variables for substitution, conditional content inclusion, loops, and string filters. Variables come from `.yfm`, `presets.yaml`, or the `--vars` flag. ```markdown Welcome to {{ product }} version {{ version }}! Use not_var{{ literal_braces }} in your template. {% if OS == 'iOS' %} Download from the [App Store](https://apple.com/app-store/). {% elsif OS == 'Android' %} Download from [Google Play](https://play.google.com). {% else %} Download from our [website](https://example.com/download). {% endif %} Tap {% if OS == 'iOS' %}Settings{% else %}Preferences{% endif %} to continue. {% for user in users %} - Hello, {{ user }}! {% endfor %} Hello, {{ user.name | capitalize }}! Total users: {{ users | length }} Hello P{{ user.name.slice(1) }}! ``` ```yaml # presets.yaml providing the above variables default: product: MyApp version: '2.0' OS: iOS user: name: masha users: - Alice - Bob ``` --- ## YFM Syntax — Content Reuse with `{% include %}` Extract repeated content into shared files stored in `_`-prefixed directories, then include them anywhere. ```markdown {% include [Note about authentication](_includes/auth-note.md) %} {% include notitle [Auth note](_includes/auth-note.md) %} {% include [Part 2 only](reference.md#part2) %} ``` ```markdown ## Authentication Requirements {#auth} All API calls require a valid Bearer token in the `Authorization` header. ## Rate Limits {#limits} Requests are limited to 1000/hour per API key. ``` ```markdown {% include [Auth requirements](_includes/auth-note.md#auth) %} ``` --- ## YFM Syntax — Links, Media, and Code Standard linking, image embedding with size control, file download links, and syntax-highlighted code blocks. ```markdown [Visit Diplodoc](https://diplodoc.com "Official site") [{#T}](./api/index.md) [See configuration options](config.md#settings) My favorite tool is [Diplodoc][1]. [1]: https://diplodoc.com "Diplodoc Platform" ![Architecture diagram](_images/arch.png "System architecture"){width=800} [![Logo](_images/logo.png "Go home"){width=120}](https://diplodoc.com) {% file src="data:text/plain;base64,SGVsbG8=" name="hello.txt" %} ```typescript showLineNumbers import { Build } from '@diplodoc/cli'; const ext = new MyExtension(); ext.apply(program); ``` Run `yfm build -i ./docs -o ./out` to compile. ``` --- ## YFM Syntax — Page Metadata and Comments Add YAML front matter for SEO metadata and non-rendering author comments. ```markdown --- title: API Reference description: Complete reference for the MyApp REST API. --- [//]: # (TODO: add authentication examples before launch) # API Reference Content starts here... ``` --- ## Includers — Auto-generated Documentation Includers connect external content sources into the documentation build via `toc.yaml`. They run as a pipeline and can be chained. ```yaml # toc.yaml — chain of includers: unarchive tarball then render with generic includer title: Documentation href: index.yaml items: # Generic includer: import any pre-generated markdown directory - name: SDK Docs include: path: sdk-docs includers: - name: generic input: generated/sdk # path to markdown files autotitle: true # use file headings as nav labels linkIndex: true # make index.md the clickable section href mode: link # OpenAPI includer: generate API reference from OpenAPI 3.x spec - name: REST API include: path: api-reference includers: - name: openapi input: openapi.yaml # OpenAPI 3.x spec file mode: link # Unarchive → generic pipeline: unpack tarball then render - name: External Docs include: path: external mode: link includers: - name: unarchive input: docs.tar # tarball with markdown content output: unpacked # temp directory for extracted files - name: generic input: unpacked # use unarchive's output as input ``` ```yaml # index.yaml — link to includer-generated sections title: Documentation links: - title: SDK Docs href: sdk-docs/ - title: REST API href: api-reference/ - title: External Docs href: external/ ``` --- ## OpenAPI Includer — Advanced Configuration Fine-tune how OpenAPI specs are rendered: customize tag names, filter endpoints, control sandbox tabs, and manage search indexing. ```yaml # toc.yaml — full OpenAPI includer configuration title: API Docs href: index.yaml items: - name: API Reference include: path: api mode: link includers: - name: openapi input: openapi.yaml # OpenAPI-specific options (set alongside include) tags: __root__: name: All Endpoints # rename the top-level TOC entry alias: endpoints # rewrite URL slug authentication: name: Auth alias: auth hidden: false internal: hidden: true # hide this tag from navigation leadingPage: name: API Overview spec: renderMode: inline # include raw spec on leading page (or: hidden) sandbox: tabName: Try It host: 'https://api.example.com' # base URL for sandbox requests filter: endpoint: tags contains "nobuild" != true # exclude draft endpoints noindex: tag: name == "noindex" # prevent search indexing for tagged sections ``` ```yaml # openapi.yaml — hide a field using x-hidden extension paths: /users: get: parameters: - name: internal_id in: query schema: type: string x-hidden: true # this parameter won't appear in the rendered docs ``` --- ## S3 Publishing Publish built documentation directly to S3-compatible object storage using the `--publish` flag. ```bash # Publish using environment variables for credentials export YFM_STORAGE_KEY_ID=AKIAIOSFODNN7EXAMPLE export YFM_STORAGE_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY yfm build -i ./docs -o ./out --publish \ --storageEndpoint https://storage.yandexcloud.net \ --storageBucket my-docs-bucket \ --storagePrefix v2.0 ``` ```yaml # .yfm — equivalent S3 config (credentials via env vars) storageEndpoint: https://storage.yandexcloud.net storageBucket: my-docs-bucket storagePrefix: v2.0 # each build version in its own folder ``` --- ## GitHub Actions — Automated Builds Integrate Diplodoc builds into CI/CD using the official GitHub Actions. ```yaml # .github/workflows/docs.yml — build and deploy to GitHub Pages name: Build and Deploy Docs on: push: branches: [main] paths: ['docs/**'] push: tags: ['v*.*.*'] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/configure-pages@v5 # Build docs using the official action - name: Build docs uses: diplodoc-platform/docs-build-static-action@v1 with: src-root: './docs' build-root: './docs-html' - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: './docs-html' - name: Deploy to GitHub Pages uses: actions/deploy-pages@v4 # Versioned release to S3 release: runs-on: ubuntu-latest steps: - name: Release versioned docs uses: diplodoc-platform/docs-release-action@v2 with: revision: "${{ github.sha }}" version: "${{ github.ref_name }}" storage-bucket: ${{ secrets.DIPLODOC_STORAGE_BUCKET }} storage-access-key-id: ${{ secrets.DIPLODOC_ACCESS_KEY_ID }} storage-secret-access-key: ${{ secrets.DIPLODOC_SECRET_ACCESS_KEY }} ``` --- ## Extensions API — Hook-based CLI Customization Extend the Diplodoc build pipeline using TypeScript extensions. Extensions tap into hooks exposed by `Program` (CLI setup) and `Run` (build execution) context objects. ```typescript // my-extension/index.ts import { Build } from '@diplodoc/cli'; import { Option } from 'commander'; import { getBaseHooks, getTocHooks, getMarkdownHooks, getLeadingHooks, getMetaHooks, } from '@diplodoc/cli/hooks'; export class MyExtension { apply(program: Build) { // 1. Command Extension: add a custom CLI flag getBaseHooks(program).Command.tap('MyExtension', (command) => { command.addOption(new Option('--my-flag ', 'Custom flag')); }); // 2. Processing Extension: hook into build execution getBaseHooks(program).BeforeAnyRun.tap('MyExtension', (run) => { const tocHooks = getTocHooks(run.toc); const markdownHooks = getMarkdownHooks(run.markdown); const leadingHooks = getLeadingHooks(run.leading); const metaHooks = getMetaHooks(run.meta); // Modify every TOC item during resolution tocHooks.Item.tapPromise('MyExtension', async (item) => { if (item.name) { item.name = `[DRAFT] ${item.name}`; } return item; }); // Transform markdown content before rendering markdownHooks.Resolved.tapPromise('MyExtension', async (content) => { return content.replace(/TODO:/g, '⚠️ TODO:'); }); // Enrich leading page data from an external API leadingHooks.Resolved.tapPromise('MyExtension', async (page) => { const extra = await fetchExternalMetadata(); return { ...page, ...extra }; }); }); // 3. Cleanup after each run getBaseHooks(program).AfterAnyRun.tap('MyExtension', (run) => { console.log('Build complete:', run.output); }); } } ``` ```yaml # .yfm — register the extension extensions: - name: my-extension path: ./my-extension/index.ts ``` --- ## Summary Diplodoc serves two primary use cases: **standalone technical documentation sites** for software products and APIs, and **enterprise documentation platforms** that consolidate multiple teams' docs under one roof. In the standalone case, teams write content in YFM markdown, define their `toc.yaml` navigation, and run `yfm build` locally or in CI to produce a static HTML site ready for GitHub Pages, S3, or any web server. The variable and preset system means the same source repository can produce separate internal and external builds, user-tier builds, or multi-language editions — without duplicating a single content file. The built-in OpenAPI includer makes Diplodoc a natural fit for teams wanting hand-written prose alongside auto-generated REST API reference pages. For integration, Diplodoc fits into any Node.js-capable CI/CD pipeline. The official `diplodoc-platform/docs-build-static-action` and `docs-release-action` GitHub Actions handle build and versioned S3 publish in a few YAML lines. The Extensions API exposes a TypeScript hook system modeled after webpack's tapable library, enabling teams to write reusable build plugins that add CLI flags, transform content, integrate external data sources, or customize the VCS, search, and metadata services. The `@diplodoc/cli` package is the single install target; the `.yfm` config file wires together extensions, analytics (GTM, Yandex Metrika), CSP rules, search providers (local lunr.js or Algolia), and custom CSS — making the entire documentation infrastructure reproducible from a single version-controlled configuration.