@redpanda-data/docs-extensions-and-macros 4.12.2 ā 4.12.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 +354 -89
- package/extensions/algolia-indexer/generate-index.js +43 -27
- package/package.json +1 -1
- package/tools/property-extractor/Makefile +63 -8
- package/tools/property-extractor/README.adoc +973 -621
- package/tools/property-extractor/compare-properties.js +10 -6
- package/tools/property-extractor/generate-handlebars-docs.js +9 -6
- package/tools/property-extractor/property_extractor.py +93 -10
- package/tools/property-extractor/templates/topic-property-mappings.hbs +6 -1
- package/tools/property-extractor/templates/topic-property.hbs +1 -1
- package/tools/property-extractor/topic_property_extractor.py +269 -65
- package/tools/property-extractor/transformers.py +48 -21
- package/tools/redpanda-connect/README.adoc +736 -0
- package/tools/redpanda-connect/helpers/renderConnectFields.js +57 -31
- package/tools/redpanda-connect/helpers/renderLeafField.js +10 -3
- package/tools/redpanda-connect/helpers/renderYamlList.js +7 -2
- package/tools/redpanda-connect/helpers/toYaml.js +8 -3
- package/tools/redpanda-connect/report-delta.js +64 -2
package/bin/doc-tools.js
CHANGED
|
@@ -480,6 +480,42 @@ function runClusterDocs(mode, tag, options) {
|
|
|
480
480
|
if (r.status !== 0) process.exit(r.status);
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
+
/**
|
|
484
|
+
* Cleanup old diff files, keeping only the 2 most recent.
|
|
485
|
+
*
|
|
486
|
+
* @param {string} diffDir - Directory containing diff files
|
|
487
|
+
*/
|
|
488
|
+
function cleanupOldDiffs(diffDir) {
|
|
489
|
+
try {
|
|
490
|
+
console.log('Cleaning up old diff JSON files (keeping only 2 most recent)ā¦');
|
|
491
|
+
|
|
492
|
+
const absoluteDiffDir = path.resolve(diffDir);
|
|
493
|
+
if (!fs.existsSync(absoluteDiffDir)) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Get all diff files sorted by modification time (newest first)
|
|
498
|
+
const files = fs.readdirSync(absoluteDiffDir)
|
|
499
|
+
.filter(file => file.startsWith('redpanda-property-changes-') && file.endsWith('.json'))
|
|
500
|
+
.map(file => ({
|
|
501
|
+
name: file,
|
|
502
|
+
path: path.join(absoluteDiffDir, file),
|
|
503
|
+
time: fs.statSync(path.join(absoluteDiffDir, file)).mtime.getTime()
|
|
504
|
+
}))
|
|
505
|
+
.sort((a, b) => b.time - a.time);
|
|
506
|
+
|
|
507
|
+
// Delete all but the 2 most recent
|
|
508
|
+
if (files.length > 2) {
|
|
509
|
+
files.slice(2).forEach(file => {
|
|
510
|
+
console.log(` Removing old file: ${file.name}`);
|
|
511
|
+
fs.unlinkSync(file.path);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.error(` Failed to cleanup old diff files: ${error.message}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
483
519
|
/**
|
|
484
520
|
* Generate a detailed JSON report describing property changes between two releases.
|
|
485
521
|
*
|
|
@@ -499,12 +535,13 @@ function runClusterDocs(mode, tag, options) {
|
|
|
499
535
|
function generatePropertyComparisonReport(oldTag, newTag, outputDir) {
|
|
500
536
|
try {
|
|
501
537
|
console.log(`\nš Generating detailed property comparison report...`);
|
|
502
|
-
|
|
503
|
-
// Look for the property JSON files in
|
|
538
|
+
|
|
539
|
+
// Look for the property JSON files in the standard location (modules/reference/attachments)
|
|
540
|
+
// regardless of where we're saving the diff output
|
|
504
541
|
const repoRoot = findRepoRoot();
|
|
505
|
-
const
|
|
506
|
-
const oldJsonPath = path.join(
|
|
507
|
-
const newJsonPath = path.join(
|
|
542
|
+
const attachmentsDir = path.join(repoRoot, 'modules/reference/attachments');
|
|
543
|
+
const oldJsonPath = path.join(attachmentsDir, `redpanda-properties-${oldTag}.json`);
|
|
544
|
+
const newJsonPath = path.join(attachmentsDir, `redpanda-properties-${newTag}.json`);
|
|
508
545
|
|
|
509
546
|
// Check if JSON files exist
|
|
510
547
|
if (!fs.existsSync(oldJsonPath)) {
|
|
@@ -526,7 +563,7 @@ function generatePropertyComparisonReport(oldTag, newTag, outputDir) {
|
|
|
526
563
|
// Run the property comparison tool with descriptive filename
|
|
527
564
|
const propertyExtractorDir = path.resolve(__dirname, '../tools/property-extractor');
|
|
528
565
|
const compareScript = path.join(propertyExtractorDir, 'compare-properties.js');
|
|
529
|
-
const reportFilename = `property-changes-${oldTag}-to-${newTag}.json`;
|
|
566
|
+
const reportFilename = `redpanda-property-changes-${oldTag}-to-${newTag}.json`;
|
|
530
567
|
const reportPath = path.join(absoluteOutputDir, reportFilename);
|
|
531
568
|
const args = [compareScript, oldJsonPath, newJsonPath, oldTag, newTag, absoluteOutputDir, reportFilename];
|
|
532
569
|
|
|
@@ -858,6 +895,26 @@ automation
|
|
|
858
895
|
|
|
859
896
|
const newIndex = JSON.parse(fs.readFileSync(dataFile, 'utf8'));
|
|
860
897
|
|
|
898
|
+
// Check if versions match - skip diff and updates if so
|
|
899
|
+
if (oldVersion && newVersion && oldVersion === newVersion) {
|
|
900
|
+
console.log(`\nā Already at version ${newVersion}`);
|
|
901
|
+
console.log(' No diff or version updates needed.\n');
|
|
902
|
+
|
|
903
|
+
console.log('š Generation Report:');
|
|
904
|
+
console.log(` ⢠Partial files: ${partialsWritten}`);
|
|
905
|
+
const fieldsPartials = partialFiles.filter(fp => fp.includes('/fields/'));
|
|
906
|
+
const examplesPartials = partialFiles.filter(fp => fp.includes('/examples/'));
|
|
907
|
+
|
|
908
|
+
console.log(` ⢠Fields partials: ${fieldsPartials.length}`);
|
|
909
|
+
console.log(` ⢠Examples partials: ${examplesPartials.length}`);
|
|
910
|
+
|
|
911
|
+
if (options.draftMissing && draftsWritten) {
|
|
912
|
+
console.log(` ⢠Draft files: ${draftsWritten}`);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
process.exit(0);
|
|
916
|
+
}
|
|
917
|
+
|
|
861
918
|
// Publish merged version with overrides to modules/components/attachments
|
|
862
919
|
if (options.overrides && fs.existsSync(options.overrides)) {
|
|
863
920
|
try {
|
|
@@ -1073,65 +1130,144 @@ automation
|
|
|
1073
1130
|
endIdx = nextMatch ? startIdx + 1 + nextMatch.index : whatsNew.length;
|
|
1074
1131
|
}
|
|
1075
1132
|
// Compose new section
|
|
1076
|
-
|
|
1077
|
-
// Add link to full release notes for this connector version after version heading and before component updates
|
|
1133
|
+
// Add link to full release notes for this connector version after version heading
|
|
1078
1134
|
let releaseNotesLink = '';
|
|
1079
1135
|
if (diff.comparison && diff.comparison.newVersion) {
|
|
1080
1136
|
releaseNotesLink = `link:https://github.com/redpanda-data/connect/releases/tag/v${diff.comparison.newVersion}[See the full release notes^].\n\n`;
|
|
1081
1137
|
}
|
|
1082
|
-
section = `\n== Version ${diff.comparison.newVersion}\n\n${releaseNotesLink}
|
|
1083
|
-
|
|
1138
|
+
let section = `\n== Version ${diff.comparison.newVersion}\n\n${releaseNotesLink}`;
|
|
1139
|
+
|
|
1140
|
+
// Separate Bloblang components from regular components
|
|
1141
|
+
const bloblangComponents = [];
|
|
1142
|
+
const regularComponents = [];
|
|
1143
|
+
|
|
1084
1144
|
if (diff.details.newComponents && diff.details.newComponents.length) {
|
|
1085
|
-
section += 'This release adds the following new components:\n\n';
|
|
1086
|
-
// Group by type
|
|
1087
|
-
const byType = {};
|
|
1088
1145
|
for (const comp of diff.details.newComponents) {
|
|
1146
|
+
if (comp.type === 'bloblang-functions' || comp.type === 'bloblang-methods') {
|
|
1147
|
+
bloblangComponents.push(comp);
|
|
1148
|
+
} else {
|
|
1149
|
+
regularComponents.push(comp);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// Bloblang updates section
|
|
1155
|
+
if (bloblangComponents.length > 0) {
|
|
1156
|
+
section += '=== Bloblang updates\n\n';
|
|
1157
|
+
section += 'This release adds the following new Bloblang capabilities:\n\n';
|
|
1158
|
+
|
|
1159
|
+
// Group by type (functions vs methods)
|
|
1160
|
+
const byType = {};
|
|
1161
|
+
for (const comp of bloblangComponents) {
|
|
1089
1162
|
if (!byType[comp.type]) byType[comp.type] = [];
|
|
1090
1163
|
byType[comp.type].push(comp);
|
|
1091
1164
|
}
|
|
1165
|
+
|
|
1092
1166
|
for (const [type, comps] of Object.entries(byType)) {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1167
|
+
if (type === 'bloblang-functions') {
|
|
1168
|
+
section += '* Functions:\n';
|
|
1169
|
+
for (const comp of comps) {
|
|
1170
|
+
section += `** xref:guides:bloblang/functions.adoc#${comp.name}[\`${comp.name}\`]`;
|
|
1171
|
+
if (comp.status && comp.status !== 'stable') section += ` (${comp.status})`;
|
|
1172
|
+
if (comp.description) section += `: ${capToTwoSentences(comp.description)}`;
|
|
1173
|
+
section += '\n';
|
|
1174
|
+
}
|
|
1175
|
+
} else if (type === 'bloblang-methods') {
|
|
1176
|
+
section += '* Methods:\n';
|
|
1177
|
+
for (const comp of comps) {
|
|
1178
|
+
section += `** xref:guides:bloblang/methods.adoc#${comp.name}[\`${comp.name}\`]`;
|
|
1179
|
+
if (comp.status && comp.status !== 'stable') section += ` (${comp.status})`;
|
|
1180
|
+
if (comp.description) section += `: ${capToTwoSentences(comp.description)}`;
|
|
1181
|
+
section += '\n';
|
|
1182
|
+
}
|
|
1099
1183
|
}
|
|
1100
1184
|
}
|
|
1185
|
+
section += '\n';
|
|
1101
1186
|
}
|
|
1102
1187
|
|
|
1103
|
-
//
|
|
1104
|
-
if (
|
|
1105
|
-
section += '
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1188
|
+
// Regular component updates section
|
|
1189
|
+
if (regularComponents.length > 0) {
|
|
1190
|
+
section += '=== Component updates\n\n';
|
|
1191
|
+
section += 'This release adds the following new components:\n\n';
|
|
1192
|
+
|
|
1193
|
+
section += '[cols="1m,1,1,3"]\n';
|
|
1194
|
+
section += '|===\n';
|
|
1195
|
+
section += '|Component |Type |Status |Description\n\n';
|
|
1196
|
+
|
|
1197
|
+
for (const comp of regularComponents) {
|
|
1198
|
+
const typeLabel = comp.type.charAt(0).toUpperCase() + comp.type.slice(1);
|
|
1199
|
+
const statusLabel = comp.status || '-';
|
|
1200
|
+
const desc = comp.description ? capToTwoSentences(comp.description) : '-';
|
|
1201
|
+
|
|
1202
|
+
section += `|xref:components:${comp.type}/${comp.name}.adoc[${comp.name}]\n`;
|
|
1203
|
+
section += `|${typeLabel}\n`;
|
|
1204
|
+
section += `|${statusLabel}\n`;
|
|
1205
|
+
section += `|${desc}\n\n`;
|
|
1117
1206
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1207
|
+
|
|
1208
|
+
section += '|===\n\n';
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// New fields (exclude Bloblang functions/methods)
|
|
1212
|
+
if (diff.details.newFields && diff.details.newFields.length) {
|
|
1213
|
+
// Filter out Bloblang components
|
|
1214
|
+
const regularFields = diff.details.newFields.filter(field => {
|
|
1215
|
+
const [type] = field.component.split(':');
|
|
1216
|
+
return type !== 'bloblang-functions' && type !== 'bloblang-methods';
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
if (regularFields.length > 0) {
|
|
1220
|
+
section += '\n=== New field support\n\n';
|
|
1221
|
+
section += 'This release adds support for the following new fields:\n\n';
|
|
1222
|
+
|
|
1223
|
+
// Group by field name
|
|
1224
|
+
const byField = {};
|
|
1225
|
+
for (const field of regularFields) {
|
|
1226
|
+
const [type, compName] = field.component.split(':');
|
|
1227
|
+
if (!byField[field.field]) {
|
|
1228
|
+
byField[field.field] = {
|
|
1229
|
+
description: field.description,
|
|
1230
|
+
components: []
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
byField[field.field].components.push({ type, name: compName });
|
|
1125
1234
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1235
|
+
|
|
1236
|
+
section += '[cols="1m,3,2a"]\n';
|
|
1237
|
+
section += '|===\n';
|
|
1238
|
+
section += '|Field |Description |Affected components\n\n';
|
|
1239
|
+
|
|
1240
|
+
for (const [fieldName, info] of Object.entries(byField)) {
|
|
1241
|
+
// Format component list - group by type
|
|
1242
|
+
const byType = {};
|
|
1243
|
+
for (const comp of info.components) {
|
|
1244
|
+
if (!byType[comp.type]) byType[comp.type] = [];
|
|
1245
|
+
byType[comp.type].push(comp.name);
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
let componentList = '';
|
|
1249
|
+
for (const [type, names] of Object.entries(byType)) {
|
|
1250
|
+
if (componentList) componentList += '\n\n';
|
|
1251
|
+
|
|
1252
|
+
// Smart pluralization: don't add 's' if already plural
|
|
1253
|
+
const typeLabel = names.length === 1
|
|
1254
|
+
? type.charAt(0).toUpperCase() + type.slice(1)
|
|
1255
|
+
: type.charAt(0).toUpperCase() + type.slice(1) + (type.endsWith('s') ? '' : 's');
|
|
1256
|
+
|
|
1257
|
+
componentList += `*${typeLabel}:*\n\n`;
|
|
1258
|
+
names.forEach(name => {
|
|
1259
|
+
componentList += `* xref:components:${type}/${name}.adoc#${fieldName}[${name}]\n`;
|
|
1260
|
+
});
|
|
1133
1261
|
}
|
|
1262
|
+
|
|
1263
|
+
const desc = info.description ? capToTwoSentences(info.description) : '-';
|
|
1264
|
+
|
|
1265
|
+
section += `|${fieldName}\n`;
|
|
1266
|
+
section += `|${desc}\n`;
|
|
1267
|
+
section += `|${componentList}\n\n`;
|
|
1134
1268
|
}
|
|
1269
|
+
|
|
1270
|
+
section += '|===\n\n';
|
|
1135
1271
|
}
|
|
1136
1272
|
}
|
|
1137
1273
|
|
|
@@ -1139,56 +1275,180 @@ automation
|
|
|
1139
1275
|
if (diff.details.deprecatedComponents && diff.details.deprecatedComponents.length) {
|
|
1140
1276
|
section += '\n=== Deprecations\n\n';
|
|
1141
1277
|
section += 'The following components are now deprecated:\n\n';
|
|
1142
|
-
|
|
1143
|
-
|
|
1278
|
+
|
|
1279
|
+
section += '[cols="1m,1,3"]\n';
|
|
1280
|
+
section += '|===\n';
|
|
1281
|
+
section += '|Component |Type |Description\n\n';
|
|
1282
|
+
|
|
1144
1283
|
for (const comp of diff.details.deprecatedComponents) {
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
section +=
|
|
1284
|
+
const typeLabel = comp.type.charAt(0).toUpperCase() + comp.type.slice(1);
|
|
1285
|
+
const desc = comp.description ? capToTwoSentences(comp.description) : '-';
|
|
1286
|
+
|
|
1287
|
+
if (comp.type === 'bloblang-functions') {
|
|
1288
|
+
section += `|xref:guides:bloblang/functions.adoc#${comp.name}[${comp.name}]\n`;
|
|
1289
|
+
} else if (comp.type === 'bloblang-methods') {
|
|
1290
|
+
section += `|xref:guides:bloblang/methods.adoc#${comp.name}[${comp.name}]\n`;
|
|
1291
|
+
} else {
|
|
1292
|
+
section += `|xref:components:${comp.type}/${comp.name}.adoc[${comp.name}]\n`;
|
|
1152
1293
|
}
|
|
1294
|
+
section += `|${typeLabel}\n`;
|
|
1295
|
+
section += `|${desc}\n\n`;
|
|
1153
1296
|
}
|
|
1297
|
+
|
|
1298
|
+
section += '|===\n\n';
|
|
1154
1299
|
}
|
|
1155
1300
|
|
|
1156
|
-
// Deprecated fields
|
|
1301
|
+
// Deprecated fields (exclude Bloblang functions/methods)
|
|
1157
1302
|
if (diff.details.deprecatedFields && diff.details.deprecatedFields.length) {
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1303
|
+
// Filter out Bloblang components
|
|
1304
|
+
const regularDeprecatedFields = diff.details.deprecatedFields.filter(field => {
|
|
1305
|
+
const [type] = field.component.split(':');
|
|
1306
|
+
return type !== 'bloblang-functions' && type !== 'bloblang-methods';
|
|
1307
|
+
});
|
|
1308
|
+
|
|
1309
|
+
if (regularDeprecatedFields.length > 0) {
|
|
1310
|
+
if (!diff.details.deprecatedComponents || diff.details.deprecatedComponents.length === 0) {
|
|
1311
|
+
section += '\n=== Deprecations\n\n';
|
|
1312
|
+
} else {
|
|
1313
|
+
section += '\n';
|
|
1314
|
+
}
|
|
1315
|
+
section += 'The following fields are now deprecated:\n\n';
|
|
1316
|
+
|
|
1317
|
+
// Group by field name
|
|
1318
|
+
const byField = {};
|
|
1319
|
+
for (const field of regularDeprecatedFields) {
|
|
1320
|
+
const [type, compName] = field.component.split(':');
|
|
1321
|
+
if (!byField[field.field]) {
|
|
1322
|
+
byField[field.field] = {
|
|
1323
|
+
description: field.description,
|
|
1324
|
+
components: []
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
byField[field.field].components.push({ type, name: compName });
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
section += '[cols="1m,3,2a"]\n';
|
|
1331
|
+
section += '|===\n';
|
|
1332
|
+
section += '|Field |Description |Affected components\n\n';
|
|
1333
|
+
|
|
1334
|
+
for (const [fieldName, info] of Object.entries(byField)) {
|
|
1335
|
+
// Format component list - group by type
|
|
1336
|
+
const byType = {};
|
|
1337
|
+
for (const comp of info.components) {
|
|
1338
|
+
if (!byType[comp.type]) byType[comp.type] = [];
|
|
1339
|
+
byType[comp.type].push(comp.name);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
let componentList = '';
|
|
1343
|
+
for (const [type, names] of Object.entries(byType)) {
|
|
1344
|
+
if (componentList) componentList += '\n\n';
|
|
1345
|
+
|
|
1346
|
+
// Smart pluralization: don't add 's' if already plural
|
|
1347
|
+
const typeLabel = names.length === 1
|
|
1348
|
+
? type.charAt(0).toUpperCase() + type.slice(1)
|
|
1349
|
+
: type.charAt(0).toUpperCase() + type.slice(1) + (type.endsWith('s') ? '' : 's');
|
|
1350
|
+
|
|
1351
|
+
componentList += `*${typeLabel}:*\n\n`;
|
|
1352
|
+
names.forEach(name => {
|
|
1353
|
+
componentList += `* xref:components:${type}/${name}.adoc#${fieldName}[${name}]\n`;
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
const desc = info.description ? capToTwoSentences(info.description) : '-';
|
|
1358
|
+
|
|
1359
|
+
section += `|${fieldName}\n`;
|
|
1360
|
+
section += `|${desc}\n`;
|
|
1361
|
+
section += `|${componentList}\n\n`;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
section += '|===\n\n';
|
|
1171
1365
|
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
// Changed defaults (exclude Bloblang functions/methods)
|
|
1369
|
+
if (diff.details.changedDefaults && diff.details.changedDefaults.length) {
|
|
1370
|
+
// Filter out Bloblang components
|
|
1371
|
+
const regularChangedDefaults = diff.details.changedDefaults.filter(change => {
|
|
1372
|
+
const [type] = change.component.split(':');
|
|
1373
|
+
return type !== 'bloblang-functions' && type !== 'bloblang-methods';
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1376
|
+
if (regularChangedDefaults.length > 0) {
|
|
1377
|
+
section += '\n=== Default value changes\n\n';
|
|
1378
|
+
section += 'This release includes the following default value changes:\n\n';
|
|
1379
|
+
|
|
1380
|
+
// Group by field name and default values to avoid overwriting different default changes
|
|
1381
|
+
const byFieldAndDefaults = {};
|
|
1382
|
+
for (const change of regularChangedDefaults) {
|
|
1383
|
+
const [type, compName] = change.component.split(':');
|
|
1384
|
+
const compositeKey = `${change.field}|${String(change.oldDefault)}|${String(change.newDefault)}`;
|
|
1385
|
+
if (!byFieldAndDefaults[compositeKey]) {
|
|
1386
|
+
byFieldAndDefaults[compositeKey] = {
|
|
1387
|
+
field: change.field,
|
|
1388
|
+
oldDefault: change.oldDefault,
|
|
1389
|
+
newDefault: change.newDefault,
|
|
1390
|
+
description: change.description,
|
|
1391
|
+
components: []
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
byFieldAndDefaults[compositeKey].components.push({
|
|
1395
|
+
type,
|
|
1396
|
+
name: compName
|
|
1397
|
+
});
|
|
1179
1398
|
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1399
|
+
|
|
1400
|
+
// Create table
|
|
1401
|
+
section += '[cols="1m,1,1,3,2a"]\n';
|
|
1402
|
+
section += '|===\n';
|
|
1403
|
+
section += '|Field |Old default |New default |Description |Affected components\n\n';
|
|
1404
|
+
|
|
1405
|
+
for (const [compositeKey, info] of Object.entries(byFieldAndDefaults)) {
|
|
1406
|
+
// Format old and new defaults
|
|
1407
|
+
const formatDefault = (val) => {
|
|
1408
|
+
if (val === undefined || val === null) return 'none';
|
|
1409
|
+
if (typeof val === 'string') return val;
|
|
1410
|
+
if (typeof val === 'number' || typeof val === 'boolean') return String(val);
|
|
1411
|
+
return JSON.stringify(val);
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1414
|
+
const oldVal = formatDefault(info.oldDefault);
|
|
1415
|
+
const newVal = formatDefault(info.newDefault);
|
|
1416
|
+
|
|
1417
|
+
// Get description
|
|
1418
|
+
const desc = info.description ? capToTwoSentences(info.description) : '-';
|
|
1419
|
+
|
|
1420
|
+
// Format component references - group by type
|
|
1421
|
+
const byType = {};
|
|
1422
|
+
for (const comp of info.components) {
|
|
1423
|
+
if (!byType[comp.type]) byType[comp.type] = [];
|
|
1424
|
+
byType[comp.type].push(comp.name);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
let componentList = '';
|
|
1428
|
+
for (const [type, names] of Object.entries(byType)) {
|
|
1429
|
+
if (componentList) componentList += '\n\n';
|
|
1430
|
+
|
|
1431
|
+
// Smart pluralization: don't add 's' if already plural
|
|
1432
|
+
const typeLabel = names.length === 1
|
|
1433
|
+
? type.charAt(0).toUpperCase() + type.slice(1)
|
|
1434
|
+
: type.charAt(0).toUpperCase() + type.slice(1) + (type.endsWith('s') ? '' : 's');
|
|
1435
|
+
|
|
1436
|
+
componentList += `*${typeLabel}:*\n\n`;
|
|
1437
|
+
|
|
1438
|
+
// List components, with links to the field anchor
|
|
1439
|
+
names.forEach(name => {
|
|
1440
|
+
componentList += `* xref:components:${type}/${name}.adoc#${info.field}[${name}]\n`;
|
|
1441
|
+
});
|
|
1190
1442
|
}
|
|
1443
|
+
|
|
1444
|
+
section += `|${info.field}\n`;
|
|
1445
|
+
section += `|${oldVal}\n`;
|
|
1446
|
+
section += `|${newVal}\n`;
|
|
1447
|
+
section += `|${desc}\n`;
|
|
1448
|
+
section += `|${componentList}\n\n`;
|
|
1191
1449
|
}
|
|
1450
|
+
|
|
1451
|
+
section += '|===\n\n';
|
|
1192
1452
|
}
|
|
1193
1453
|
}
|
|
1194
1454
|
|
|
@@ -1302,7 +1562,7 @@ automation
|
|
|
1302
1562
|
if (templates.deprecatedProperty) {
|
|
1303
1563
|
env.TEMPLATE_DEPRECATED_PROPERTY = path.resolve(templates.deprecatedProperty);
|
|
1304
1564
|
}
|
|
1305
|
-
env.OUTPUT_JSON_DIR = path.resolve(outDir, '
|
|
1565
|
+
env.OUTPUT_JSON_DIR = path.resolve(outDir, 'attachments');
|
|
1306
1566
|
env.OUTPUT_AUTOGENERATED_DIR = path.resolve(outDir);
|
|
1307
1567
|
if (options.generatePartials) {
|
|
1308
1568
|
env.GENERATE_PARTIALS = '1';
|
|
@@ -1330,7 +1590,12 @@ automation
|
|
|
1330
1590
|
}
|
|
1331
1591
|
make(newTag, overridesPath, templates, outputDir);
|
|
1332
1592
|
if (oldTag && !tagsAreSame) {
|
|
1333
|
-
|
|
1593
|
+
// Save diff to overrides directory if OVERRIDES is specified, otherwise to outputDir
|
|
1594
|
+
const diffOutputDir = overridesPath ? path.dirname(path.resolve(overridesPath)) : outputDir;
|
|
1595
|
+
generatePropertyComparisonReport(oldTag, newTag, diffOutputDir);
|
|
1596
|
+
|
|
1597
|
+
// Cleanup old diff files (keep only 2 most recent)
|
|
1598
|
+
cleanupOldDiffs(diffOutputDir);
|
|
1334
1599
|
} else if (tagsAreSame) {
|
|
1335
1600
|
console.log('--diff and --tag are the same. Skipping diff and Antora config update.');
|
|
1336
1601
|
}
|
|
@@ -6,6 +6,9 @@ const path = require('path')
|
|
|
6
6
|
const URL = require('url')
|
|
7
7
|
const chalk = require('chalk')
|
|
8
8
|
|
|
9
|
+
// Create encoder once at module scope for efficiency
|
|
10
|
+
const textEncoder = new TextEncoder()
|
|
11
|
+
|
|
9
12
|
/**
|
|
10
13
|
* Generates an Algolia index:
|
|
11
14
|
*
|
|
@@ -143,37 +146,50 @@ function generateIndex (playbook, contentCatalog, { indexLatestOnly = false, exc
|
|
|
143
146
|
if (!(cname in algolia)) algolia[cname] = {}
|
|
144
147
|
if (!(version in algolia[cname])) algolia[cname][version] = []
|
|
145
148
|
|
|
149
|
+
// Check if this is a properties reference page (or has many titles)
|
|
150
|
+
const isPropertiesPage = page.pub.url.includes('/properties/') || titles.length > 30;
|
|
151
|
+
|
|
146
152
|
// Handle the article text
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
153
|
+
let text = '';
|
|
154
|
+
|
|
155
|
+
if (!isPropertiesPage) {
|
|
156
|
+
// For normal pages, index full text content
|
|
157
|
+
const contentElements = article.querySelectorAll('p, table, li');
|
|
158
|
+
let contentText = '';
|
|
159
|
+
let currentSize = 0;
|
|
160
|
+
// Maximum size in bytes (Algolia's limit is 100KB, using 50KB for safety)
|
|
161
|
+
const MAX_SIZE = 50000;
|
|
162
|
+
|
|
163
|
+
for (const element of contentElements) {
|
|
164
|
+
let elementText = '';
|
|
165
|
+
if (element.tagName === 'TABLE') {
|
|
166
|
+
for (const tr of element.querySelectorAll('tr')) {
|
|
167
|
+
for (const cell of tr.querySelectorAll('td, th')) {
|
|
168
|
+
elementText += cell.textContent + ' ';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
elementText = element.textContent;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const elementSize = textEncoder.encode(elementText).length;
|
|
176
|
+
if (currentSize + elementSize > MAX_SIZE) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
|
|
168
180
|
contentText += elementText;
|
|
169
181
|
currentSize += elementSize;
|
|
170
182
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
|
|
184
|
+
text = contentText.replace(/\n/g, ' ')
|
|
185
|
+
.replace(/\r/g, ' ')
|
|
186
|
+
.replace(/\s+/g, ' ')
|
|
187
|
+
.trim();
|
|
188
|
+
} else {
|
|
189
|
+
// For long pages, only use intro as text (property names are already in titles array)
|
|
190
|
+
text = intro;
|
|
191
|
+
logger.info(`Skipping full text indexing for long page: ${page.pub.url} (${titles.length} properties)`);
|
|
192
|
+
}
|
|
177
193
|
|
|
178
194
|
let tag;
|
|
179
195
|
const title = (component.title || '').trim();
|