@redpanda-data/docs-extensions-and-macros 4.15.1 → 4.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extension-utils/url-utils.js +39 -0
- package/extensions/README.adoc +4 -0
- package/extensions/REFERENCE.adoc +424 -0
- package/extensions/add-faq-structured-data.js +153 -0
- package/extensions/add-git-dates.js +287 -0
- package/extensions/convert-llms-to-txt.js +341 -7
- package/extensions/convert-sitemap-to-markdown.js +274 -0
- package/extensions/convert-to-markdown.js +187 -20
- package/extensions/git-full-clone.js +114 -0
- package/package.json +5 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared URL utility functions for extensions
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Convert HTML URL to markdown URL
|
|
9
|
+
* @param {string} htmlUrl - The HTML URL (e.g., '/path/to/page/' or '/path/to/page/index.html')
|
|
10
|
+
* @returns {string} - The markdown URL (e.g., '/path/to/page.md')
|
|
11
|
+
*/
|
|
12
|
+
function toMarkdownUrl(htmlUrl) {
|
|
13
|
+
if (!htmlUrl) return ''
|
|
14
|
+
|
|
15
|
+
// Handle root path
|
|
16
|
+
if (htmlUrl === '/' || htmlUrl === '/index.html') {
|
|
17
|
+
return '/index.md'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Remove trailing slash
|
|
21
|
+
let mdUrl = htmlUrl.replace(/\/$/, '')
|
|
22
|
+
|
|
23
|
+
// Replace /index.html with .md
|
|
24
|
+
mdUrl = mdUrl.replace(/\/index\.html$/, '.md')
|
|
25
|
+
|
|
26
|
+
// Replace .html with .md
|
|
27
|
+
mdUrl = mdUrl.replace(/\.html$/, '.md')
|
|
28
|
+
|
|
29
|
+
// If it doesn't end with .md yet, add it
|
|
30
|
+
if (!mdUrl.endsWith('.md')) {
|
|
31
|
+
mdUrl += '.md'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return mdUrl
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
toMarkdownUrl,
|
|
39
|
+
}
|
package/extensions/README.adoc
CHANGED
|
@@ -77,6 +77,10 @@ IMPORTANT: Extensions must be registered under the `antora.extensions` key in yo
|
|
|
77
77
|
* **replace-attributes-in-attachments** - Replace AsciiDoc attributes in attached files
|
|
78
78
|
* **collect-bloblang-samples** - Collect Bloblang code samples
|
|
79
79
|
|
|
80
|
+
=== Git integration
|
|
81
|
+
* **git-full-clone** - Ensure full git clones for accurate git dates
|
|
82
|
+
* **add-git-dates** - Add git-based created and modified dates to pages
|
|
83
|
+
|
|
80
84
|
=== Content enhancement
|
|
81
85
|
* **add-global-attributes** - Add attributes globally to all pages
|
|
82
86
|
* **add-pages-to-root** - Add pages to the root navigation
|
|
@@ -766,3 +766,427 @@ The processed attribute can be used in Handlebars templates:
|
|
|
766
766
|
{{/each}}
|
|
767
767
|
</div>
|
|
768
768
|
```
|
|
769
|
+
|
|
770
|
+
== Git full clone
|
|
771
|
+
|
|
772
|
+
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.
|
|
773
|
+
|
|
774
|
+
The extension uses a two-phase approach:
|
|
775
|
+
|
|
776
|
+
1. **Phase 1**: Sets `git.depth = 0` in playbook during registration (best effort)
|
|
777
|
+
2. **Phase 2**: After content aggregation, detects repos with a `shallow` file and runs `git fetch --unshallow` to convert them to full clones
|
|
778
|
+
|
|
779
|
+
This two-phase approach works around Antora's default shallow clone behavior, which can't always be overridden via playbook configuration alone.
|
|
780
|
+
|
|
781
|
+
=== How it works
|
|
782
|
+
|
|
783
|
+
. During extension registration, modifies playbook to request `depth=0` for all remote repos
|
|
784
|
+
. After Antora aggregates content, checks each repo's git directory for a `shallow` file
|
|
785
|
+
. For any shallow repos found, runs `git fetch --unshallow` with timeout protection
|
|
786
|
+
. On subsequent builds with warm cache, repos are already full clones (no unshallow needed)
|
|
787
|
+
|
|
788
|
+
=== Performance
|
|
789
|
+
|
|
790
|
+
**First build** (cold cache):
|
|
791
|
+
|
|
792
|
+
- Unshallow: ~1-5 seconds per remote repo
|
|
793
|
+
- Total overhead: ~5-20 seconds depending on repo count
|
|
794
|
+
|
|
795
|
+
**Subsequent builds** (warm cache):
|
|
796
|
+
|
|
797
|
+
- Unshallow: 0 seconds (repos already full clones)
|
|
798
|
+
- Total overhead: minimal
|
|
799
|
+
|
|
800
|
+
**Scalability:**
|
|
801
|
+
|
|
802
|
+
- 1k commits: ~1-2s unshallow time
|
|
803
|
+
- 5k commits: ~3-5s unshallow time
|
|
804
|
+
- 10k commits: ~5-10s unshallow time
|
|
805
|
+
- 50k+ commits: Consider increasing timeout or pre-populating cache
|
|
806
|
+
|
|
807
|
+
=== Environment variables
|
|
808
|
+
|
|
809
|
+
This extension does not require any environment variables.
|
|
810
|
+
|
|
811
|
+
=== Configuration options
|
|
812
|
+
|
|
813
|
+
The extension accepts the following configuration options:
|
|
814
|
+
|
|
815
|
+
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.
|
|
816
|
+
|
|
817
|
+
unshallowTimeout (optional, default: 60000):: Timeout in milliseconds for the unshallow operation per repository. Increase this for very large repositories (50k+ commits).
|
|
818
|
+
|
|
819
|
+
=== Registration
|
|
820
|
+
|
|
821
|
+
Basic configuration (recommended):
|
|
822
|
+
|
|
823
|
+
[,yaml]
|
|
824
|
+
----
|
|
825
|
+
antora:
|
|
826
|
+
extensions:
|
|
827
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
|
|
828
|
+
----
|
|
829
|
+
|
|
830
|
+
With custom timeout for large repos:
|
|
831
|
+
|
|
832
|
+
[,yaml]
|
|
833
|
+
----
|
|
834
|
+
antora:
|
|
835
|
+
extensions:
|
|
836
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
|
|
837
|
+
unshallowTimeout: 120000 # 2 minutes for very large repos
|
|
838
|
+
----
|
|
839
|
+
|
|
840
|
+
For air-gapped environments:
|
|
841
|
+
|
|
842
|
+
[,yaml]
|
|
843
|
+
----
|
|
844
|
+
antora:
|
|
845
|
+
extensions:
|
|
846
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
|
|
847
|
+
skipUnshallow: true # Skip network-dependent unshallow
|
|
848
|
+
----
|
|
849
|
+
|
|
850
|
+
=== Production considerations
|
|
851
|
+
|
|
852
|
+
**Netlify/CI builds:**
|
|
853
|
+
|
|
854
|
+
- First build or cache clear: Pays unshallow cost (~5-20s)
|
|
855
|
+
- Subsequent builds with warm cache: No unshallow needed
|
|
856
|
+
- Consider pre-populating Antora cache in CI for faster cold builds
|
|
857
|
+
|
|
858
|
+
**Timeout protection:**
|
|
859
|
+
|
|
860
|
+
- Default 60-second timeout prevents hanging on slow networks
|
|
861
|
+
- Graceful failure: Build continues even if unshallow times out
|
|
862
|
+
- Git dates may be incomplete for timed-out repos (warning logged)
|
|
863
|
+
|
|
864
|
+
**Error handling:**
|
|
865
|
+
|
|
866
|
+
- Network failures don't break the build
|
|
867
|
+
- Timeout failures are logged with guidance to increase timeout
|
|
868
|
+
- Falls back to available git history if unshallow fails
|
|
869
|
+
|
|
870
|
+
**Optimization for very large repos (50k+ commits):**
|
|
871
|
+
|
|
872
|
+
1. Increase `unshallowTimeout` to 120000ms or higher
|
|
873
|
+
2. Pre-populate Antora cache with full clones in CI/CD
|
|
874
|
+
3. Use persistent cache in Netlify to avoid repeated unshallows
|
|
875
|
+
4. Consider implementing Neon KV caching for git dates (future optimization)
|
|
876
|
+
|
|
877
|
+
== Add Git dates
|
|
878
|
+
|
|
879
|
+
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.
|
|
880
|
+
|
|
881
|
+
The extension adds the following attributes to each page:
|
|
882
|
+
|
|
883
|
+
- `page-git-created-date`: The date when the file was first committed (YYYY-MM-DD format)
|
|
884
|
+
- `page-git-modified-date`: The date when the file was last modified (YYYY-MM-DD format)
|
|
885
|
+
|
|
886
|
+
These attributes are available for use in UI templates (for metadata, display banners, etc.) and are exported to markdown files for AI consumption.
|
|
887
|
+
|
|
888
|
+
=== How it works
|
|
889
|
+
|
|
890
|
+
. Groups pages by repository AND branch (same repo can have multiple branches: v/23.3, v/24.1, main)
|
|
891
|
+
. Walks git log once per repo+branch using isomorphic-git
|
|
892
|
+
. Compares tree objects between commits to detect actual file modifications (not just file existence)
|
|
893
|
+
. Builds a filepath → {created, modified} map for each repo+branch
|
|
894
|
+
. Applies dates to pages based on their source file path
|
|
895
|
+
|
|
896
|
+
This approach is **O(commits)** instead of **O(files × commits)**, making it efficient for large repositories.
|
|
897
|
+
|
|
898
|
+
=== Performance
|
|
899
|
+
|
|
900
|
+
- **Full clone** (depth=0): ~15s for 4128 pages across 12 branches (14.5s git processing)
|
|
901
|
+
- **Per-page overhead**: ~3-5ms per page
|
|
902
|
+
|
|
903
|
+
=== Environment variables
|
|
904
|
+
|
|
905
|
+
This extension does not require any environment variables.
|
|
906
|
+
|
|
907
|
+
=== Configuration options
|
|
908
|
+
|
|
909
|
+
This extension does not require configuration options. However, it works best with **full git clones** rather than shallow clones.
|
|
910
|
+
|
|
911
|
+
To enable full clones for remote repositories, use the `git-full-clone` extension:
|
|
912
|
+
|
|
913
|
+
```yaml
|
|
914
|
+
antora:
|
|
915
|
+
extensions:
|
|
916
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/git-full-clone'
|
|
917
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/add-git-dates'
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
=== Registration
|
|
921
|
+
|
|
922
|
+
```yaml
|
|
923
|
+
antora:
|
|
924
|
+
extensions:
|
|
925
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/add-git-dates'
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
=== UI integration
|
|
929
|
+
|
|
930
|
+
The git dates are available in Handlebars templates via `page.attributes`:
|
|
931
|
+
|
|
932
|
+
```html
|
|
933
|
+
{{#with page.attributes.git-created-date}}
|
|
934
|
+
<meta name="datePublished" content="{{this}}">
|
|
935
|
+
{{/with}}
|
|
936
|
+
{{#with page.attributes.git-modified-date}}
|
|
937
|
+
<meta name="dateModified" content="{{this}}">
|
|
938
|
+
{{/with}}
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
They are also included in schema.org structured data for SEO.
|
|
942
|
+
|
|
943
|
+
== FAQ structured data
|
|
944
|
+
|
|
945
|
+
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>`.
|
|
946
|
+
|
|
947
|
+
=== Environment variables
|
|
948
|
+
|
|
949
|
+
This extension does not require any environment variables.
|
|
950
|
+
|
|
951
|
+
=== Configuration options
|
|
952
|
+
|
|
953
|
+
This extension does not require configuration options.
|
|
954
|
+
|
|
955
|
+
=== Registration
|
|
956
|
+
|
|
957
|
+
```yaml
|
|
958
|
+
antora:
|
|
959
|
+
extensions:
|
|
960
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/add-faq-structured-data'
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
=== Usage
|
|
964
|
+
|
|
965
|
+
Add FAQ attributes to your AsciiDoc page header:
|
|
966
|
+
|
|
967
|
+
```asciidoc
|
|
968
|
+
= My Documentation Page
|
|
969
|
+
:page-faq-1-question: How do I install Redpanda?
|
|
970
|
+
:page-faq-1-answer: Download from redpanda.com and run the installer. See our installation guide for details.
|
|
971
|
+
:page-faq-1-anchor: #installation
|
|
972
|
+
|
|
973
|
+
:page-faq-2-question: What are the system requirements?
|
|
974
|
+
:page-faq-2-answer: You need at least 2GB of RAM and 2 CPU cores for development.
|
|
975
|
+
:page-faq-2-anchor: #requirements
|
|
976
|
+
|
|
977
|
+
:page-faq-3-question: Does Redpanda support Kafka APIs?
|
|
978
|
+
:page-faq-3-answer: Yes! Redpanda is fully compatible with Kafka APIs.
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
**Required attributes per FAQ:**
|
|
982
|
+
|
|
983
|
+
- `page-faq-N-question` - The FAQ question
|
|
984
|
+
- `page-faq-N-answer` - The FAQ answer
|
|
985
|
+
|
|
986
|
+
**Optional:**
|
|
987
|
+
|
|
988
|
+
- `page-faq-N-anchor` - Link to page section (e.g., `#installation`)
|
|
989
|
+
|
|
990
|
+
**Tips:**
|
|
991
|
+
|
|
992
|
+
- FAQs must be numbered sequentially (1, 2, 3...)
|
|
993
|
+
- Answers can reference prose content: "See our installation guide for details"
|
|
994
|
+
- Anchors create deep links to related content on the page
|
|
995
|
+
- Keep answers concise (Google truncates after ~300 characters)
|
|
996
|
+
|
|
997
|
+
=== Generated output
|
|
998
|
+
|
|
999
|
+
The extension generates schema.org FAQPage JSON-LD in the page `<head>`:
|
|
1000
|
+
|
|
1001
|
+
```json
|
|
1002
|
+
{
|
|
1003
|
+
"@type": "FAQPage",
|
|
1004
|
+
"mainEntity": [
|
|
1005
|
+
{
|
|
1006
|
+
"@type": "Question",
|
|
1007
|
+
"name": "How do I install Redpanda?",
|
|
1008
|
+
"acceptedAnswer": {
|
|
1009
|
+
"@type": "Answer",
|
|
1010
|
+
"text": "Download from redpanda.com and run the installer."
|
|
1011
|
+
},
|
|
1012
|
+
"url": "https://docs.redpanda.com/page#installation"
|
|
1013
|
+
}
|
|
1014
|
+
]
|
|
1015
|
+
}
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
This structured data appears in Google search results as rich snippets, improving SEO and click-through rates.
|
|
1019
|
+
|
|
1020
|
+
== Convert pages to markdown
|
|
1021
|
+
|
|
1022
|
+
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.
|
|
1023
|
+
|
|
1024
|
+
=== Features
|
|
1025
|
+
|
|
1026
|
+
- Converts all HTML pages to GitHub-Flavored Markdown
|
|
1027
|
+
- Exports as `.md` files (e.g., `/page.html` → `/page.md`)
|
|
1028
|
+
- Adds YAML frontmatter with page metadata
|
|
1029
|
+
- Decodes HTML entities in titles
|
|
1030
|
+
- Supports content negotiation via `Accept: text/markdown` header
|
|
1031
|
+
- Stores markdown in `page.markdownContents` for other extensions
|
|
1032
|
+
|
|
1033
|
+
=== Configuration
|
|
1034
|
+
|
|
1035
|
+
Add to your Antora playbook:
|
|
1036
|
+
|
|
1037
|
+
[,yaml]
|
|
1038
|
+
----
|
|
1039
|
+
antora:
|
|
1040
|
+
extensions:
|
|
1041
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-to-markdown'
|
|
1042
|
+
----
|
|
1043
|
+
|
|
1044
|
+
=== Frontmatter attributes
|
|
1045
|
+
|
|
1046
|
+
The extension exports these attributes to YAML frontmatter:
|
|
1047
|
+
|
|
1048
|
+
- `page-title`: Page title
|
|
1049
|
+
- `page-description`: Page description
|
|
1050
|
+
- `page-component-name`, `page-component-version`: Component info
|
|
1051
|
+
- `page-git-created-date`, `page-git-modified-date`: Git dates (if git-dates extension enabled)
|
|
1052
|
+
- `page-categories`: Categories
|
|
1053
|
+
- `page-topic-type`: Topic type (tutorial, how-to, concept, reference)
|
|
1054
|
+
- `page-personas`: Target audience
|
|
1055
|
+
- Custom attributes from allowlist
|
|
1056
|
+
|
|
1057
|
+
=== Example output
|
|
1058
|
+
|
|
1059
|
+
[,yaml]
|
|
1060
|
+
----
|
|
1061
|
+
---
|
|
1062
|
+
title: "Get started with Redpanda"
|
|
1063
|
+
description: "Quick start guide for Redpanda"
|
|
1064
|
+
component: ROOT
|
|
1065
|
+
version: current
|
|
1066
|
+
created: 2024-01-15
|
|
1067
|
+
modified: 2024-03-29
|
|
1068
|
+
categories:
|
|
1069
|
+
- Getting Started
|
|
1070
|
+
topic-type: tutorial
|
|
1071
|
+
personas:
|
|
1072
|
+
- developer
|
|
1073
|
+
---
|
|
1074
|
+
|
|
1075
|
+
# Get started with Redpanda
|
|
1076
|
+
|
|
1077
|
+
Your markdown content here...
|
|
1078
|
+
----
|
|
1079
|
+
|
|
1080
|
+
== Generate llms.txt exports
|
|
1081
|
+
|
|
1082
|
+
The `convert-llms-to-txt` extension generates AI-optimized documentation exports in plain text format following the llms.txt standard.
|
|
1083
|
+
|
|
1084
|
+
=== Features
|
|
1085
|
+
|
|
1086
|
+
- Generates `llms.txt` from a curated `llms.adoc` page in the home component
|
|
1087
|
+
- Creates `llms-full.txt` with all documentation pages
|
|
1088
|
+
- Generates component-specific exports (e.g., `ROOT-full.txt`, `cloud-full.txt`)
|
|
1089
|
+
- Unpublishes the HTML version of llms.adoc
|
|
1090
|
+
- Replaces site-url attribute dynamically for preview builds
|
|
1091
|
+
|
|
1092
|
+
=== Configuration
|
|
1093
|
+
|
|
1094
|
+
Add to your Antora playbook after `convert-to-markdown`:
|
|
1095
|
+
|
|
1096
|
+
[,yaml]
|
|
1097
|
+
----
|
|
1098
|
+
antora:
|
|
1099
|
+
extensions:
|
|
1100
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-to-markdown'
|
|
1101
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-llms-to-txt'
|
|
1102
|
+
----
|
|
1103
|
+
|
|
1104
|
+
=== Setup
|
|
1105
|
+
|
|
1106
|
+
Create `modules/home/pages/llms.adoc` in your docs repository with curated documentation overview content. The extension will:
|
|
1107
|
+
|
|
1108
|
+
1. Convert it to markdown
|
|
1109
|
+
2. Place `llms.txt` at site root
|
|
1110
|
+
3. Generate `llms-full.txt` with all pages
|
|
1111
|
+
4. Generate component-specific full.txt files
|
|
1112
|
+
5. Unpublish the HTML version
|
|
1113
|
+
|
|
1114
|
+
=== Generated files
|
|
1115
|
+
|
|
1116
|
+
- `{site-url}/llms.txt` - Curated overview
|
|
1117
|
+
- `{site-url}/llms-full.txt` - Complete documentation
|
|
1118
|
+
- `{site-url}/ROOT-full.txt` - Self-Managed docs only
|
|
1119
|
+
- `{site-url}/cloud-full.txt` - Cloud docs only
|
|
1120
|
+
- `{site-url}/redpanda-connect-full.txt` - Connect docs only
|
|
1121
|
+
|
|
1122
|
+
=== Attributes
|
|
1123
|
+
|
|
1124
|
+
The extension replaces `{site-url}` attribute with:
|
|
1125
|
+
|
|
1126
|
+
- `playbook.site.url` in production builds
|
|
1127
|
+
- `DEPLOY_PRIME_URL` environment variable in preview builds (when `PREVIEW=true`)
|
|
1128
|
+
|
|
1129
|
+
== Convert sitemaps to markdown
|
|
1130
|
+
|
|
1131
|
+
The `convert-sitemap-to-markdown` extension generates human-readable markdown versions of XML sitemap files.
|
|
1132
|
+
|
|
1133
|
+
=== Features
|
|
1134
|
+
|
|
1135
|
+
- Converts all sitemap XML files to markdown
|
|
1136
|
+
- Generates individual `.md` files for each sitemap
|
|
1137
|
+
- Creates master `sitemap-all.md` combining all pages
|
|
1138
|
+
- Organizes URLs by component/version
|
|
1139
|
+
- Includes page metadata (modified dates, priority)
|
|
1140
|
+
- Uses Antora content catalog (no filesystem operations)
|
|
1141
|
+
|
|
1142
|
+
=== Configuration
|
|
1143
|
+
|
|
1144
|
+
Add to your Antora playbook:
|
|
1145
|
+
|
|
1146
|
+
[,yaml]
|
|
1147
|
+
----
|
|
1148
|
+
antora:
|
|
1149
|
+
extensions:
|
|
1150
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/convert-sitemap-to-markdown'
|
|
1151
|
+
----
|
|
1152
|
+
|
|
1153
|
+
=== Generated files
|
|
1154
|
+
|
|
1155
|
+
For a site with component-specific sitemaps:
|
|
1156
|
+
|
|
1157
|
+
- `sitemap.md` - Sitemap index with links to sub-sitemaps
|
|
1158
|
+
- `sitemap-ROOT.md` - Self-Managed pages
|
|
1159
|
+
- `sitemap-home.md` - Home component pages
|
|
1160
|
+
- `sitemap-redpanda-cloud.md` - Cloud pages
|
|
1161
|
+
- `sitemap-redpanda-connect.md` - Connect pages
|
|
1162
|
+
- `sitemap-all.md` - Master combined sitemap with all pages
|
|
1163
|
+
|
|
1164
|
+
=== Output format
|
|
1165
|
+
|
|
1166
|
+
[,markdown]
|
|
1167
|
+
----
|
|
1168
|
+
# Complete documentation sitemap
|
|
1169
|
+
|
|
1170
|
+
> Combined view of all 4,126 documentation pages from 8 sitemaps
|
|
1171
|
+
|
|
1172
|
+
## Source sitemaps
|
|
1173
|
+
|
|
1174
|
+
- [sitemap-ROOT.xml](sitemap-ROOT.md)
|
|
1175
|
+
- [sitemap-home.xml](sitemap-home.md)
|
|
1176
|
+
|
|
1177
|
+
## Pages
|
|
1178
|
+
|
|
1179
|
+
Total pages: 4,126
|
|
1180
|
+
|
|
1181
|
+
### Current
|
|
1182
|
+
|
|
1183
|
+
- [Get Started](https://docs.redpanda.com/current/get-started/) (modified: 2024-03-29)
|
|
1184
|
+
- [Deploy](https://docs.redpanda.com/current/deploy/) (modified: 2024-03-28)
|
|
1185
|
+
----
|
|
1186
|
+
|
|
1187
|
+
=== Use cases
|
|
1188
|
+
|
|
1189
|
+
- AI agents: Provide sitemap-all.md for quick site navigation
|
|
1190
|
+
- Documentation planning: Review complete site structure
|
|
1191
|
+
- Content audits: Identify gaps or outdated content by date
|
|
1192
|
+
- User discovery: Help users find content through browseable map
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generates FAQPage JSON-LD structured data for SEO.
|
|
5
|
+
*
|
|
6
|
+
* USAGE:
|
|
7
|
+
* :page-faq-1-question: How do I install Redpanda?
|
|
8
|
+
* :page-faq-1-answer: Download from redpanda.com and run the installer.
|
|
9
|
+
* :page-faq-1-anchor: #installation (optional - links to section)
|
|
10
|
+
*
|
|
11
|
+
* :page-faq-2-question: What are the system requirements?
|
|
12
|
+
* :page-faq-2-answer: You need at least 2GB RAM and 2 CPU cores.
|
|
13
|
+
* :page-faq-2-anchor: #requirements
|
|
14
|
+
*
|
|
15
|
+
* The extension:
|
|
16
|
+
* - Generates schema.org FAQPage JSON-LD in <head>
|
|
17
|
+
* - Supports multiple FAQs numbered sequentially (1, 2, 3...)
|
|
18
|
+
* - Anchor is optional and adds URL to the FAQ question
|
|
19
|
+
* - Writers can reference existing page content in answers
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extract FAQ entries from page attributes
|
|
24
|
+
* @param {Object} attributes - Page attributes object
|
|
25
|
+
* @param {Object} logger - Logger instance
|
|
26
|
+
* @returns {Array<{question: string, answer: string, anchor?: string}>}
|
|
27
|
+
*/
|
|
28
|
+
function extractFaqs(attributes, logger) {
|
|
29
|
+
const faqs = []
|
|
30
|
+
const faqNumbers = new Set()
|
|
31
|
+
|
|
32
|
+
// Find all FAQ numbers by scanning for -question attributes
|
|
33
|
+
Object.keys(attributes).forEach(key => {
|
|
34
|
+
const match = key.match(/^page-faq-(\d+)-question$/)
|
|
35
|
+
if (match) {
|
|
36
|
+
faqNumbers.add(parseInt(match[1], 10))
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
if (faqNumbers.size === 0) return faqs
|
|
41
|
+
|
|
42
|
+
// Extract FAQs in numerical order
|
|
43
|
+
const sortedNumbers = Array.from(faqNumbers).sort((a, b) => a - b)
|
|
44
|
+
|
|
45
|
+
sortedNumbers.forEach(num => {
|
|
46
|
+
const question = attributes[`page-faq-${num}-question`]
|
|
47
|
+
const answer = attributes[`page-faq-${num}-answer`]
|
|
48
|
+
const anchor = attributes[`page-faq-${num}-anchor`]
|
|
49
|
+
|
|
50
|
+
// Both question and answer are required
|
|
51
|
+
if (!question) {
|
|
52
|
+
logger.warn(`FAQ ${num}: question missing`)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!answer) {
|
|
57
|
+
logger.warn(`FAQ ${num}: answer missing`)
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const faq = {
|
|
62
|
+
question: question.trim(),
|
|
63
|
+
answer: answer.trim()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (anchor) {
|
|
67
|
+
faq.anchor = anchor.trim()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
faqs.push(faq)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return faqs
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Generate FAQPage JSON-LD structure
|
|
78
|
+
* @param {Array} faqs - Array of FAQ objects
|
|
79
|
+
* @param {string} baseUrl - Base URL for the page
|
|
80
|
+
* @returns {Object} FAQPage JSON-LD object
|
|
81
|
+
*/
|
|
82
|
+
function generateFaqJsonLd(faqs, baseUrl) {
|
|
83
|
+
const mainEntity = faqs.map(faq => {
|
|
84
|
+
const question = {
|
|
85
|
+
'@type': 'Question',
|
|
86
|
+
'name': faq.question,
|
|
87
|
+
'acceptedAnswer': {
|
|
88
|
+
'@type': 'Answer',
|
|
89
|
+
'text': faq.answer
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Add URL with anchor if provided
|
|
94
|
+
if (faq.anchor) {
|
|
95
|
+
const anchor = faq.anchor.startsWith('#') ? faq.anchor : `#${faq.anchor}`
|
|
96
|
+
question.url = `${baseUrl}${anchor}`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return question
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
'@type': 'FAQPage',
|
|
104
|
+
'mainEntity': mainEntity
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports.register = function () {
|
|
109
|
+
const logger = this.getLogger('add-faq-structured-data-extension')
|
|
110
|
+
let playbook
|
|
111
|
+
|
|
112
|
+
this.once('playbookBuilt', ({ playbook: pb }) => {
|
|
113
|
+
playbook = pb
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
this.on('documentsConverted', ({ contentCatalog }) => {
|
|
117
|
+
const pages = contentCatalog.getPages()
|
|
118
|
+
let processedCount = 0
|
|
119
|
+
let totalFaqs = 0
|
|
120
|
+
const siteUrl = playbook?.site?.url || 'https://docs.redpanda.com'
|
|
121
|
+
|
|
122
|
+
pages.forEach(page => {
|
|
123
|
+
const attributes = page.asciidoc?.attributes
|
|
124
|
+
if (!attributes) return
|
|
125
|
+
|
|
126
|
+
// Extract FAQs from attributes
|
|
127
|
+
const faqs = extractFaqs(attributes, logger)
|
|
128
|
+
|
|
129
|
+
if (faqs.length === 0) return
|
|
130
|
+
|
|
131
|
+
// Generate base URL for the page
|
|
132
|
+
let baseUrl = ''
|
|
133
|
+
if (page.pub?.url) {
|
|
134
|
+
baseUrl = `${siteUrl}${page.pub.url}`
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Generate FAQPage JSON-LD
|
|
138
|
+
const faqJsonLd = generateFaqJsonLd(faqs, baseUrl)
|
|
139
|
+
|
|
140
|
+
// Store as JSON string in page attribute for UI template
|
|
141
|
+
attributes['page-faq-json-ld'] = JSON.stringify(faqJsonLd, null, 2)
|
|
142
|
+
|
|
143
|
+
processedCount++
|
|
144
|
+
totalFaqs += faqs.length
|
|
145
|
+
|
|
146
|
+
logger.debug(`Added ${faqs.length} FAQs to ${page.src.relative}`)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
if (processedCount > 0) {
|
|
150
|
+
logger.info(`Generated FAQ structured data for ${processedCount} pages (${totalFaqs} total FAQs)`)
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
}
|