@redpanda-data/docs-extensions-and-macros 4.10.3 → 4.10.5
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 +92 -99
- package/package.json +1 -1
- package/tools/property-extractor/compare-properties.js +4 -4
- package/tools/property-extractor/generate-handlebars-docs.js +133 -442
- package/tools/property-extractor/helpers/anchorName.js +7 -0
- package/tools/property-extractor/helpers/index.js +1 -0
- package/tools/property-extractor/property_extractor.py +62 -2
- package/tools/property-extractor/templates/deprecated-property.hbs +1 -7
- package/tools/property-extractor/templates/property.hbs +55 -17
- package/tools/property-extractor/templates/topic-property-mappings.hbs +13 -0
- package/tools/property-extractor/templates/topic-property.hbs +41 -2
- package/tools/redpanda-connect/templates/examples-partials.hbs +1 -1
- package/tools/property-extractor/templates/property-cloud.hbs +0 -100
- package/tools/property-extractor/templates/property-page-with-includes.hbs +0 -17
- package/tools/property-extractor/templates/property-page.hbs +0 -22
- package/tools/property-extractor/templates/topic-property-cloud.hbs +0 -94
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const AUTOGEN_NOTICE = '// This content is autogenerated. Do not edit manually. To override descriptions, use the doc-tools CLI with the --overrides option: https://redpandadata.atlassian.net/wiki/spaces/DOC/pages/1396244485/Review+Redpanda+configuration+properties\n';
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
const fs = require('fs');
|
|
@@ -7,14 +8,17 @@ const helpers = require('./helpers');
|
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Handlebars documentation generator for Redpanda configuration properties.
|
|
10
|
-
*
|
|
11
|
+
*
|
|
11
12
|
* Supports custom template overrides using environment variables:
|
|
12
|
-
* -
|
|
13
|
-
* - TEMPLATE_PROPERTY: Individual property section template
|
|
13
|
+
* - TEMPLATE_PROPERTY: Individual property section template
|
|
14
14
|
* - TEMPLATE_TOPIC_PROPERTY: Individual topic property section template
|
|
15
15
|
* - TEMPLATE_DEPRECATED_PROPERTY: Individual deprecated property section template
|
|
16
16
|
* - TEMPLATE_DEPRECATED: Deprecated properties page template
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
|
+
* Behavior flags (environment variables):
|
|
19
|
+
* - GENERATE_PARTIALS=1 Generate consolidated property partials and deprecated partials
|
|
20
|
+
* - OUTPUT_PARTIALS_DIR=<p> Destination for consolidated partials (required if GENERATE_PARTIALS=1)
|
|
21
|
+
*
|
|
18
22
|
* CLI Usage: node generate-handlebars-docs.js <input-file> <output-dir>
|
|
19
23
|
*/
|
|
20
24
|
|
|
@@ -44,81 +48,6 @@ function isObjectStorageProperty(prop) {
|
|
|
44
48
|
);
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
/**
|
|
48
|
-
* Configuration mapping for different property types
|
|
49
|
-
*/
|
|
50
|
-
const PROPERTY_CONFIG = {
|
|
51
|
-
broker: {
|
|
52
|
-
pageTitle: 'Broker Configuration Properties',
|
|
53
|
-
pageAliases: ['reference:node-properties.adoc', 'reference:node-configuration-sample.adoc'],
|
|
54
|
-
description: 'Reference of broker configuration properties.',
|
|
55
|
-
intro: `Broker configuration properties are applied individually to each broker in a cluster. You can find and modify these properties in the \`redpanda.yaml\` configuration file.
|
|
56
|
-
|
|
57
|
-
For information on how to edit broker properties, see xref:manage:cluster-maintenance/node-property-configuration.adoc[].
|
|
58
|
-
|
|
59
|
-
NOTE: All broker properties require that you restart Redpanda for any update to take effect.`,
|
|
60
|
-
sectionTitle: 'Broker configuration',
|
|
61
|
-
groups: [
|
|
62
|
-
{
|
|
63
|
-
filter: (prop) => prop.config_scope === 'broker' && !prop.is_deprecated
|
|
64
|
-
}
|
|
65
|
-
],
|
|
66
|
-
filename: 'broker-properties.adoc'
|
|
67
|
-
},
|
|
68
|
-
cluster: {
|
|
69
|
-
pageTitle: 'Cluster Configuration Properties',
|
|
70
|
-
pageAliases: ['reference:tunable-properties.adoc', 'reference:cluster-properties.adoc'],
|
|
71
|
-
description: 'Cluster configuration properties list.',
|
|
72
|
-
intro: `Cluster configuration properties are the same for all brokers in a cluster, and are set at the cluster level.
|
|
73
|
-
|
|
74
|
-
For information on how to edit cluster properties, see xref:manage:cluster-maintenance/cluster-property-configuration.adoc[] or xref:manage:kubernetes/k-cluster-property-configuration.adoc[].
|
|
75
|
-
|
|
76
|
-
NOTE: Some cluster properties require that you restart the cluster for any updates to take effect. See the specific property details to identify whether or not a restart is required.`,
|
|
77
|
-
sectionTitle: 'Cluster configuration',
|
|
78
|
-
groups: [
|
|
79
|
-
{
|
|
80
|
-
filter: (prop) => prop.config_scope === 'cluster' && !prop.is_deprecated && !isObjectStorageProperty(prop)
|
|
81
|
-
}
|
|
82
|
-
],
|
|
83
|
-
filename: 'cluster-properties.adoc'
|
|
84
|
-
},
|
|
85
|
-
'object-storage': {
|
|
86
|
-
pageTitle: 'Object Storage Properties',
|
|
87
|
-
description: 'Reference of object storage properties.',
|
|
88
|
-
intro: `Object storage properties are a type of cluster property. For information on how to edit cluster properties, see xref:manage:cluster-maintenance/cluster-property-configuration.adoc[].
|
|
89
|
-
|
|
90
|
-
NOTE: Some object storage properties require that you restart the cluster for any updates to take effect. See the specific property details to identify whether or not a restart is required.`,
|
|
91
|
-
sectionTitle: 'Object storage configuration',
|
|
92
|
-
sectionIntro: 'Object storage properties should only be set if you enable xref:manage:tiered-storage.adoc[Tiered Storage].',
|
|
93
|
-
groups: [
|
|
94
|
-
{
|
|
95
|
-
filter: (prop) => isObjectStorageProperty(prop) && !prop.is_deprecated
|
|
96
|
-
}
|
|
97
|
-
],
|
|
98
|
-
filename: 'object-storage-properties.adoc'
|
|
99
|
-
},
|
|
100
|
-
topic: {
|
|
101
|
-
pageTitle: 'Topic Configuration Properties',
|
|
102
|
-
pageAliases: ['reference:topic-properties.adoc'],
|
|
103
|
-
description: 'Reference of topic configuration properties.',
|
|
104
|
-
intro: `A topic-level property sets a Redpanda or Kafka configuration for a particular topic.
|
|
105
|
-
|
|
106
|
-
Many topic-level properties have corresponding xref:manage:cluster-maintenance/cluster-property-configuration.adoc[cluster properties] that set a default value for all topics of a cluster. To customize the value for a topic, you can set a topic-level property that overrides the value of the corresponding cluster property.
|
|
107
|
-
|
|
108
|
-
NOTE: All topic properties take effect immediately after being set.`,
|
|
109
|
-
sectionTitle: 'Topic configuration',
|
|
110
|
-
groups: [
|
|
111
|
-
{
|
|
112
|
-
filter: (prop) => prop.config_scope === 'topic' && !prop.is_deprecated,
|
|
113
|
-
template: 'topic-property'
|
|
114
|
-
}
|
|
115
|
-
],
|
|
116
|
-
filename: 'topic-properties.adoc'
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// "src/v/kafka/server/handlers/topics/types.cc": "topic"
|
|
121
|
-
|
|
122
51
|
/**
|
|
123
52
|
* Gets template path, checking environment variables for custom paths first
|
|
124
53
|
*/
|
|
@@ -134,251 +63,99 @@ function getTemplatePath(defaultPath, envVar) {
|
|
|
134
63
|
/**
|
|
135
64
|
* Register Handlebars partials used to render property documentation.
|
|
136
65
|
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* - "property"
|
|
140
|
-
* - "topic-property" (uses cloud-aware `topic-property-cloud.hbs` when enabled)
|
|
66
|
+
* Registers:
|
|
67
|
+
* - "property"
|
|
68
|
+
* - "topic-property"
|
|
141
69
|
* - "deprecated-property"
|
|
142
|
-
*
|
|
143
|
-
* @param {boolean} [hasCloudSupport=false] - If true, select cloud-aware templates for the `property` and `topic-property` partials.
|
|
144
|
-
* @throws {Error} If any required template file is missing or cannot be read; errors are rethrown after logging.
|
|
145
70
|
*/
|
|
146
|
-
function registerPartials(
|
|
71
|
+
function registerPartials() {
|
|
147
72
|
const templatesDir = path.join(__dirname, 'templates');
|
|
148
|
-
|
|
73
|
+
|
|
149
74
|
try {
|
|
150
|
-
console.log(
|
|
151
|
-
|
|
152
|
-
// Register property partial (choose cloud or regular version)
|
|
153
|
-
const propertyTemplateFile = hasCloudSupport ? 'property-cloud.hbs' : 'property.hbs';
|
|
75
|
+
console.log('📝 Registering Handlebars templates');
|
|
76
|
+
|
|
154
77
|
const propertyTemplatePath = getTemplatePath(
|
|
155
|
-
path.join(templatesDir,
|
|
78
|
+
path.join(templatesDir, 'property.hbs'),
|
|
156
79
|
'TEMPLATE_PROPERTY'
|
|
157
80
|
);
|
|
158
|
-
|
|
159
81
|
if (!fs.existsSync(propertyTemplatePath)) {
|
|
160
82
|
throw new Error(`Property template not found: ${propertyTemplatePath}`);
|
|
161
83
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
handlebars.registerPartial('property', propertyTemplate);
|
|
165
|
-
console.log(`✅ Registered property template: ${propertyTemplateFile}`);
|
|
166
|
-
|
|
167
|
-
// Register topic property partial (choose cloud or regular version)
|
|
168
|
-
const topicPropertyTemplateFile = hasCloudSupport ? 'topic-property-cloud.hbs' : 'topic-property.hbs';
|
|
84
|
+
handlebars.registerPartial('property', fs.readFileSync(propertyTemplatePath, 'utf8'));
|
|
85
|
+
|
|
169
86
|
const topicPropertyTemplatePath = getTemplatePath(
|
|
170
|
-
path.join(templatesDir,
|
|
87
|
+
path.join(templatesDir, 'topic-property.hbs'),
|
|
171
88
|
'TEMPLATE_TOPIC_PROPERTY'
|
|
172
89
|
);
|
|
173
|
-
|
|
174
90
|
if (!fs.existsSync(topicPropertyTemplatePath)) {
|
|
175
91
|
throw new Error(`Topic property template not found: ${topicPropertyTemplatePath}`);
|
|
176
92
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
handlebars.registerPartial('topic-property', topicPropertyTemplate);
|
|
180
|
-
console.log(`✅ Registered topic property template: ${topicPropertyTemplateFile}`);
|
|
181
|
-
|
|
182
|
-
// Register deprecated property partial
|
|
93
|
+
handlebars.registerPartial('topic-property', fs.readFileSync(topicPropertyTemplatePath, 'utf8'));
|
|
94
|
+
|
|
183
95
|
const deprecatedPropertyTemplatePath = getTemplatePath(
|
|
184
96
|
path.join(templatesDir, 'deprecated-property.hbs'),
|
|
185
97
|
'TEMPLATE_DEPRECATED_PROPERTY'
|
|
186
98
|
);
|
|
187
|
-
|
|
188
99
|
if (!fs.existsSync(deprecatedPropertyTemplatePath)) {
|
|
189
100
|
throw new Error(`Deprecated property template not found: ${deprecatedPropertyTemplatePath}`);
|
|
190
101
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
console.log(`✅ Registered deprecated property template`);
|
|
195
|
-
|
|
102
|
+
handlebars.registerPartial('deprecated-property', fs.readFileSync(deprecatedPropertyTemplatePath, 'utf8'));
|
|
103
|
+
|
|
104
|
+
console.log('✅ Registered all partials');
|
|
196
105
|
} catch (error) {
|
|
197
106
|
console.error('❌ Failed to register Handlebars templates:');
|
|
198
|
-
console.error(`
|
|
199
|
-
console.error(' This indicates missing or corrupted template files.');
|
|
200
|
-
console.error(' Check that all .hbs files exist in tools/property-extractor/templates/');
|
|
107
|
+
console.error(` ${error.message}`);
|
|
201
108
|
throw error;
|
|
202
109
|
}
|
|
203
110
|
}
|
|
204
111
|
|
|
205
|
-
/**
|
|
206
|
-
* Generates documentation for a specific property type
|
|
207
|
-
*/
|
|
208
|
-
function generatePropertyDocs(properties, config, outputDir) {
|
|
209
|
-
// Check if partials are being generated to determine which template to use
|
|
210
|
-
const useIncludes = process.env.GENERATE_PARTIALS === '1';
|
|
211
|
-
|
|
212
|
-
let templatePath;
|
|
213
|
-
if (useIncludes) {
|
|
214
|
-
// Use the include-based template when partials are also being generated
|
|
215
|
-
templatePath = getTemplatePath(
|
|
216
|
-
path.join(__dirname, 'templates', 'property-page-with-includes.hbs'),
|
|
217
|
-
'TEMPLATE_PROPERTY_PAGE_WITH_INCLUDES'
|
|
218
|
-
);
|
|
219
|
-
} else {
|
|
220
|
-
// Use the standard template for full content
|
|
221
|
-
templatePath = getTemplatePath(
|
|
222
|
-
path.join(__dirname, 'templates', 'property-page.hbs'),
|
|
223
|
-
'TEMPLATE_PROPERTY_PAGE'
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const template = handlebars.compile(fs.readFileSync(templatePath, 'utf8'));
|
|
228
|
-
|
|
229
|
-
if (useIncludes) {
|
|
230
|
-
// For include-based pages, we need minimal data - just page metadata and filename for include
|
|
231
|
-
const data = {
|
|
232
|
-
...config,
|
|
233
|
-
filename: config.filename.replace('.adoc', '') // Remove .adoc extension for include
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const output = template(data);
|
|
237
|
-
const outputPath = path.join(outputDir, config.filename);
|
|
238
|
-
|
|
239
|
-
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
240
|
-
fs.writeFileSync(outputPath, output, 'utf8');
|
|
241
|
-
|
|
242
|
-
console.log(`✅ Generated include-based page ${outputPath}`);
|
|
243
|
-
|
|
244
|
-
// Count properties for this type
|
|
245
|
-
const typeCount = Object.values(properties).filter(prop => {
|
|
246
|
-
return config.groups.some(group => group.filter(prop));
|
|
247
|
-
}).length;
|
|
248
|
-
|
|
249
|
-
return typeCount;
|
|
250
|
-
} else {
|
|
251
|
-
// Filter and group properties according to configuration
|
|
252
|
-
const groups = config.groups.map(group => {
|
|
253
|
-
const filteredProperties = Object.values(properties)
|
|
254
|
-
.filter(prop => group.filter(prop))
|
|
255
|
-
.sort((a, b) => String(a.name || '').localeCompare(String(b.name || '')));
|
|
256
|
-
|
|
257
|
-
return {
|
|
258
|
-
title: group.title,
|
|
259
|
-
intro: group.intro,
|
|
260
|
-
properties: filteredProperties,
|
|
261
|
-
template: group.template || 'property' // Default to 'property' template
|
|
262
|
-
};
|
|
263
|
-
}).filter(group => group.properties.length > 0);
|
|
264
|
-
|
|
265
|
-
const data = {
|
|
266
|
-
...config,
|
|
267
|
-
groups
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const output = template(data);
|
|
271
|
-
const outputPath = path.join(outputDir, config.filename);
|
|
272
|
-
|
|
273
|
-
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
274
|
-
fs.writeFileSync(outputPath, output, 'utf8');
|
|
275
|
-
|
|
276
|
-
console.log(`✅ Generated full content page ${outputPath}`);
|
|
277
|
-
return groups.reduce((total, group) => total + group.properties.length, 0);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
112
|
/**
|
|
282
113
|
* Generate consolidated AsciiDoc partials for properties grouped by type.
|
|
283
|
-
*
|
|
284
|
-
* Creates separate .adoc files for each property type (cluster-properties.adoc,
|
|
285
|
-
* topic-properties.adoc, object-storage-properties.adoc, broker-properties.adoc)
|
|
286
|
-
* containing all properties of that type using the appropriate templates.
|
|
287
|
-
*
|
|
288
|
-
* @param {Object} properties - Map of properties (property name → property object).
|
|
289
|
-
* @param {string} partialsDir - Directory where consolidated property files will be written.
|
|
290
|
-
* @param {boolean} [hasCloudSupport=false] - If true, use cloud-aware templates.
|
|
291
|
-
* @returns {number} The total number of properties included in the consolidated partials.
|
|
292
114
|
*/
|
|
293
|
-
function generatePropertyPartials(properties, partialsDir
|
|
115
|
+
function generatePropertyPartials(properties, partialsDir) {
|
|
294
116
|
console.log(`📝 Generating consolidated property partials in ${partialsDir}…`);
|
|
295
|
-
|
|
296
|
-
// Use the appropriate template based on cloud support
|
|
297
|
-
const templateName = hasCloudSupport ? 'property-cloud' : 'property';
|
|
298
|
-
const templatePath = getTemplatePath(
|
|
299
|
-
path.join(__dirname, 'templates', `${templateName}.hbs`),
|
|
300
|
-
'TEMPLATE_PROPERTY'
|
|
301
|
-
);
|
|
302
|
-
const template = handlebars.compile(fs.readFileSync(templatePath, 'utf8'));
|
|
303
117
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
'TEMPLATE_TOPIC_PROPERTY'
|
|
118
|
+
const propertyTemplate = handlebars.compile(
|
|
119
|
+
fs.readFileSync(getTemplatePath(path.join(__dirname, 'templates', 'property.hbs'), 'TEMPLATE_PROPERTY'), 'utf8')
|
|
120
|
+
);
|
|
121
|
+
const topicTemplate = handlebars.compile(
|
|
122
|
+
fs.readFileSync(getTemplatePath(path.join(__dirname, 'templates', 'topic-property.hbs'), 'TEMPLATE_TOPIC_PROPERTY'), 'utf8')
|
|
309
123
|
);
|
|
310
|
-
const topicTemplate = handlebars.compile(fs.readFileSync(topicTemplatePath, 'utf8'));
|
|
311
124
|
|
|
312
|
-
// Create the main partials directory
|
|
313
125
|
const propertiesPartialsDir = path.join(partialsDir, 'properties');
|
|
314
126
|
fs.mkdirSync(propertiesPartialsDir, { recursive: true });
|
|
315
|
-
|
|
316
|
-
// Group properties by type
|
|
317
|
-
const propertyGroups = {
|
|
318
|
-
cluster: [],
|
|
319
|
-
topic: [],
|
|
320
|
-
broker: [],
|
|
321
|
-
'object-storage': []
|
|
322
|
-
};
|
|
323
127
|
|
|
324
|
-
|
|
128
|
+
const propertyGroups = { cluster: [], topic: [], broker: [], 'object-storage': [] };
|
|
129
|
+
|
|
325
130
|
Object.values(properties).forEach(prop => {
|
|
326
|
-
if (!prop.name || !prop.config_scope) return;
|
|
327
|
-
|
|
328
|
-
if (prop.config_scope === '
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
propertyGroups.
|
|
332
|
-
} else if (prop.config_scope === 'cluster') {
|
|
333
|
-
// Check if it's an object storage property
|
|
334
|
-
if (isObjectStorageProperty(prop)) {
|
|
335
|
-
propertyGroups['object-storage'].push(prop);
|
|
336
|
-
} else {
|
|
337
|
-
propertyGroups.cluster.push(prop);
|
|
338
|
-
}
|
|
131
|
+
if (!prop.name || !prop.config_scope) return;
|
|
132
|
+
if (prop.config_scope === 'topic') propertyGroups.topic.push(prop);
|
|
133
|
+
else if (prop.config_scope === 'broker') propertyGroups.broker.push(prop);
|
|
134
|
+
else if (prop.config_scope === 'cluster') {
|
|
135
|
+
if (isObjectStorageProperty(prop)) propertyGroups['object-storage'].push(prop);
|
|
136
|
+
else propertyGroups.cluster.push(prop);
|
|
339
137
|
}
|
|
340
138
|
});
|
|
341
139
|
|
|
342
140
|
let totalCount = 0;
|
|
343
|
-
|
|
344
|
-
// Generate consolidated partials for each property type
|
|
141
|
+
|
|
345
142
|
Object.entries(propertyGroups).forEach(([type, props]) => {
|
|
346
143
|
if (props.length === 0) return;
|
|
347
|
-
|
|
348
|
-
// Sort properties by name
|
|
349
144
|
props.sort((a, b) => String(a.name || '').localeCompare(String(b.name || '')));
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const selectedTemplate = type === 'topic' ? topicTemplate : template;
|
|
353
|
-
|
|
354
|
-
// Generate content for all properties of this type
|
|
355
|
-
const content = props.map(prop => selectedTemplate(prop)).join('\n');
|
|
356
|
-
|
|
357
|
-
// Write the consolidated file
|
|
145
|
+
const selectedTemplate = type === 'topic' ? topicTemplate : propertyTemplate;
|
|
146
|
+
const content = props.map(p => selectedTemplate(p)).join('\n');
|
|
358
147
|
const filename = `${type}-properties.adoc`;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
console.log(`✅ Generated ${outputPath} with ${props.length} properties`);
|
|
148
|
+
fs.writeFileSync(path.join(propertiesPartialsDir, filename), AUTOGEN_NOTICE + content, 'utf8');
|
|
149
|
+
console.log(`✅ Generated ${filename} (${props.length} properties)`);
|
|
363
150
|
totalCount += props.length;
|
|
364
151
|
});
|
|
365
|
-
|
|
366
|
-
console.log(`✅
|
|
152
|
+
|
|
153
|
+
console.log(`✅ Done. ${totalCount} total properties.`);
|
|
367
154
|
return totalCount;
|
|
368
155
|
}
|
|
369
156
|
|
|
370
157
|
/**
|
|
371
|
-
* Generate
|
|
372
|
-
*
|
|
373
|
-
* Scans the provided properties map for entries with `is_deprecated === true`, groups
|
|
374
|
-
* them by `config_scope` ("broker" and "cluster"), sorts each group by property name,
|
|
375
|
-
* renders the `deprecated-properties` Handlebars template, and writes the output to
|
|
376
|
-
* `<outputDir>/deprecated/partials/deprecated-properties.adoc`.
|
|
377
|
-
*
|
|
378
|
-
* @param {Object.<string, Object>} properties - Map of property objects keyed by property name.
|
|
379
|
-
* Each property object may contain `is_deprecated`, `config_scope`, and `name` fields.
|
|
380
|
-
* @param {string} outputDir - Destination directory where the deprecated fragment will be written.
|
|
381
|
-
* @returns {number} The total number of deprecated properties found and written.
|
|
158
|
+
* Generate deprecated properties documentation.
|
|
382
159
|
*/
|
|
383
160
|
function generateDeprecatedDocs(properties, outputDir) {
|
|
384
161
|
const templatePath = getTemplatePath(
|
|
@@ -387,220 +164,135 @@ function generateDeprecatedDocs(properties, outputDir) {
|
|
|
387
164
|
);
|
|
388
165
|
const template = handlebars.compile(fs.readFileSync(templatePath, 'utf8'));
|
|
389
166
|
|
|
390
|
-
const deprecatedProperties = Object.values(properties).filter(
|
|
391
|
-
|
|
167
|
+
const deprecatedProperties = Object.values(properties).filter(p => p.is_deprecated);
|
|
392
168
|
const brokerProperties = deprecatedProperties
|
|
393
|
-
.filter(
|
|
394
|
-
.sort((a, b) =>
|
|
395
|
-
|
|
169
|
+
.filter(p => p.config_scope === 'broker')
|
|
170
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
396
171
|
const clusterProperties = deprecatedProperties
|
|
397
|
-
.filter(
|
|
398
|
-
.sort((a, b) =>
|
|
172
|
+
.filter(p => p.config_scope === 'cluster')
|
|
173
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
399
174
|
|
|
400
175
|
const data = {
|
|
401
176
|
deprecated: deprecatedProperties.length > 0,
|
|
402
|
-
brokerProperties: brokerProperties.length
|
|
403
|
-
clusterProperties: clusterProperties.length
|
|
177
|
+
brokerProperties: brokerProperties.length ? brokerProperties : null,
|
|
178
|
+
clusterProperties: clusterProperties.length ? clusterProperties : null
|
|
404
179
|
};
|
|
405
180
|
|
|
406
181
|
const output = template(data);
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
// Use the explicitly set partials directory
|
|
412
|
-
outputPath = path.join(process.env.OUTPUT_PARTIALS_DIR, 'deprecated', 'deprecated-properties.adoc');
|
|
413
|
-
} else if (outputDir.includes('pages/properties')) {
|
|
414
|
-
// Fallback: Navigate back from pages/properties to reference, then into partials/deprecated
|
|
415
|
-
outputPath = path.join(path.dirname(path.dirname(outputDir)), 'partials', 'deprecated', 'deprecated-properties.adoc');
|
|
416
|
-
} else {
|
|
417
|
-
// Fallback: Direct path when outputDir is the base directory
|
|
418
|
-
outputPath = path.join(outputDir, 'partials', 'deprecated', 'deprecated-properties.adoc');
|
|
419
|
-
}
|
|
420
|
-
|
|
182
|
+
const outputPath = process.env.OUTPUT_PARTIALS_DIR
|
|
183
|
+
? path.join(process.env.OUTPUT_PARTIALS_DIR, 'deprecated', 'deprecated-properties.adoc')
|
|
184
|
+
: path.join(outputDir, 'partials', 'deprecated', 'deprecated-properties.adoc');
|
|
185
|
+
|
|
421
186
|
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
422
|
-
fs.writeFileSync(outputPath, output, 'utf8');
|
|
423
|
-
|
|
187
|
+
fs.writeFileSync(outputPath, AUTOGEN_NOTICE + output, 'utf8');
|
|
424
188
|
console.log(`✅ Generated ${outputPath}`);
|
|
425
189
|
return deprecatedProperties.length;
|
|
426
190
|
}
|
|
427
191
|
|
|
428
192
|
/**
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* Checks the provided map of properties and returns true if at least one
|
|
432
|
-
* property object has a `cloud_supported` own property (regardless of its value).
|
|
433
|
-
*
|
|
434
|
-
* @param {Object<string, Object>} properties - Map from property name to its metadata object.
|
|
435
|
-
* @return {boolean} True if any property has a `cloud_supported` attribute; otherwise false.
|
|
193
|
+
* Generate topic-property-mappings.adoc using the mappings template and topic properties.
|
|
436
194
|
*/
|
|
437
|
-
function
|
|
438
|
-
|
|
439
|
-
|
|
195
|
+
function generateTopicPropertyMappings(properties, partialsDir) {
|
|
196
|
+
const templatesDir = path.join(__dirname, 'templates');
|
|
197
|
+
const mappingsTemplatePath = getTemplatePath(
|
|
198
|
+
path.join(templatesDir, 'topic-property-mappings.hbs'),
|
|
199
|
+
'TEMPLATE_TOPIC_PROPERTY_MAPPINGS'
|
|
200
|
+
);
|
|
201
|
+
if (!fs.existsSync(mappingsTemplatePath)) {
|
|
202
|
+
throw new Error(`topic-property-mappings.hbs template not found: ${mappingsTemplatePath}`);
|
|
203
|
+
}
|
|
204
|
+
const topicProperties = Object.values(properties).filter(
|
|
205
|
+
p => p.is_topic_property && p.corresponding_cluster_property
|
|
440
206
|
);
|
|
207
|
+
if (topicProperties.length === 0) {
|
|
208
|
+
console.log('ℹ️ No topic properties with corresponding_cluster_property found. Skipping topic-property-mappings.adoc.');
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
const hbsSource = fs.readFileSync(mappingsTemplatePath, 'utf8');
|
|
212
|
+
const hbs = handlebars.compile(hbsSource);
|
|
213
|
+
const rendered = hbs({ topicProperties });
|
|
214
|
+
const mappingsOut = path.join(partialsDir, 'topic-property-mappings.adoc');
|
|
215
|
+
fs.writeFileSync(mappingsOut, AUTOGEN_NOTICE + rendered, 'utf8');
|
|
216
|
+
console.log(`✅ Generated ${mappingsOut}`);
|
|
217
|
+
return topicProperties.length;
|
|
441
218
|
}
|
|
442
219
|
|
|
443
220
|
/**
|
|
444
|
-
* Generate
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
221
|
+
* Generate error reports for missing descriptions and deprecated properties.
|
|
222
|
+
*/
|
|
223
|
+
function generateErrorReports(properties) {
|
|
224
|
+
const emptyDescriptions = [];
|
|
225
|
+
const deprecatedProperties = [];
|
|
226
|
+
|
|
227
|
+
Object.values(properties).forEach(p => {
|
|
228
|
+
if (!p.description || !p.description.trim()) emptyDescriptions.push(p.name);
|
|
229
|
+
if (p.is_deprecated) deprecatedProperties.push(p.name);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const total = Object.keys(properties).length;
|
|
233
|
+
const pctEmpty = total ? ((emptyDescriptions.length / total) * 100).toFixed(2) : '0.00';
|
|
234
|
+
const pctDeprecated = total ? ((deprecatedProperties.length / total) * 100).toFixed(2) : '0.00';
|
|
235
|
+
console.log(`Empty descriptions: ${emptyDescriptions.length} (${pctEmpty}%)`);
|
|
236
|
+
console.log(`Deprecated: ${deprecatedProperties.length} (${pctDeprecated}%)`);
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
empty_descriptions: emptyDescriptions.sort(),
|
|
240
|
+
deprecated_properties: deprecatedProperties.sort()
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Main generator — only supports partials and deprecated docs.
|
|
459
246
|
*/
|
|
460
247
|
function generateAllDocs(inputFile, outputDir) {
|
|
461
|
-
// Read input JSON
|
|
462
248
|
const data = JSON.parse(fs.readFileSync(inputFile, 'utf8'));
|
|
463
249
|
const properties = data.properties || {};
|
|
464
250
|
|
|
465
|
-
|
|
466
|
-
const hasCloudSupport = hasCloudSupportMetadata(properties);
|
|
467
|
-
if (hasCloudSupport) {
|
|
468
|
-
console.log('🌤️ Cloud support metadata detected, using cloud-aware templates');
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Register partials with cloud support detection
|
|
472
|
-
registerPartials(hasCloudSupport);
|
|
473
|
-
|
|
474
|
-
let totalProperties = 0;
|
|
475
|
-
let totalBrokerProperties = 0;
|
|
476
|
-
let totalClusterProperties = 0;
|
|
477
|
-
let totalObjectStorageProperties = 0;
|
|
478
|
-
let totalTopicProperties = 0;
|
|
479
|
-
|
|
480
|
-
// Generate complete property pages only if requested
|
|
481
|
-
if (process.env.GENERATE_PAGES === '1') {
|
|
482
|
-
console.log(`📄 Generating complete property pages...`);
|
|
483
|
-
|
|
484
|
-
// Generate each type of documentation
|
|
485
|
-
for (const [type, config] of Object.entries(PROPERTY_CONFIG)) {
|
|
486
|
-
const count = generatePropertyDocs(properties, config, outputDir);
|
|
487
|
-
totalProperties += count;
|
|
488
|
-
|
|
489
|
-
if (type === 'broker') totalBrokerProperties = count;
|
|
490
|
-
else if (type === 'cluster') totalClusterProperties = count;
|
|
491
|
-
else if (type === 'object-storage') totalObjectStorageProperties = count;
|
|
492
|
-
else if (type === 'topic') totalTopicProperties = count;
|
|
493
|
-
}
|
|
494
|
-
} else {
|
|
495
|
-
console.log(`📄 Skipping complete property pages (use --generate-pages to enable)`);
|
|
496
|
-
|
|
497
|
-
// Still count properties for summary
|
|
498
|
-
Object.values(properties).forEach(prop => {
|
|
499
|
-
if (prop.config_scope === 'broker' && !prop.is_deprecated) totalBrokerProperties++;
|
|
500
|
-
else if (prop.config_scope === 'cluster' && !prop.is_deprecated) {
|
|
501
|
-
if (prop.name && (
|
|
502
|
-
prop.name.includes('cloud_storage') ||
|
|
503
|
-
prop.name.includes('s3_') ||
|
|
504
|
-
prop.name.includes('azure_') ||
|
|
505
|
-
prop.name.includes('gcs_') ||
|
|
506
|
-
prop.name.includes('archival_') ||
|
|
507
|
-
prop.name.includes('remote_') ||
|
|
508
|
-
prop.name.includes('tiered_')
|
|
509
|
-
)) {
|
|
510
|
-
totalObjectStorageProperties++;
|
|
511
|
-
} else {
|
|
512
|
-
totalClusterProperties++;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
else if (prop.config_scope === 'topic' && !prop.is_deprecated) totalTopicProperties++;
|
|
516
|
-
});
|
|
517
|
-
totalProperties = totalBrokerProperties + totalClusterProperties + totalObjectStorageProperties + totalTopicProperties;
|
|
518
|
-
}
|
|
251
|
+
registerPartials();
|
|
519
252
|
|
|
520
|
-
// Generate individual property partials if requested
|
|
521
253
|
let partialsCount = 0;
|
|
522
254
|
let deprecatedCount = 0;
|
|
255
|
+
|
|
523
256
|
if (process.env.GENERATE_PARTIALS === '1' && process.env.OUTPUT_PARTIALS_DIR) {
|
|
524
|
-
|
|
257
|
+
console.log('📄 Generating property partials and deprecated docs...');
|
|
525
258
|
deprecatedCount = generateDeprecatedDocs(properties, outputDir);
|
|
526
|
-
|
|
527
|
-
|
|
259
|
+
partialsCount = generatePropertyPartials(properties, process.env.OUTPUT_PARTIALS_DIR);
|
|
260
|
+
|
|
261
|
+
// Generate topic-property-mappings.adoc
|
|
262
|
+
try {
|
|
263
|
+
generateTopicPropertyMappings(properties, process.env.OUTPUT_PARTIALS_DIR);
|
|
264
|
+
} catch (err) {
|
|
265
|
+
console.error(`❌ Failed to generate topic-property-mappings.adoc: ${err.message}`);
|
|
266
|
+
}
|
|
528
267
|
} else {
|
|
529
|
-
console.log(
|
|
530
|
-
console.log(`📄 Skipping deprecated properties documentation (use --generate-partials to enable)`);
|
|
268
|
+
console.log('📄 Skipping partial generation (set GENERATE_PARTIALS=1 and OUTPUT_PARTIALS_DIR to enable)');
|
|
531
269
|
}
|
|
532
270
|
|
|
533
|
-
|
|
534
|
-
const errorReport = generateErrorReports(properties, outputDir);
|
|
535
|
-
|
|
536
|
-
// Add error arrays directly to the input file so they're included when copied
|
|
271
|
+
const errors = generateErrorReports(properties);
|
|
537
272
|
const inputData = JSON.parse(fs.readFileSync(inputFile, 'utf8'));
|
|
538
|
-
inputData.empty_descriptions =
|
|
539
|
-
inputData.deprecated_properties =
|
|
273
|
+
inputData.empty_descriptions = errors.empty_descriptions;
|
|
274
|
+
inputData.deprecated_properties = errors.deprecated_properties;
|
|
540
275
|
fs.writeFileSync(inputFile, JSON.stringify(inputData, null, 2), 'utf8');
|
|
541
|
-
console.log(`📝 Added error arrays to ${inputFile}`);
|
|
542
|
-
|
|
543
|
-
console.log(`📊 Generation Summary:`);
|
|
544
|
-
console.log(` Total properties read: ${Object.keys(properties).length}`);
|
|
545
|
-
console.log(` Total Broker properties: ${totalBrokerProperties}`);
|
|
546
|
-
console.log(` Total Cluster properties: ${totalClusterProperties}`);
|
|
547
|
-
console.log(` Total Object Storage properties: ${totalObjectStorageProperties}`);
|
|
548
|
-
console.log(` Total Topic properties: ${totalTopicProperties}`);
|
|
549
|
-
console.log(` Total Deprecated properties: ${deprecatedCount}`);
|
|
550
|
-
if (partialsCount > 0) {
|
|
551
|
-
console.log(` Total Property partials: ${partialsCount}`);
|
|
552
|
-
}
|
|
553
276
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
objectStorageProperties: totalObjectStorageProperties,
|
|
559
|
-
topicProperties: totalTopicProperties,
|
|
560
|
-
deprecatedProperties: deprecatedCount,
|
|
561
|
-
propertyPartials: partialsCount
|
|
562
|
-
};
|
|
563
|
-
}
|
|
277
|
+
console.log('📊 Summary:');
|
|
278
|
+
console.log(` Total properties: ${Object.keys(properties).length}`);
|
|
279
|
+
console.log(` Total partials generated: ${partialsCount}`);
|
|
280
|
+
console.log(` Deprecated properties: ${deprecatedCount}`);
|
|
564
281
|
|
|
565
|
-
/**
|
|
566
|
-
* Generate error reports for properties with missing or invalid data
|
|
567
|
-
*/
|
|
568
|
-
function generateErrorReports(properties, outputDir) {
|
|
569
|
-
const emptyDescriptions = [];
|
|
570
|
-
const deprecatedProperties = [];
|
|
571
|
-
|
|
572
|
-
Object.values(properties).forEach(prop => {
|
|
573
|
-
if (!prop.description || prop.description.trim() === '') {
|
|
574
|
-
emptyDescriptions.push(prop.name);
|
|
575
|
-
}
|
|
576
|
-
if (prop.is_deprecated) {
|
|
577
|
-
deprecatedProperties.push(prop.name);
|
|
578
|
-
}
|
|
579
|
-
});
|
|
580
|
-
|
|
581
|
-
// Add these arrays to the properties JSON file
|
|
582
|
-
const totalProperties = Object.keys(properties).length;
|
|
583
|
-
const percentageEmpty = totalProperties > 0 ? ((emptyDescriptions.length / totalProperties) * 100).toFixed(2) : '0.00';
|
|
584
|
-
const percentageDeprecated = totalProperties > 0 ? ((deprecatedProperties.length / totalProperties) * 100).toFixed(2) : '0.00';
|
|
585
|
-
console.log(`You have ${emptyDescriptions.length} properties with empty description. Percentage of errors: ${percentageEmpty}%.`);
|
|
586
|
-
console.log(`You have ${deprecatedProperties.length} deprecated properties. Percentage of errors: ${percentageDeprecated}%.`);
|
|
587
|
-
|
|
588
|
-
// Return the arrays sorted for deterministic output
|
|
589
282
|
return {
|
|
590
|
-
|
|
591
|
-
|
|
283
|
+
totalProperties: Object.keys(properties).length,
|
|
284
|
+
propertyPartials: partialsCount,
|
|
285
|
+
deprecatedProperties: deprecatedCount
|
|
592
286
|
};
|
|
593
287
|
}
|
|
594
288
|
|
|
595
289
|
module.exports = {
|
|
596
290
|
generateAllDocs,
|
|
597
|
-
generatePropertyDocs,
|
|
598
291
|
generateDeprecatedDocs,
|
|
599
|
-
generatePropertyPartials
|
|
600
|
-
PROPERTY_CONFIG
|
|
292
|
+
generatePropertyPartials
|
|
601
293
|
};
|
|
602
294
|
|
|
603
|
-
// CLI
|
|
295
|
+
// CLI
|
|
604
296
|
if (require.main === module) {
|
|
605
297
|
const args = process.argv.slice(2);
|
|
606
298
|
if (args.length < 2) {
|
|
@@ -609,7 +301,6 @@ if (require.main === module) {
|
|
|
609
301
|
}
|
|
610
302
|
|
|
611
303
|
const [inputFile, outputDir] = args;
|
|
612
|
-
|
|
613
304
|
if (!fs.existsSync(inputFile)) {
|
|
614
305
|
console.error(`❌ Input file not found: ${inputFile}`);
|
|
615
306
|
process.exit(1);
|
|
@@ -618,8 +309,8 @@ if (require.main === module) {
|
|
|
618
309
|
try {
|
|
619
310
|
generateAllDocs(inputFile, outputDir);
|
|
620
311
|
console.log('✅ Documentation generation completed successfully');
|
|
621
|
-
} catch (
|
|
622
|
-
console.error(`❌ Error
|
|
312
|
+
} catch (err) {
|
|
313
|
+
console.error(`❌ Error: ${err.message}`);
|
|
623
314
|
process.exit(1);
|
|
624
315
|
}
|
|
625
316
|
}
|