@redpanda-data/docs-extensions-and-macros 4.6.2 → 4.6.4

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/bin/doc-tools.js CHANGED
@@ -485,7 +485,16 @@ automation
485
485
  .option('--template-examples <path>', 'Examples section partial template', path.resolve(__dirname, '../tools/redpanda-connect/templates/examples-partials.hbs'))
486
486
  .option('--overrides <path>', 'Optional JSON file with overrides')
487
487
  .action(async (options) => {
488
- let success = true;
488
+ requireTool('rpk', {
489
+ versionFlag: '--version',
490
+ help: 'rpk is not installed. Install rpk: https://docs.redpanda.com/current/get-started/rpk-install/'
491
+ });
492
+
493
+ requireTool('rpk connect', {
494
+ versionFlag: '--version',
495
+ help: 'rpk connect is not installed. Run rpk connect install before continuing.'
496
+ });
497
+
489
498
  const dataDir = path.resolve(process.cwd(), options.dataDir);
490
499
  fs.mkdirSync(dataDir, { recursive: true });
491
500
 
@@ -495,7 +504,6 @@ automation
495
504
  let dataFile;
496
505
  if (options.fetchConnectors) {
497
506
  try {
498
- execSync('rpk --version', { stdio: 'ignore' });
499
507
  newVersion = getRpkConnectVersion();
500
508
  const tmpFile = path.join(dataDir, `connect-${newVersion}.tmp.json`);
501
509
  const finalFile = path.join(dataDir, `connect-${newVersion}.json`);
@@ -512,7 +520,7 @@ automation
512
520
  console.log(`✅ Fetched and saved: ${finalFile}`);
513
521
  } catch (err) {
514
522
  console.error(`❌ Failed to fetch connectors: ${err.message}`);
515
- success = false;
523
+ process.exit(1);
516
524
  }
517
525
  } else {
518
526
  const candidates = fs.readdirSync(dataDir).filter(f => /^connect-\d+\.\d+\.\d+\.json$/.test(f));
@@ -542,7 +550,7 @@ automation
542
550
  partialFiles = result.partialFiles;
543
551
  } catch (err) {
544
552
  console.error(`❌ Failed to generate partials: ${err.message}`);
545
- success = false;
553
+ process.exit(1);
546
554
  }
547
555
 
548
556
  if (options.draftMissing) {
@@ -613,7 +621,7 @@ automation
613
621
  }
614
622
  } catch (err) {
615
623
  console.error(`❌ Could not draft missing: ${err.message}`);
616
- success = false;
624
+ process.exit(1);
617
625
  }
618
626
  }
619
627
 
@@ -667,8 +675,7 @@ automation
667
675
  console.log('\n📄 Summary:');
668
676
  console.log(` • Run time: ${timestamp}`);
669
677
  console.log(` • Version used: ${newVersion}`);
670
-
671
- process.exit(success ? 0 : 1);
678
+ process.exit(0);
672
679
  });
673
680
 
674
681
  automation
@@ -115,40 +115,58 @@ module.exports.register = function ({ config }) {
115
115
  let redpandaConnectUrl = '';
116
116
  let redpandaCloudUrl = '';
117
117
 
118
+ function isConnectorDocPath (filePath, type) {
119
+ const dirsToCheck = [
120
+ `pages/${type}s/`,
121
+ `partials/components/${type}s/`
122
+ ];
123
+ return dirsToCheck.some(dir => filePath.includes(dir));
124
+ }
125
+
126
+ function isCloudDoc(file, connector, type) {
127
+ return (
128
+ file.src.component === 'redpanda-cloud' &&
129
+ file.path.includes(`connect/components/${type}s/${connector}.adoc`)
130
+ );
131
+ }
132
+
118
133
  // Look for both Redpanda Connect and Cloud URLs
119
134
  for (const file of pages) {
120
- const component = file.src.component;
121
- const filePath = file.path;
135
+ const { component } = file.src; // such as 'redpanda-connect'
136
+ const { path: filePath } = file; // such as modules/.../pages/sinks/foo.adoc
122
137
 
123
138
  if (
124
139
  component === 'redpanda-connect' &&
125
140
  filePath.endsWith(`/${connector}.adoc`) &&
126
- filePath.includes(`pages/${type}s/`)
141
+ isConnectorDocPath(filePath, type)
127
142
  ) {
128
143
  redpandaConnectUrl = file.pub.url;
129
144
  }
130
145
 
131
- // Only check for Redpanda Cloud URLs if cloud is supported
132
- if (
133
- is_cloud_supported === 'y' &&
134
- component === 'redpanda-cloud' &&
135
- filePath.endsWith(`/${connector}.adoc`) &&
136
- filePath.includes(`${type}s/`)
137
- ) {
146
+ // -------------------------------------------------
147
+ // Redpanda Cloud (only if cloud supported)
148
+ // -------------------------------------------------
149
+ if (is_cloud_supported === 'y' && isCloudDoc(file, connector, type)) {
138
150
  redpandaCloudUrl = file.pub.url;
139
151
  }
140
152
  }
141
153
 
142
- // Log a warning if neither URL was found and the component is not deprecated
143
154
  if (
144
155
  deprecated !== 'y' &&
145
156
  !connector.includes('sql_driver') &&
146
157
  !redpandaConnectUrl &&
147
- (!redpandaCloudUrl && is_cloud_supported === 'y')
158
+ !(is_cloud_supported === 'y' && redpandaCloudUrl)
148
159
  ) {
149
- logger.warn(`Docs missing for: ${connector} of type: ${type}`);
160
+ logger.warn(`Self-Managed docs missing for: ${connector} of type: ${type}`);
150
161
  }
151
162
 
163
+ if (
164
+ is_cloud_supported === 'y' &&
165
+ !redpandaCloudUrl &&
166
+ redpandaConnectUrl
167
+ ) {
168
+ logger.warn(`Cloud docs missing for: ${connector} of type: ${type}`);
169
+ }
152
170
 
153
171
  // Return the translated and enriched row
154
172
  return {
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ module.exports.register = function (registry) {
4
+ registry.inlineMacro(function () {
5
+ const self = this;
6
+ self.named('badge');
7
+ self.process((parent, target, attrs) => {
8
+ const label = attrs.label || 'label';
9
+ const className = `badge--${label.toLowerCase().replace(/\s+/g, '-')}`;
10
+ const isLarge = attrs.size === 'large';
11
+ const sizeClass = isLarge ? 'badge--large' : '';
12
+ const tooltip = attrs.tooltip;
13
+ const tooltipAttr = tooltip ? ` data-tooltip="${tooltip}"` : '';
14
+
15
+ // Add brackets if not large
16
+ const renderedLabel = isLarge ? label : `(${label})`;
17
+
18
+ return `<span class="badge ${className} ${sizeClass}"${tooltipAttr}>${renderedLabel}</span>`;
19
+ });
20
+ });
21
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redpanda-data/docs-extensions-and-macros",
3
- "version": "4.6.2",
3
+ "version": "4.6.4",
4
4
  "description": "Antora extensions and macros developed for Redpanda documentation.",
5
5
  "keywords": [
6
6
  "antora",
@@ -57,7 +57,8 @@
57
57
  "./macros/glossary": "./macros/glossary.js",
58
58
  "./macros/rp-connect-components": "./macros/rp-connect-components.js",
59
59
  "./macros/config-ref": "./macros/config-ref.js",
60
- "./macros/helm-ref": "./macros/helm-ref.js"
60
+ "./macros/helm-ref": "./macros/helm-ref.js",
61
+ "./macros/badge": "./macros/badge.js"
61
62
  },
62
63
  "files": [
63
64
  "extensions",
@@ -35,47 +35,99 @@ function registerPartial(name, filePath) {
35
35
 
36
36
  /**
37
37
  * Deep-merge `overrides` into `target`. Only 'description', 'type',
38
- * plus nested array/object entries get overridden; other keys remain intact.
38
+ * 'annotated_field', 'examples', and known nested fields are overridden.
39
39
  */
40
40
  function mergeOverrides(target, overrides) {
41
41
  if (!overrides || typeof overrides !== 'object') return target;
42
42
  if (!target || typeof target !== 'object') {
43
43
  throw new Error('Target must be a valid object');
44
44
  }
45
+
46
+ const scalarKeys = ['description', 'type', 'annotated_field', 'version'];
47
+
45
48
  for (const key in overrides) {
49
+ // === Handle annotated_options ===
50
+ if (key === 'annotated_options' && Array.isArray(overrides[key]) && Array.isArray(target[key])) {
51
+ const overrideMap = new Map(overrides[key].map(([name, desc]) => [name, desc]));
52
+
53
+ target[key] = target[key].map(([name, desc]) => {
54
+ if (overrideMap.has(name)) {
55
+ return [name, overrideMap.get(name)];
56
+ }
57
+ return [name, desc];
58
+ });
59
+
60
+ const existingNames = new Set(target[key].map(([name]) => name));
61
+ for (const [name, desc] of overrides[key]) {
62
+ if (!existingNames.has(name)) {
63
+ target[key].push([name, desc]);
64
+ }
65
+ }
66
+ continue;
67
+ }
68
+
69
+ // === Handle examples ===
70
+ if (key === 'examples' && Array.isArray(overrides[key]) && Array.isArray(target[key])) {
71
+ const overrideMap = new Map(overrides[key].map(o => [o.title, o]));
72
+
73
+ target[key] = target[key].map(example => {
74
+ const override = overrideMap.get(example.title);
75
+ if (override) {
76
+ return {
77
+ ...example,
78
+ ...(override.summary && { summary: override.summary }),
79
+ ...(override.config && { config: override.config }),
80
+ };
81
+ }
82
+ return example;
83
+ });
84
+
85
+ const existingTitles = new Set(target[key].map(e => e.title));
86
+ for (const example of overrides[key]) {
87
+ if (!existingTitles.has(example.title)) {
88
+ target[key].push(example);
89
+ }
90
+ }
91
+ continue;
92
+ }
93
+
94
+ // === Merge arrays of objects with .name ===
46
95
  if (Array.isArray(target[key]) && Array.isArray(overrides[key])) {
47
- // Merge two parallel arrays by matching items on `.name`
48
96
  target[key] = target[key].map(item => {
49
97
  const overrideItem = overrides[key].find(o => o.name === item.name);
50
98
  if (overrideItem) {
51
- // Overwrite description/type if present
52
- ['description', 'type'].forEach(field => {
99
+ scalarKeys.forEach(field => {
53
100
  if (Object.hasOwn(overrideItem, field)) {
54
101
  item[field] = overrideItem[field];
55
102
  }
56
103
  });
57
- // Copy through selfManagedOnly flag
58
104
  if (Object.hasOwn(overrideItem, 'selfManagedOnly')) {
59
105
  item.selfManagedOnly = overrideItem.selfManagedOnly;
60
106
  }
61
- // Recurse for nested children
62
- item = mergeOverrides(item, overrideItem);
107
+ return mergeOverrides(item, overrideItem);
63
108
  }
64
109
  return item;
65
110
  });
66
- } else if (
111
+ continue;
112
+ }
113
+
114
+ // === Merge nested objects ===
115
+ if (
67
116
  typeof target[key] === 'object' &&
68
117
  typeof overrides[key] === 'object' &&
69
118
  !Array.isArray(target[key]) &&
70
119
  !Array.isArray(overrides[key])
71
120
  ) {
72
- // Deep-merge plain objects
73
121
  target[key] = mergeOverrides(target[key], overrides[key]);
74
- } else if (['description', 'type'].includes(key) && Object.hasOwn(overrides, key)) {
75
- // Overwrite the primitive
122
+ continue;
123
+ }
124
+
125
+ // === Overwrite scalar keys ===
126
+ if (scalarKeys.includes(key) && Object.hasOwn(overrides, key)) {
76
127
  target[key] = overrides[key];
77
128
  }
78
129
  }
130
+
79
131
  return target;
80
132
  }
81
133
 
@@ -1,11 +0,0 @@
1
- 'use strict';
2
-
3
- module.exports.register = function (registry) {
4
- registry.inlineMacro(function () {
5
- const self = this;
6
- self.named('enterprise-label');
7
- self.process((parent, target, attrs) => {
8
- return `<span class="inline-enterprise-label">Enterprise</span>`;
9
- });
10
- });
11
- };