@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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
121
|
-
const filePath = file.
|
|
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
|
|
141
|
+
isConnectorDocPath(filePath, type)
|
|
127
142
|
) {
|
|
128
143
|
redpandaConnectUrl = file.pub.url;
|
|
129
144
|
}
|
|
130
145
|
|
|
131
|
-
//
|
|
132
|
-
if
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
(
|
|
158
|
+
!(is_cloud_supported === 'y' && redpandaCloudUrl)
|
|
148
159
|
) {
|
|
149
|
-
logger.warn(`
|
|
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 {
|
package/macros/badge.js
ADDED
|
@@ -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.
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
62
|
-
item = mergeOverrides(item, overrideItem);
|
|
107
|
+
return mergeOverrides(item, overrideItem);
|
|
63
108
|
}
|
|
64
109
|
return item;
|
|
65
110
|
});
|
|
66
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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
|
-
};
|