@redpanda-data/docs-extensions-and-macros 4.8.0 → 4.8.1

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.
Files changed (25) hide show
  1. package/bin/doc-tools.js +88 -53
  2. package/package.json +1 -1
  3. package/tools/property-extractor/Makefile +62 -34
  4. package/tools/property-extractor/generate-handlebars-docs.js +344 -0
  5. package/tools/property-extractor/helpers/and.js +10 -0
  6. package/tools/property-extractor/helpers/eq.js +9 -0
  7. package/tools/property-extractor/helpers/formatPropertyValue.js +128 -0
  8. package/tools/property-extractor/helpers/formatUnits.js +26 -0
  9. package/tools/property-extractor/helpers/index.js +13 -0
  10. package/tools/property-extractor/helpers/join.js +18 -0
  11. package/tools/property-extractor/helpers/ne.js +9 -0
  12. package/tools/property-extractor/helpers/not.js +8 -0
  13. package/tools/property-extractor/helpers/or.js +10 -0
  14. package/tools/property-extractor/helpers/renderPropertyExample.js +42 -0
  15. package/tools/property-extractor/package-lock.json +77 -0
  16. package/tools/property-extractor/package.json +6 -0
  17. package/tools/property-extractor/property_extractor.py +1163 -20
  18. package/tools/property-extractor/requirements.txt +1 -0
  19. package/tools/property-extractor/templates/deprecated-properties.hbs +25 -0
  20. package/tools/property-extractor/templates/deprecated-property.hbs +7 -0
  21. package/tools/property-extractor/templates/property-page.hbs +22 -0
  22. package/tools/property-extractor/templates/property.hbs +70 -0
  23. package/tools/property-extractor/templates/topic-property.hbs +59 -0
  24. package/tools/property-extractor/transformers.py +80 -4
  25. package/tools/property-extractor/json-to-asciidoc/generate_docs.py +0 -491
package/bin/doc-tools.js CHANGED
@@ -98,7 +98,7 @@ function requireCmd(cmd, help, versionFlag = '--version') {
98
98
  * @param {number} [minMinor=10] - Minimum required minor version of Python.
99
99
  */
100
100
  function requirePython(minMajor = 3, minMinor = 10) {
101
- const candidates = ['python3', 'python'];
101
+ const candidates = ['python3', 'python', 'python3.12', 'python3.11', 'python3.10'];
102
102
  for (const p of candidates) {
103
103
  try {
104
104
  const out = execSync(`${p} --version`, { encoding: 'utf8' }).trim();
@@ -234,12 +234,16 @@ For more details, visit: https://github.com/norwoodj/helm-docs
234
234
  /**
235
235
  * Ensures all dependencies required for generating property documentation are installed.
236
236
  *
237
- * Checks for the presence of `make`, Python 3.10 or newer, C++ compiler, and C++ standard library headers.
237
+ * Checks for the presence of `make`, Python 3.10 or newer, Node.js, C++ compiler, and C++ standard library headers.
238
238
  * Exits the process with an error message if any dependency is missing.
239
239
  */
240
240
  function verifyPropertyDependencies() {
241
241
  requireCmd('make', 'Your OS package manager');
242
242
  requirePython();
243
+
244
+ // Check for Node.js (required for Handlebars templates)
245
+ requireCmd('node', 'https://nodejs.org/en/download/ or use your package manager (e.g., brew install node)');
246
+ requireCmd('npm', 'Usually installed with Node.js');
243
247
 
244
248
  // Check for C++ compiler
245
249
  let cppCompiler = null;
@@ -463,25 +467,23 @@ function runClusterDocs(mode, tag, options) {
463
467
  if (r.status !== 0) process.exit(r.status);
464
468
  }
465
469
 
466
- // helper to diff two autogenerated directories
467
- function diffDirs(kind, oldTag, newTag) {
468
- const oldDir = path.join('autogenerated', oldTag, kind);
469
- const newDir = path.join('autogenerated', newTag, kind);
470
- const diffDir = path.join('autogenerated', 'diffs', kind, `${oldTag}_to_${newTag}`);
470
+ // helper to diff two temporary directories
471
+ function diffDirs(kind, oldTag, newTag, oldTempDir, newTempDir) {
472
+ const diffDir = path.join('tmp', 'diffs', kind, `${oldTag}_to_${newTag}`);
471
473
  const patch = path.join(diffDir, 'changes.patch');
472
474
 
473
- if (!fs.existsSync(oldDir)) {
474
- console.error(`❌ Cannot diff: missing ${oldDir}`);
475
+ if (!fs.existsSync(oldTempDir)) {
476
+ console.error(`❌ Cannot diff: missing ${oldTempDir}`);
475
477
  process.exit(1);
476
478
  }
477
- if (!fs.existsSync(newDir)) {
478
- console.error(`❌ Cannot diff: missing ${newDir}`);
479
+ if (!fs.existsSync(newTempDir)) {
480
+ console.error(`❌ Cannot diff: missing ${newTempDir}`);
479
481
  process.exit(1);
480
482
  }
481
483
 
482
484
  fs.mkdirSync(diffDir, { recursive: true });
483
485
 
484
- const cmd = `diff -ru "${oldDir}" "${newDir}" > "${patch}" || true`;
486
+ const cmd = `diff -ru "${oldTempDir}" "${newTempDir}" > "${patch}" || true`;
485
487
  const res = spawnSync(cmd, { stdio: 'inherit', shell: true });
486
488
 
487
489
  if (res.error) {
@@ -489,6 +491,10 @@ function diffDirs(kind, oldTag, newTag) {
489
491
  process.exit(1);
490
492
  }
491
493
  console.log(`✅ Wrote patch: ${patch}`);
494
+
495
+ // Clean up temporary directories
496
+ fs.rmSync(oldTempDir, { recursive: true, force: true });
497
+ fs.rmSync(newTempDir, { recursive: true, force: true });
492
498
  }
493
499
 
494
500
  automation
@@ -747,15 +753,56 @@ automation
747
753
  .description('Generate JSON and AsciiDoc documentation for Redpanda configuration properties')
748
754
  .option('--tag <tag>', 'Git tag or branch to extract from', 'dev')
749
755
  .option('--diff <oldTag>', 'Also diff autogenerated properties from <oldTag> → <tag>')
756
+ .option('--overrides <path>', 'Optional JSON file with property description overrides')
757
+ .option('--output-dir <dir>', 'Where to write all generated files', 'modules/reference')
758
+ .option('--template-property-page <path>', 'Custom Handlebars template for property page layout')
759
+ .option('--template-property <path>', 'Custom Handlebars template for individual property sections')
760
+ .option('--template-deprecated <path>', 'Custom Handlebars template for deprecated properties page')
761
+ .option('--template-deprecated-property <path>', 'Custom Handlebars template for individual deprecated property sections')
750
762
  .action((options) => {
751
763
  verifyPropertyDependencies();
752
764
 
753
765
  const newTag = options.tag;
754
766
  const oldTag = options.diff;
767
+ const overridesPath = options.overrides;
768
+ const outputDir = options.outputDir;
755
769
  const cwd = path.resolve(__dirname, '../tools/property-extractor');
756
- const make = (tag) => {
757
- console.log(`⏳ Building property docs for ${tag}…`);
758
- const r = spawnSync('make', ['build', `TAG=${tag}`], { cwd, stdio: 'inherit' });
770
+
771
+ const make = (tag, overrides, templates = {}, outputDir = 'modules/reference/', tempDir = null) => {
772
+ console.log(`⏳ Building property docs for ${tag}${tempDir ? ' (for diff)' : ''}…`);
773
+ const args = ['build', `TAG=${tag}`];
774
+
775
+ // Pass all paths as environment variables for consistency
776
+ const env = { ...process.env };
777
+ if (overrides) {
778
+ env.OVERRIDES = path.resolve(overrides);
779
+ }
780
+ if (templates.propertyPage) {
781
+ env.TEMPLATE_PROPERTY_PAGE = path.resolve(templates.propertyPage);
782
+ }
783
+ if (templates.property) {
784
+ env.TEMPLATE_PROPERTY = path.resolve(templates.property);
785
+ }
786
+ if (templates.deprecated) {
787
+ env.TEMPLATE_DEPRECATED = path.resolve(templates.deprecated);
788
+ }
789
+ if (templates.deprecatedProperty) {
790
+ env.TEMPLATE_DEPRECATED_PROPERTY = path.resolve(templates.deprecatedProperty);
791
+ }
792
+
793
+ if (tempDir) {
794
+ // For diff purposes, generate to temporary directory
795
+ env.OUTPUT_ASCIIDOC_DIR = path.resolve(tempDir);
796
+ env.OUTPUT_JSON_DIR = path.resolve(tempDir, 'examples');
797
+ env.OUTPUT_AUTOGENERATED_DIR = path.resolve(tempDir);
798
+ } else {
799
+ // Normal generation - go directly to final destination
800
+ // Let Makefile calculate OUTPUT_ASCIIDOC_DIR as OUTPUT_AUTOGENERATED_DIR/pages
801
+ env.OUTPUT_JSON_DIR = path.resolve(outputDir, 'examples');
802
+ env.OUTPUT_AUTOGENERATED_DIR = path.resolve(outputDir);
803
+ }
804
+
805
+ const r = spawnSync('make', args, { cwd, stdio: 'inherit', env });
759
806
  if (r.error) {
760
807
  console.error(`❌ ${r.error.message}`);
761
808
  process.exit(1);
@@ -763,50 +810,38 @@ automation
763
810
  if (r.status !== 0) process.exit(r.status);
764
811
  };
765
812
 
766
- if (oldTag) {
767
- const oldDir = path.join('autogenerated', oldTag, 'properties');
768
- if (!fs.existsSync(oldDir)) make(oldTag);
769
- }
770
-
771
- make(newTag);
772
-
773
- if (oldTag) {
774
- diffDirs('properties', oldTag, newTag);
775
- }
776
-
777
- process.exit(0);
778
- });
779
-
780
- automation
781
- .command('topic-property-docs')
782
- .description('Generate JSON and AsciiDoc documentation for Redpanda topic configuration properties')
783
- .option('--tag <tag>', 'Git tag or branch to extract from', 'dev')
784
- .option('--diff <oldTag>', 'Also diff autogenerated topic properties from <oldTag> → <tag>')
785
- .action((options) => {
786
- verifyPropertyDependencies();
787
-
788
- const newTag = options.tag;
789
- const oldTag = options.diff;
790
- const cwd = path.resolve(__dirname, '../tools/property-extractor');
791
- const make = (tag) => {
792
- console.log(`⏳ Building topic property docs for ${tag}…`);
793
- const r = spawnSync('make', ['topic-properties', `TAG=${tag}`], { cwd, stdio: 'inherit' });
794
- if (r.error) {
795
- console.error(`❌ ${r.error.message}`);
796
- process.exit(1);
797
- }
798
- if (r.status !== 0) process.exit(r.status);
813
+ // Collect template options
814
+ const templates = {
815
+ propertyPage: options.templatePropertyPage,
816
+ property: options.templateProperty,
817
+ deprecated: options.templateDeprecated,
818
+ deprecatedProperty: options.templateDeprecatedProperty
799
819
  };
800
820
 
821
+ let oldTempDir = null;
822
+ let newTempDir = null;
823
+
801
824
  if (oldTag) {
802
- const oldDir = path.join('autogenerated', oldTag, 'properties');
803
- if (!fs.existsSync(oldDir)) make(oldTag);
825
+ // Generate old version to temporary directory for diff
826
+ oldTempDir = path.join('tmp', 'diff', `${oldTag}-properties`);
827
+ fs.mkdirSync(oldTempDir, { recursive: true });
828
+ make(oldTag, overridesPath, templates, outputDir, oldTempDir);
804
829
  }
805
830
 
806
- make(newTag);
807
-
808
831
  if (oldTag) {
809
- diffDirs('properties', oldTag, newTag);
832
+ // Generate new version to temporary directory for diff
833
+ newTempDir = path.join('tmp', 'diff', `${newTag}-properties`);
834
+ fs.mkdirSync(newTempDir, { recursive: true });
835
+ make(newTag, overridesPath, templates, outputDir, newTempDir);
836
+
837
+ // Then generate new version to final destination
838
+ make(newTag, overridesPath, templates, outputDir);
839
+
840
+ // Compare the temporary directories
841
+ diffDirs('properties', oldTag, newTag, oldTempDir, newTempDir);
842
+ } else {
843
+ // No diff requested, just generate to final destination
844
+ make(newTag, overridesPath, templates, outputDir);
810
845
  }
811
846
 
812
847
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redpanda-data/docs-extensions-and-macros",
3
- "version": "4.8.0",
3
+ "version": "4.8.1",
4
4
  "description": "Antora extensions and macros developed for Redpanda documentation.",
5
5
  "keywords": [
6
6
  "antora",
@@ -1,4 +1,4 @@
1
- .PHONY: build venv clean redpanda-git treesitter topic-properties generate-docs check
1
+ .PHONY: build venv clean redpanda-git treesitter generate-docs check
2
2
 
3
3
  # --- Main build: venv, fetch code, build parser, extract & docgen ---
4
4
  build: venv redpanda-git treesitter
@@ -18,11 +18,11 @@ TAG ?= dev
18
18
  # Derive a “major.minor” or rc identifier from TAG for folder naming
19
19
  VERSION := $(shell \
20
20
  if echo "$(TAG)" | grep -qE '^v?[0-9]+\.[0-9]+'; then \
21
- echo "$(TAG)" \
22
- | sed -E 's/^v?([0-9]+\.[0-9]+)(\.[0-9]+)?(-rc[0-9]+)?.*/\1\3/' \
23
- | sed 's/-rc/rc/'; \
21
+ echo "$(TAG)" \
22
+ | sed -E 's/^v?([0-9]+\.[0-9]+)(\.[0-9]+)?(-rc[0-9]+)?.*/\1\3/' \
23
+ | sed 's/-rc/rc/'; \
24
24
  else \
25
- echo "$(TAG)"; \
25
+ echo "$(TAG)"; \
26
26
  fi)
27
27
 
28
28
  # Paths
@@ -34,9 +34,33 @@ REDPANDA_SRC := $(TMP_ROOT)/redpanda
34
34
  TREESITTER_DIR:= $(TOOL_ROOT)/tree-sitter/tree-sitter-cpp
35
35
  VENV := $(TOOL_ROOT)/tmp/redpanda-property-extractor-venv
36
36
  PYTHON := $(VENV)/bin/python
37
- OUTPUT_DIR := $(REPO_ROOT)/autogenerated/$(TAG)/properties
38
37
  TREE_SITTER := npx tree-sitter
39
38
 
39
+ # Output directory configuration (can be overridden by environment variables)
40
+ OUTPUT_AUTOGENERATED_DIR ?= $(REPO_ROOT)/modules/reference
41
+ OUTPUT_ASCIIDOC_DIR ?= $(OUTPUT_AUTOGENERATED_DIR)/pages
42
+ OUTPUT_JSON_DIR ?= $(OUTPUT_AUTOGENERATED_DIR)/examples
43
+
44
+ # --- Main build: venv, fetch code, build parser, extract & docgen ---
45
+ build: venv redpanda-git treesitter
46
+ @echo "🔧 Building with Redpanda tag: $(TAG)"
47
+ @mkdir -p $(TOOL_ROOT)/gen
48
+ @if [ -n "$(OVERRIDES)" ] && [ ! -f "$(OVERRIDES)" ]; then \
49
+ echo "❌ Error: Overrides file '$(OVERRIDES)' does not exist."; \
50
+ echo " Please check the path or omit the OVERRIDES variable to continue without overrides."; \
51
+ exit 1; \
52
+ fi
53
+ @cd $(TOOL_ROOT) && \
54
+ $(PYTHON) -W ignore::FutureWarning property_extractor.py \
55
+ --recursive \
56
+ --path $(REDPANDA_SRC) \
57
+ --output gen/properties-output.json \
58
+ --enhanced-output gen/$(TAG)-properties.json \
59
+ $(if $(OVERRIDES),$(if $(shell [ -f "$(OVERRIDES)" ] && echo exists),--overrides $(OVERRIDES),),)
60
+ @echo "✅ JSON generated at $(TOOL_ROOT)/gen/properties-output.json"
61
+ @echo "✅ Enhanced JSON (with overrides) generated at $(TOOL_ROOT)/gen/$(TAG)-properties.json"
62
+ @$(MAKE) generate-docs
63
+
40
64
  # --- Ensure Python venv & dependencies ---
41
65
  venv: $(TOOL_ROOT)/requirements.txt
42
66
  @if [ ! -d "$(VENV)" ]; then \
@@ -84,34 +108,38 @@ treesitter:
84
108
  @echo "🔧 Generating parser in $(TREESITTER_DIR)…"
85
109
  @cd "$(TREESITTER_DIR)" && npm install --silent && $(TREE_SITTER) generate
86
110
 
87
- # --- Turn the JSON into AsciiDoc pages under autogen/<version>/properties ---
88
- generate-docs:
89
- @echo "📝 Generating AsciiDoc pages in $(OUTPUT_DIR)…"
90
- @mkdir -p "$(OUTPUT_DIR)"
91
- @cd $(TOOL_ROOT) && \
92
- $(PYTHON) json-to-asciidoc/generate_docs.py --output-dir "$(OUTPUT_DIR)"
93
- @echo "📄 Copying properties-output.json to $(OUTPUT_DIR)…"
94
- @cp "$(TOOL_ROOT)/gen/properties-output.json" "$(OUTPUT_DIR)/"
95
- @echo "✅ Docs generated at $(OUTPUT_DIR)"
111
+ # --- Install Node.js dependencies for Handlebars ---
112
+ node-deps:
113
+ @echo "📦 Installing Node.js dependencies…"
114
+ @cd $(TOOL_ROOT) && npm install --silent
115
+
116
+ # --- Turn the JSON into AsciiDoc pages under the specified output directories ---
117
+ generate-docs: node-deps
118
+ @echo "📝 Generating AsciiDoc pages in $(OUTPUT_ASCIIDOC_DIR)"
119
+ @mkdir -p "$(OUTPUT_ASCIIDOC_DIR)"
120
+ @mkdir -p "$(OUTPUT_JSON_DIR)"
121
+ @# Use the enhanced properties file (with overrides) for documentation generation if it exists
122
+ @if [ -f "$(TOOL_ROOT)/gen/$(TAG)-properties.json" ]; then \
123
+ cd $(TOOL_ROOT) && \
124
+ node generate-handlebars-docs.js "gen/$(TAG)-properties.json" "$(OUTPUT_AUTOGENERATED_DIR)"; \
125
+ else \
126
+ cd $(TOOL_ROOT) && \
127
+ node generate-handlebars-docs.js "gen/properties-output.json" "$(OUTPUT_AUTOGENERATED_DIR)"; \
128
+ fi
129
+ @echo "📄 Copying properties JSON files to $(OUTPUT_JSON_DIR)…"
130
+ @if [ -f "$(TOOL_ROOT)/gen/$(TAG)-properties.json" ]; then \
131
+ cp "$(TOOL_ROOT)/gen/$(TAG)-properties.json" "$(OUTPUT_JSON_DIR)/"; \
132
+ fi
133
+ @echo "✅ Docs generated at $(OUTPUT_AUTOGENERATED_DIR)"
96
134
 
97
135
  # --- Debug helper to print all the key paths/vars ---
98
136
  check:
99
- @echo "MODULE_ROOT: $(MODULE_ROOT)"
100
- @echo "TOOL_ROOT: $(TOOL_ROOT)"
101
- @echo "REDPANDA_SRC: $(REDPANDA_SRC)"
102
- @echo "TREESITTER: $(TREESITTER_DIR)"
103
- @echo "VENV: $(VENV)"
104
- @echo "PYTHON: $(PYTHON)"
105
- @echo "OUTPUT_DIR: $(OUTPUT_DIR)"
106
-
107
- # --- Extract topic properties ---
108
- topic-properties: venv redpanda-git treesitter
109
- @echo "🔧 Extracting topic properties with Redpanda tag: $(TAG)"
110
- @mkdir -p $(TOOL_ROOT)/gen
111
- @mkdir -p "$(OUTPUT_DIR)"
112
- @cd $(TOOL_ROOT) && \
113
- $(PYTHON) topic_property_extractor.py \
114
- --source-path $(REDPANDA_SRC) \
115
- --output-json "$(OUTPUT_DIR)/topic-properties-output.json" \
116
- --output-adoc "$(OUTPUT_DIR)/topic-properties.adoc"
117
- @echo "✅ Topic properties extracted"
137
+ @echo "MODULE_ROOT: $(MODULE_ROOT)"
138
+ @echo "TOOL_ROOT: $(TOOL_ROOT)"
139
+ @echo "REDPANDA_SRC: $(REDPANDA_SRC)"
140
+ @echo "TREESITTER: $(TREESITTER_DIR)"
141
+ @echo "VENV: $(VENV)"
142
+ @echo "PYTHON: $(PYTHON)"
143
+ @echo "OUTPUT_ASCIIDOC_DIR: $(OUTPUT_ASCIIDOC_DIR)"
144
+ @echo "OUTPUT_JSON_DIR: $(OUTPUT_JSON_DIR)"
145
+ @echo "OUTPUT_AUTOGENERATED_DIR: $(OUTPUT_AUTOGENERATED_DIR)"