= Antora extensions reference
:toc:
:toclevels: 3

Reference documentation for all Antora extensions provided by this library.

IMPORTANT: Ensure you register each extension under the `antora.extensions` key in the playbook, not the `asciidoc.extensions` key.

== Add Bloblang samples to pages

The `collect-bloblang-samples` extension processes Bloblang examples from YAML files in the `examples` directory of the `redpanda-connect` component. This extension ensures that these examples are accessible as structured data for use in UI components or documentation, such as sample dropdowns in a Bloblang playground.

It validates, sorts, and attaches the processed examples as a JSON object to the Antora page attributes. The extension ensures examples have unique titles, mandatory fields (`input` and `mapping`), and are sorted in alphabetical order.

The processed examples are added as JSON to the `page-bloblang-samples` attribute. For example:

[,json]
----
{
  "hello-world.yaml": {
    "title": "Hello world",
    "input": "{\n  \"message\": \"hello world\"\n}\n",
    "mapping": "root.message = this.message.uppercase()\n"
  },
  "array-processing.yaml": {
    "title": "Array processing",
    "input": "{\n  \"numbers\": [1, 2, 3, 4, 5]\n}\n",
    "mapping": "root.even_numbers = this.numbers.filter(n -> n % 2 == 0)"
  }
}
----

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

To enable the extension, add it to your Antora playbook under the `antora.extensions` key. No additional configuration is required.

[,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/collect-bloblang-samples'
----

=== Example Bloblang YAML file

The following YAML file is an example of how to define a Bloblang sample:

[,yaml]
----
title: Hello world
input: |
  {
    "message": "hello world"
  }
mapping: |
  root.message = this.message.uppercase()
----

== Add pages to root

The `add-pages-to-root` extension allows you to copy files from your Antora content catalog to the root of the site during the build process. This is particularly useful for files like `llms.txt` or any custom files that need to be directly accessible at the site's root level.

This extension processes a list of file paths provided in the playbook configuration, locates those files in the Antora content catalog, and adds them to the site's root directory during the publishing phase. Each file's content and basename are preserved in the process.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

Add the `add-pages-to-root` extension to your Antora playbook under the `antora.extensions` key, and specify the list of files to process in the `files` configuration.

[source,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/add-pages-to-root'
      files:
        - home:ROOT:attachment$custom-file.txt
----

=== Registration

[source,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/add-pages-to-root'
      files:
        - home:ROOT:attachment$custom-file.txt
----

== Algolia indexer

This extension generates an Algolia index for each version of each component. The index entries are then saved to Algolia using the `saveObjects()` method, and also saved as JSON files in the site catalog. JSON files are published to the site root using the template `algolia-<component>-<version>.json`.

NOTE: Only pages that include an `<article>` element with the `doc` class are indexed.

=== Environment variables

- `ALGOLIA_ADMIN_API_KEY` (required)
- `ALGOLIA_APP_ID` (required)
- `ALGOLIA_INDEX_NAME` (required)

=== Configuration options

The extension accepts the following configuration options:

excludes (optional)::
Any elements, classes, or IDs that you want to exclude from the index.
index-latest-only (optional)::
Whether to index all versions or just the latest version of a component.

=== Registration

```yaml
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/algolia-indexer/index'
    excludes: ['.thumbs','script', '.page-versions','.feedback-section','.banner-container']
    index-latest-only: true
```

== Archive attachments

The `archive-attachments` extension automates the packaging of specific attachment files into a compressed archive (`.tar.gz`) based on configurable patterns. This archive is then made available to the generated site, allowing users to easily download grouped resources such as Docker Compose configurations.

This extension enables you to define which files and directories to include in the archive, ensuring that only relevant content is packaged and accessible.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

The extension accepts the following options in the Antora playbook.

Configure the extension in your Antora playbook by defining an array of archive configurations under `data.archives`. Each archive configuration includes:

output_archive (string, required):: The name of the generated archive file.

component (string, required):: The name of the Antora component whose attachments should be archived.

file_patterns (array of strings, required):: Glob patterns specifying which attachment paths to include in the archive.

NOTE: Ensure that `file_patterns` accurately reflect the paths of the attachments you want to archive. Overly broad patterns may include unintended files, while overly restrictive patterns might exclude necessary resources.

=== Example configuration

Here's an example configuration to enable the extension:

```yaml
antora:
  extensions:
    - require: '../docs-extensions-and-macros/extensions/archive-creation-extension.js'
      data:
        archives:
          - output_archive: 'redpanda-quickstart.tar.gz' <1>
            component: 'ROOT' <2>
            file_patterns:
              - '**/test-resources/**/docker-compose/**' <3>
```

<1> Defines the name of the generated archive placed at the site root.
<2> Defines the name of the component in which to search for attachments.
<3> Lists the glob patterns to match attachment paths for inclusion in the archive.
+
- `**`: Matches any number of directories.
- `/test-resources/`: Specifies that the matching should occur within the `test-resources/` directory.
- `/docker-compose/`: Targets the `docker-compose/` directory and all its subdirectories.
- `**:` Ensures that all files and nested directories within `docker-compose/` are included.

== Behavior with multiple components/versions

*Scenario*: Multiple components and/or multiple versions of the same component contain attachments that match the defined file_patterns.

*Outcome*: Separate archives for each component version.

For each matching (component, version) pair, the extension creates a distinct archive named `<version>-<output_archive>`. For example:
`24.3-redpanda-quickstart.tar.gz`.

These archives are placed at the site root, ensuring they are easily accessible and do not overwrite each other.

For the latest version of each component, the extension also adds the archive using the base `output_archive` name. As a result, the latest archives are accessible through a consistent filename, facilitating easy downloads without needing to reference version numbers.

Because each archive has a unique filename based on the component version, there is no risk of archives overwriting each other.
The only exception is the archive for the latest version, which consistently uses the `output_archive` name.

== Component category aggregator

This extension maps Redpanda Connect component data into a structured format:

- Maps original component names to common names.
- Populates `connectCategoriesData` and `flatComponentsData` attributes.
- Skips deprecated components.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

There are no configurable options for this extension.

=== Registration

```yaml
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/generate-rp-connect-categories'
```

== Compute end-of-life extension

This extension calculates and attaches metadata related to the end-of-life (EoL) status of docs pages, such as nearing EoL, past EoL, and associated EoL dates. This metadata can be used to display relevant banners or messages in docs to inform users about the lifecycle of each version.

The extension leverages configuration settings provided in the Antora playbook to apply EoL calculations, specify the warning period, and include links to upgrade documentation and EoL policies.

The extension computes whether a page is nearing EoL or past EoL based on the `page-release-date` attribute and configured settings.
It injects the following attributes into each page, making them available for use in UI templates:

- `page-is-nearing-eol`: Indicates if the page is within the warning period before EoL. Calculated using `(page-release-date + supported_months) - warning_weeks`.
- `page-is-past-eol`: Indicates if the page has passed its EoL. Calculated using `today > (page-release-date + supported_months)`.
- `page-eol-date`: The calculated EoL date in a human-readable format. Calculated using `page-release-date + supported_months`.
- `page-eol-doc`: The URL to the supported versions policy or EoL documentation.
- `page-upgrade-doc`: The Antora resource ID to a document containing upgrade instructions.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

To enable and configure the extension, add it to the `antora.extensions` section of your Antora playbook. Define the EoL settings under the `data.eol_settings` key with the following options:

`component` (required):: The component name to which the configuration applies.
`eol_doc` (required):: A link to the supported versions policy or EoL documentation.
`upgrade_doc` (required):: A link to the upgrade instructions.
`supported_months` (optional, default: 12):: The number of months after the publish date when the documentation reaches its EoL.
`warning_weeks` (optional, default: 6):: The number of weeks before EoL when the documentation is considered to be nearing EoL. Can be used to decide when to notify users of the upcoming EoL status.

[,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/compute-end-of-life'
      data:
        eol_settings:
          - component: 'ROOT'
            supported_months: 18
            warning_weeks: 8
            eol_doc: https://support.redpanda.com/hc/en-us/articles/20617574366743-Redpanda-Supported-Versions
            upgrade_doc: ROOT:upgrade:index.adoc
----

=== Registration

You can register the extension with a customized configuration for different components in your playbook:

[,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/compute-end-of-life'
      data:
        eol_settings:
          - component: 'ROOT'
            supported_months: 12
            warning_weeks: 6
            eol_doc: https://example.com/supported-versions
            upgrade_doc: ROOT:upgrade:index.adoc
          - component: 'example-docs'
            supported_months: 24
            warning_weeks: 12
            eol_doc: https://example.com/example-supported-versions
            upgrade_doc: example-docs:upgrade:index.adoc
----


=== Example Handlebars template:

[,handlebars]
----
{{#if page.attributes.is-nearing-eol}}
  <div class="banner-container nearing-eol">
    This documentation will reach its end of life on {{page.attributes.eol-date}}.
    Please <a href="{{resolve-resource page.attributes.upgrade-doc}}">upgrade to a supported version</a>.
  </div>
{{else if page.attributes.is-past-eol}}
  <div class="banner-container past-eol">
    This documentation reached its end of life on {{page.attributes.eol-date}}.
    See our <a href="{{page.attributes.eol-doc}}" target="_blank">supported versions policy</a>.
  </div>
{{/if}}
----

== Generate index data

The `generate-index-data` extension creates structured index data about doc pages based on configurable filters. The indexed data is saved to a specified attribute in all component versions, enabling the dynamic generation of categorized links and descriptions within your docs using UI templates.

This extension allows you to define multiple indexing criteria, such as component, URL filter, and environment type.

The generated data is an array of objects, where each object represents a component version. Each object contains the following properties:

- `component` (string):
  The name of the Antora component.

- `version` (string):
  The version of the component.

- `pages` (array):
  A list of pages that match the indexing criteria. Each page contains:
** `title` (string): The title of the doc page.
** `url` (string): The URL of the doc page relative to the site root.
** `description` (string): A brief description sourced from the `:description:` attribute in the AsciiDoc file. Defaults to an empty string if not provided.

Example:

```json
[
  {
    "component": "ROOT",
    "version": "24.3",
    "pages": [
      {
        "title": "Manage Debug Bundles in Redpanda Console",
        "url": "/current/console/ui/generate-bundle/",
        "description": "Learn how to generate, download, and delete debug bundles in Redpanda Console for comprehensive cluster diagnostics."
      },
    ]
  }
]
```

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

The extension accepts the following options in the Antora playbook.

NOTE: Ensure filters are well-defined to minimize unnecessary processing. Avoid overly broad configurations in `data.sets`.

- `data.sets` (required): An object defining one or more indexing configurations. Each configuration (or set) accepts the following options:

** `component` (string, required): The Antora component to search for pages.

** `attribute_name` (string, required): The attribute name to assign the generated index data. This allows pages and templates to reference the index.

** `filter` (string, optional): A substring to match within page URLs.

** `env_type` (string, optional): Matches pages with environment-specific attributes (for example, Docker, Kubernetes).

** `output_file` (string, optional): Save the generated index data as a JSON file at the specified path. If not provided, no file is created.

=== Example configuration

Here's an example configuration to enable the generate-index-data-extension:

```yaml
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/generate-index-data-extension'
      data:
        sets:
          console_ui:
            component: ROOT  # Search the ROOT component
            filter: console/ui # Filter pages containing this substring in their URL
            attribute_name: console-ui-index # Save the result in this attribute
            output_file: redpanda-labs/console-ui-index.json # Save data to this file
          docker_labs:
            component: redpanda-labs
            filter: docker-compose
            env_type: Docker
            attribute_name: docker-labs-index
```

=== Use the generated data

The index data can be referenced in AsciiDoc pages by specifying the following required attributes:

```asciidoc
= CONSOLE UI
:page-index-data: console-ui-index <1>
:page-role: index-list <2>
```

<1> The attribute whose data you want to display on the page. This must match an attribute configured in the extension.
<2> The page role. This role specfies the UI template that renders the data in the `page-index-data` on the page.

You can optionally display pages only if they match the component and version of the current Asciidoc page by adding the `:page-match-component-version:` attribute.

```asciidoc
= CONSOLE UI
:page-index-data: console-ui-index
:page-role: index-list
:page-match-component-version: ''
```

== Redpanda Connect tag modifier

This extension updates the playbook to use the latest release tag for the Redpanda Connect documentation. It ensures that the Redpanda Connect documentation is always pulled from the latest release tag available on GitHub.

=== Environment variables

- `REDPANDA_GITHUB_TOKEN` (optional): A Personal access token (PAT) that has `repo` permissions for the `redpanda-data` GitHub organization.

NOTE: If you don't set the environment variable, the latest version of Redpanda Connect may not be fetched. When the environment variable is not set, the extension sends unauthenticated requests to GitHub. Unauthenticated requests may result in hitting the API rate limit and cause GitHub to reject the request. In this case the fallback version is used. This version is defined in the playbook where the extension is registered.

=== Configuration options

There are no configurable options for this extension.

=== Registration

```yaml
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/modify-connect-tag-playbook'
```

== Version fetcher

This extension fetches the latest release versions from GitHub.

The following attributes are available to all versions of all Antora components:

`latest-console-version`: The latest release version of Redpanda Console.
`latest-connect-version`: The latest release version of Redpanda Connect.
`redpanda-beta-version`: The latest RC version of Redpanda.
`redpanda-beta-commit`: The commit hash for the latest RC version of Redpanda.

The following attributes are available to the latest version of the `ROOT` component (Redpanda docs):

`full-version`: The latest release version of Redpanda.
`latest-release-commit`: The commit hash for the latest release version of Redpanda.
`latest-operator-version`: The latest release version of the Redpanda Operator.
`latest-redpanda-helm-chart-version`: The latest release version of the Redpanda Helm chart.

=== Environment variables

- `REDPANDA_GITHUB_TOKEN` (optional): A Personal access token (PAT) that has `repo` permissions for the `redpanda-data` GitHub organization.

NOTE: If you don't set the environment variable, the latest versions may not be fetched. When the environment variable is not set, the extension sends unauthenticated requests to GitHub. Unauthenticated requests may result in hitting the API rate limit and cause GitHub to reject the request.

=== Registration

```yaml
antora:
  extensions:
  - '@redpanda-data/docs-extensions-and-macros/extensions/version-fetcher/set-latest-version'
```

== Validate attributes

This extension ensures the consistency and validity of page attributes, focusing on validating page categories against a predefined list of valid categories and subcategories. It automatically adds missing parent categories for any specified subcategories and removes any specified categories that are invalid. Additionally, it processes specific environment attributes, setting corresponding page-level attributes when environment conditions are met.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

There are no configurable options for this extension. It operates based on site attributes defined in `add-global-attributes.js` to determine valid categories and subcategories.

=== Registration

Register the `validate-attributes` extension in the Antora playbook under the `antora.extensions` key like so:

[source,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/validate-attributes.js'
----

== Related docs

This extension enhances the connectivity between lab exercises and relevant documentation by dynamically identifying and linking related documentation pages and other lab exercises based on shared categories and deployment types.

=== Environment variables

This extension operates without requiring any specific environment variables.

=== Configuration options

This extension does not offer configurable options. It uses the inherent attributes of pages to determine relationships based on `page-categories` and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).

=== Registration

To integrate the `related-docs-extension` into your Antora playbook, add it under the `antora.extensions` key as demonstrated below:

[source,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/related-docs-extension.js'
----

== Related labs

This extension enriches documentation pages with links to related lab exercises, facilitating a deeper understanding of the content through practical application. It dynamically assigns related labs to each documentation page based on shared categories and deployment types.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

The extension operates without explicit configuration options. It automatically processes documentation pages to identify and link related labs based on shared `page-categories` attributes and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).

=== Registration

Include the `related-labs-extension` in the Antora playbook under the `antora.extensions` key as follows:

[source,yaml]
----
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/related-labs-extension.js'
----

== Global attributes

This extension collects Asciidoc attributes from the https://github.com/redpanda-data/docs-site[`shared` component] or a local YAML file and makes them available to all component versions. Having global attributes is useful for consistent configuration of local and production builds.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

The extension accepts the following configuration options:

attributespath (optional):: Specifies the path to a local YAML file that contains global attributes. If this is provided, the extension will load attributes from this file first. If this path is not provided or no valid attributes are found in the file, the extension will fall back to loading attributes from the `shared` component.

=== Registration

```yml
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/add-global-attributes'
    attributespath: './local-attributes.yml'
```

In this example, the `attributespath` option points to a local YAML file (`./local-attributes.yml`), which contains the global attributes. The extension will load attributes from this file first before falling back to the `shared` component.

== Produce redirects (customization of core Antora)

This extension replaces the default https://gitlab.com/antora/antora/-/tree/v3.1.x/packages/redirect-producer[`produceRedirects()` function] in Antora to handle redirect loops caused by https://docs.antora.org/antora/latest/page/page-aliases/[page aliases]. Normally, page aliases in Antora are used to resolve outdated links without causing issues. However, with https://docs.antora.org/antora/latest/playbook/urls-html-extension-style/#html-extension-style-key[`indexify`], the same URL may inadvertently be used for both the source and target of a redirect, leading to loops. This problem is https://antora.zulipchat.com/#narrow/stream/282400-users/topic/Redirect.20Loop.20Issue.20with.20Page.20Renaming.20and.20Indexify/near/433691700[recognized as a bug] in core Antora. For example, creating a page alias for `modules/manage/security/authorization.adoc` to point to `modules/manage/security/authorization/index.adoc' can lead to a redirect loop where `manage/security/authorization/` points to `manage/security/authorization/`. Furthermore, omitting the alias would lead to `xref not found` errors because Antora relies on the alias to resolve the old xrefs. This extension is necessary until such behaviors are natively supported or fixed in Antora core.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

There are no configurable options for this extension.

=== Registration

```yaml
antora:
  extensions:
  - '@redpanda-data/docs-extensions-and-macros/extensions/modify-redirects'
```

== Replace attributes in attachments

This extension automates the replacement of AsciiDoc attribute placeholders with their respective values within attachment files, such as CSS, HTML, and YAML.

[NOTE]
====
- The `@` character is removed from attribute values to prevent potential issues with CSS or HTML syntax.
- If the same attribute placeholder is used multiple times within a file, all instances will be replaced with the attribute's value.
====

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

The extension accepts the following configuration options in the Antora playbook:

data.replacements (required):: An array of replacement configurations. Each configuration can target multiple components and define specific file patterns and custom replacement rules.

* `components` (array of strings, required): Lists the names of the Antora components whose attachments should undergo attribute replacement.

* `file_patterns` (array of strings, required): Glob patterns specifying which attachment files to process. These patterns determine the files that will undergo attribute replacement based on their paths within the content catalog.

* `custom_replacements` (array of objects, optional): Defines custom search-and-replace rules to be applied to the matched files. Each rule consists of:
** `search` (string, required): A regular expression pattern to search for within the file content.
** `replace` (string, required): The string to replace each match found by the `search` pattern.

NOTE: Ensure that `file_patterns` accurately reflect the paths of the attachments you want to process. Overly broad patterns may include unintended files, while overly restrictive patterns might exclude necessary resources.

=== Registration

This is an example of how to register and configure the `replace-attributes-in-attachments` extension in your Antora playbook. This example demonstrates defining multiple replacement configurations, each targeting different components and specifying their own file patterns and custom replacements.

```yaml
antora:
  extensions:
    - require: './extensions/replace-attributes-in-attachments'
      data:
        replacements:
          - components:
              - 'ROOT'
              - 'redpanda-labs'
            file_patterns:
              - '**/docker-compose.yaml'
              - '**/docker-compose.yml'
            custom_replacements:
              - search: ''\\$\\{CONFIG_FILE:[^}]*\\}''
                replace: 'console.yaml'
          - components:
              - 'API'
            file_patterns:
              - '**/api-docs/**/resources/**'
            custom_replacements:
              - search: '\\$\\{API_ENDPOINT:[^}]*\\}'
                replace: 'https://api.example.com'
```

== Aggregate terms

This extension aggregates all term pages from the https://github.com/redpanda-data/docs-site[`shared` component] and does the following:

- Makes all `term-name`, `hover-text`, and `link` attributes available to the `glossterm` macro.
- Looks for glossary pages named `reference:glossary.adoc` in all versions of all components and appends the contents of each term file to the glossary in alphabetical order.
- If a glossary page is found, sets the `glossary-page` attribute of the `glossterm` macro to `reference:glossary.adoc` so that terms can be linked to the glossary page.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

The extension accepts the following configuration options:

termspath (optional):: Specifies the path to a local directory containing term files (in `.adoc` format). If this path is provided, the extension will attempt to load terms from this directory first. If this path is not provided or no valid terms are found in the specified directory, the extension will fall back to loading terms from the `shared` component.

Term files should follow the following structure:

```asciidoc
:category: Documentation
:hover-text: This is a description of the term.
:link: https://example.com

== Term Title

This is the detailed description of the term.
```

=== Registration

```yml
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/aggregate-terms'
    termspath: './local-terms/'
```

In this example, the `termspath` option points to a local directory (./local-terms/), where the term files are stored. The extension will load terms from this directory first before falling back to the `shared` component.

== Unlisted pages

This extension identifies and logs any pages that aren't listed in the navigation (nav) file of each version of each component. It then optionally adds these unlisted pages to the end of the navigation tree under a configurable heading.

IMPORTANT: By default, this extension excludes components named 'api'. This behavior is hardcoded and cannot be changed in the configuration.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

This extension accepts the following configuration options:

addToNavigation (optional)::
Whether to add unlisted pages to the navigation. The default is `false` (unlisted pages are not added).

unlistedPagesHeading (optional)::
The heading under which to list the unlisted pages in the navigation. The default is 'Unlisted Pages'.

=== Registration

```yaml
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/unlisted-pages'
    addToNavigation: true
    unlistedPagesHeading: 'Additional Resources'
```

== Process context switcher

This extension processes the `page-context-switcher` attribute to enable cross-version navigation widgets in documentation pages. It automatically replaces "current" references with full resource IDs and injects the context switcher configuration to all referenced target pages, ensuring bidirectional navigation works correctly.

The extension finds pages with the `page-context-switcher` attribute, parses the JSON configuration, and:

1. Replaces any "current" values with the full resource ID of the current page
2. Finds all target pages referenced in the switcher configuration
3. Injects the same context switcher attribute to target pages (with appropriate resource ID mappings)
4. Builds resource IDs in the format: `version@component:module:relative-path`

This enables UI components to render version switchers that work across different versions of the same content.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

This extension does not require any configuration options.

=== Registration

```yaml
antora:
  extensions:
    - require: '@redpanda-data/docs-extensions-and-macros/extensions/process-context-switcher'
```

=== Usage

Add the `page-context-switcher` attribute to any page where you want cross-version navigation:

```asciidoc
:page-context-switcher: [{"name": "Version 2.x", "to": "24.3@ROOT:console:config/security/authentication.adoc" },{"name": "Version 3.x", "to": "current" }]
```

=== Processed output

After processing, the "current" reference is replaced with the full resource ID:

```json
[
  {"name": "Version 2.x", "to": "24.3@ROOT:console:config/security/authentication.adoc"},
  {"name": "Version 3.x", "to": "current@ROOT:console:config/security/authentication.adoc"}
]
```

The target page (`24.3@ROOT:console:config/security/authentication.adoc`) will also receive the same context switcher configuration with appropriate resource ID mappings.

=== UI integration

The processed attribute can be used in Handlebars templates:

```html
<div class="context-switcher">
  {{#each (obj page.attributes.page-context-switcher)}}
    <a
      id="{{{this.name}}}"
      href="{{{relativize (resolve-resource this.to)}}}"
      class="context-link {{#if (eq @root.page.url (resolve-resource this.to))}}active{{/if}}"
    >
      <button type="button">{{{this.name}}}</button>
    </a>
  {{/each}}
</div>
```

== Git full clone

This extension ensures Antora uses full git clones instead of shallow clones for remote repositories. Full git history is required for accurate git date extraction by the `add-git-dates` extension.

The extension uses a two-phase approach:

1. **Phase 1**: Sets `git.depth = 0` in playbook during registration (best effort)
2. **Phase 2**: After content aggregation, detects repos with a `shallow` file and runs `git fetch --unshallow` to convert them to full clones

This two-phase approach works around Antora's default shallow clone behavior, which can't always be overridden via playbook configuration alone.

=== How it works

. During extension registration, modifies playbook to request `depth=0` for all remote repos
. After Antora aggregates content, checks each repo's git directory for a `shallow` file
. For any shallow repos found, runs `git fetch --unshallow` with timeout protection
. On subsequent builds with warm cache, repos are already full clones (no unshallow needed)

=== Performance

**First build** (cold cache):

- Unshallow: ~1-5 seconds per remote repo
- Total overhead: ~5-20 seconds depending on repo count

**Subsequent builds** (warm cache):

- Unshallow: 0 seconds (repos already full clones)
- Total overhead: minimal

**Scalability:**

- 1k commits: ~1-2s unshallow time
- 5k commits: ~3-5s unshallow time
- 10k commits: ~5-10s unshallow time
- 50k+ commits: Consider increasing timeout or pre-populating cache

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

The extension accepts the following configuration options:

skipUnshallow (optional, default: false):: Set to `true` to skip the unshallow phase entirely. Useful for air-gapped CI/CD environments or when git dates are not needed.

unshallowTimeout (optional, default: 60000):: Timeout in milliseconds for the unshallow operation per repository. Increase this for very large repositories (50k+ commits).

=== Registration

Basic configuration (recommended):

[,yaml]
----
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
----

With custom timeout for large repos:

[,yaml]
----
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
    unshallowTimeout: 120000  # 2 minutes for very large repos
----

For air-gapped environments:

[,yaml]
----
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
    skipUnshallow: true  # Skip network-dependent unshallow
----

=== Production considerations

**Netlify/CI builds:**

- First build or cache clear: Pays unshallow cost (~5-20s)
- Subsequent builds with warm cache: No unshallow needed
- Consider pre-populating Antora cache in CI for faster cold builds

**Timeout protection:**

- Default 60-second timeout prevents hanging on slow networks
- Graceful failure: Build continues even if unshallow times out
- Git dates may be incomplete for timed-out repos (warning logged)

**Error handling:**

- Network failures don't break the build
- Timeout failures are logged with guidance to increase timeout
- Falls back to available git history if unshallow fails

**Optimization for very large repos (50k+ commits):**

1. Increase `unshallowTimeout` to 120000ms or higher
2. Pre-populate Antora cache with full clones in CI/CD
3. Use persistent cache in Netlify to avoid repeated unshallows
4. Consider implementing Neon KV caching for git dates (future optimization)

== Add Git dates

This extension adds accurate git-based created and modified dates to documentation pages by analyzing commit history. It uses isomorphic-git (bundled with Antora) to walk the commit history of each repository and detects actual file modifications by comparing tree objects between commits.

The extension adds the following attributes to each page:

- `page-git-created-date`: The date when the file was first committed (YYYY-MM-DD format)
- `page-git-modified-date`: The date when the file was last modified (YYYY-MM-DD format)

These attributes are available for use in UI templates (for metadata, display banners, etc.) and are exported to markdown files for AI consumption.

=== How it works

. Groups pages by repository AND branch (same repo can have multiple branches: v/23.3, v/24.1, main)
. Walks git log once per repo+branch using isomorphic-git
. Compares tree objects between commits to detect actual file modifications (not just file existence)
. Builds a filepath → {created, modified} map for each repo+branch
. Applies dates to pages based on their source file path

This approach is **O(commits)** instead of **O(files × commits)**, making it efficient for large repositories.

=== Performance

- **Full clone** (depth=0): ~15s for 4128 pages across 12 branches (14.5s git processing)
- **Per-page overhead**: ~3-5ms per page

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

This extension does not require configuration options. However, it works best with **full git clones** rather than shallow clones.

To enable full clones for remote repositories, use the `git-full-clone` extension:

```yaml
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/add-git-dates'
```

=== Registration

```yaml
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/add-git-dates'
```

=== UI integration

The git dates are available in Handlebars templates via `page.attributes`:

```html
{{#with page.attributes.git-created-date}}
  <meta name="datePublished" content="{{this}}">
{{/with}}
{{#with page.attributes.git-modified-date}}
  <meta name="dateModified" content="{{this}}">
{{/with}}
```

They are also included in schema.org structured data for SEO.

== FAQ structured data

This extension generates schema.org FAQPage JSON-LD for better SEO and Google rich results. Writers define FAQs using page attributes, and the extension generates compliant structured data in the page `<head>`.

=== Environment variables

This extension does not require any environment variables.

=== Configuration options

This extension does not require configuration options.

=== Registration

```yaml
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/add-faq-structured-data'
```

=== Usage

Add FAQ attributes to your AsciiDoc page header:

```asciidoc
= My Documentation Page
:page-faq-1-question: How do I install Redpanda?
:page-faq-1-answer: Download from redpanda.com and run the installer. See our installation guide for details.
:page-faq-1-anchor: #installation

:page-faq-2-question: What are the system requirements?
:page-faq-2-answer: You need at least 2GB of RAM and 2 CPU cores for development.
:page-faq-2-anchor: #requirements

:page-faq-3-question: Does Redpanda support Kafka APIs?
:page-faq-3-answer: Yes! Redpanda is fully compatible with Kafka APIs.
```

**Required attributes per FAQ:**

- `page-faq-N-question` - The FAQ question
- `page-faq-N-answer` - The FAQ answer

**Optional:**

- `page-faq-N-anchor` - Link to page section (e.g., `#installation`)

**Tips:**

- FAQs must be numbered sequentially (1, 2, 3...)
- Answers can reference prose content: "See our installation guide for details"
- Anchors create deep links to related content on the page
- Keep answers concise (Google truncates after ~300 characters)

=== Generated output

The extension generates schema.org FAQPage JSON-LD in the page `<head>`:

```json
{
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "How do I install Redpanda?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Download from redpanda.com and run the installer."
      },
      "url": "https://docs.redpanda.com/page#installation"
    }
  ]
}
```

This structured data appears in Google search results as rich snippets, improving SEO and click-through rates.

== Convert pages to markdown

The `convert-to-markdown` extension converts all HTML pages to markdown format and exports them as `.md` files alongside the HTML. This creates AI-friendly markdown versions of the documentation with proper frontmatter.

=== Features

- Converts all HTML pages to GitHub-Flavored Markdown
- Exports as `.md` files (e.g., `/page.html` → `/page.md`)
- Adds YAML frontmatter with page metadata
- Decodes HTML entities in titles
- Supports content negotiation via `Accept: text/markdown` header
- Stores markdown in `page.markdownContents` for other extensions

=== Configuration

Add to your Antora playbook:

[,yaml]
----
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-to-markdown'
----

=== Frontmatter attributes

The extension exports these attributes to YAML frontmatter:

- `page-title`: Page title
- `page-description`: Page description
- `page-component-name`, `page-component-version`: Component info
- `page-git-created-date`, `page-git-modified-date`: Git dates (if git-dates extension enabled)
- `page-categories`: Categories
- `page-topic-type`: Topic type (tutorial, how-to, concept, reference)
- `page-personas`: Target audience
- Custom attributes from allowlist

=== Example output

[,yaml]
----
---
title: "Get started with Redpanda"
description: "Quick start guide for Redpanda"
component: ROOT
version: current
created: 2024-01-15
modified: 2024-03-29
categories:
  - Getting Started
topic-type: tutorial
personas:
  - developer
---

# Get started with Redpanda

Your markdown content here...
----

== Generate llms.txt exports

The `convert-llms-to-txt` extension generates AI-optimized documentation exports in plain text format following the llms.txt standard.

=== Features

- Generates `llms.txt` from a curated `llms.adoc` page in the home component
- Creates `llms-full.txt` with all documentation pages
- Generates component-specific exports (e.g., `ROOT-full.txt`, `cloud-full.txt`)
- Unpublishes the HTML version of llms.adoc
- Replaces site-url attribute dynamically for preview builds

=== Configuration

Add to your Antora playbook after `convert-to-markdown`:

[,yaml]
----
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-to-markdown'
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-llms-to-txt'
----

=== Setup

Create `modules/home/pages/llms.adoc` in your docs repository with curated documentation overview content. The extension will:

1. Convert it to markdown
2. Place `llms.txt` at site root
3. Generate `llms-full.txt` with all pages
4. Generate component-specific full.txt files
5. Unpublish the HTML version

=== Generated files

- `{site-url}/llms.txt` - Curated overview
- `{site-url}/llms-full.txt` - Complete documentation
- `{site-url}/ROOT-full.txt` - Self-Managed docs only
- `{site-url}/cloud-full.txt` - Cloud docs only
- `{site-url}/redpanda-connect-full.txt` - Connect docs only

=== Attributes

The extension replaces `{site-url}` attribute with:

- `playbook.site.url` in production builds
- `DEPLOY_PRIME_URL` environment variable in preview builds (when `PREVIEW=true`)

== Convert sitemaps to markdown

The `convert-sitemap-to-markdown` extension generates human-readable markdown versions of XML sitemap files.

=== Features

- Converts all sitemap XML files to markdown
- Generates individual `.md` files for each sitemap
- Creates master `sitemap-all.md` combining all pages
- Organizes URLs by component/version
- Includes page metadata (modified dates, priority)
- Uses Antora content catalog (no filesystem operations)

=== Configuration

Add to your Antora playbook:

[,yaml]
----
antora:
  extensions:
  - require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-sitemap-to-markdown'
----

=== Generated files

For a site with component-specific sitemaps:

- `sitemap.md` - Sitemap index with links to sub-sitemaps
- `sitemap-ROOT.md` - Self-Managed pages
- `sitemap-home.md` - Home component pages
- `sitemap-redpanda-cloud.md` - Cloud pages
- `sitemap-redpanda-connect.md` - Connect pages
- `sitemap-all.md` - Master combined sitemap with all pages

=== Output format

[,markdown]
----
# Complete documentation sitemap

> Combined view of all 4,126 documentation pages from 8 sitemaps

## Source sitemaps

- [sitemap-ROOT.xml](sitemap-ROOT.md)
- [sitemap-home.xml](sitemap-home.md)

## Pages

Total pages: 4,126

### Current

- [Get Started](https://docs.redpanda.com/current/get-started/) (modified: 2024-03-29)
- [Deploy](https://docs.redpanda.com/current/deploy/) (modified: 2024-03-28)
----

=== Use cases

- AI agents: Provide sitemap-all.md for quick site navigation
- Documentation planning: Review complete site structure
- Content audits: Identify gaps or outdated content by date
- User discovery: Help users find content through browseable map
