@redpanda-data/docs-extensions-and-macros 5.12.2 → 5.12.3
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/extensions/generate-fields-only-pages.js +6 -20
- package/package.json +1 -1
- package/tools/redpanda-connect/helpers/flattenConnectFields.js +73 -0
- package/tools/redpanda-connect/helpers/renderConnectFields.js +5 -5
- package/tools/redpanda-connect/report-delta.js +134 -80
- package/tools/redpanda-connect/rpcn-connector-docs-handler.js +23 -10
|
@@ -11,6 +11,7 @@ const handlebars = require('handlebars')
|
|
|
11
11
|
|
|
12
12
|
// Import and register Redpanda Connect helpers
|
|
13
13
|
const helpers = require('../tools/redpanda-connect/helpers')
|
|
14
|
+
const { flattenConnectFields } = require('../tools/redpanda-connect/helpers/flattenConnectFields')
|
|
14
15
|
Object.entries(helpers).forEach(([name, fn]) => {
|
|
15
16
|
if (typeof fn === 'function') {
|
|
16
17
|
handlebars.registerHelper(name, fn)
|
|
@@ -25,18 +26,11 @@ handlebars.registerHelper('renderConnectFieldsTable', function (children) {
|
|
|
25
26
|
|
|
26
27
|
const rows = []
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const isArray = field.kind === 'array'
|
|
35
|
-
const nameWithArray = (typeof field.name === 'string' && isArray && !field.name.endsWith('[]'))
|
|
36
|
-
? `${field.name}[]`
|
|
37
|
-
: field.name
|
|
38
|
-
const currentPath = pathPrefix ? `${pathPrefix}.${nameWithArray}` : nameWithArray
|
|
39
|
-
|
|
29
|
+
// The dotted paths, the `[]` array marker and the deprecated-field skipping
|
|
30
|
+
// all come from the shared walker, so this table, the reference-page
|
|
31
|
+
// headings and the connector delta report cannot drift apart.
|
|
32
|
+
flattenConnectFields(children, { arrayMarker: true, skipDeprecated: true })
|
|
33
|
+
.forEach(({ path: currentPath, field }) => {
|
|
40
34
|
// Normalize type
|
|
41
35
|
let displayType
|
|
42
36
|
const isArrayTitle = typeof field.name === 'string' && field.name.endsWith('[]')
|
|
@@ -88,15 +82,7 @@ handlebars.registerHelper('renderConnectFieldsTable', function (children) {
|
|
|
88
82
|
default: defaultValue || '-',
|
|
89
83
|
description: desc || '-'
|
|
90
84
|
})
|
|
91
|
-
|
|
92
|
-
// Recurse for children
|
|
93
|
-
if (field.children && Array.isArray(field.children) && field.children.length > 0) {
|
|
94
|
-
collectFields(field.children, currentPath)
|
|
95
|
-
}
|
|
96
85
|
})
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
collectFields(children, '')
|
|
100
86
|
|
|
101
87
|
if (rows.length === 0) return 'No configuration fields available.\n\n'
|
|
102
88
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared walker for Redpanda Connect field trees.
|
|
5
|
+
*
|
|
6
|
+
* This is a plain module, not a Handlebars helper, so it is deliberately not
|
|
7
|
+
* exported from helpers/index.js. It exists because the same recursion was
|
|
8
|
+
* written four times (the reference-page renderer, the fields-only table
|
|
9
|
+
* extension and the connector delta report), and the copies disagreed about
|
|
10
|
+
* what a field path looks like. The renderer is the authority: the path this
|
|
11
|
+
* module produces must match the `=== ` heading renderConnectFields emits,
|
|
12
|
+
* because the what's-new tables link to those headings.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Field name as it appears in the rendered docs: an array-of-object field
|
|
17
|
+
* carries an `[]` marker so the path is a valid config path.
|
|
18
|
+
* @param {object} field - Field definition
|
|
19
|
+
* @returns {string} Display name for the field
|
|
20
|
+
*/
|
|
21
|
+
function connectFieldName (field) {
|
|
22
|
+
const name = field && field.name;
|
|
23
|
+
if (typeof name === 'string' && field.kind === 'array' && !name.endsWith('[]')) {
|
|
24
|
+
return `${name}[]`;
|
|
25
|
+
}
|
|
26
|
+
return name;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Walk a field tree depth-first and return one entry per field, in the order
|
|
31
|
+
* the fields appear in the source data.
|
|
32
|
+
*
|
|
33
|
+
* A field nested under an existing group (for example
|
|
34
|
+
* `sqs.zero_key_warn_interval` under aws_s3's pre-existing `sqs` group) is
|
|
35
|
+
* only visible to a set-based diff if the tree is flattened first: a map of
|
|
36
|
+
* top-level names alone treats that as no change at all, because `sqs` itself
|
|
37
|
+
* is not new.
|
|
38
|
+
*
|
|
39
|
+
* Nameless nodes are skipped along with their subtree, matching
|
|
40
|
+
* renderConnectFields: a node with no name gets no heading, so nothing under
|
|
41
|
+
* it is addressable in the published docs.
|
|
42
|
+
*
|
|
43
|
+
* @param {Array} children - Field definitions (each may itself have `children`)
|
|
44
|
+
* @param {object} [opts] - { arrayMarker, skipDeprecated, prefix }
|
|
45
|
+
* @param {boolean} [opts.arrayMarker=false] - Append `[]` to array-of-object names
|
|
46
|
+
* @param {boolean} [opts.skipDeprecated=false] - Skip deprecated fields and their subtrees
|
|
47
|
+
* @param {string} [opts.prefix=''] - Dotted path of the parent, if any
|
|
48
|
+
* @returns {Array<{path: string, name: string, parentPath: (string|null), field: object}>}
|
|
49
|
+
*/
|
|
50
|
+
function flattenConnectFields (children, opts = {}) {
|
|
51
|
+
const { arrayMarker = false, skipDeprecated = false, prefix = '' } = opts;
|
|
52
|
+
const result = [];
|
|
53
|
+
|
|
54
|
+
const walk = (list, currentPrefix, parentPath) => {
|
|
55
|
+
if (!Array.isArray(list)) return;
|
|
56
|
+
list.forEach(field => {
|
|
57
|
+
if (!field || !field.name) return;
|
|
58
|
+
if (skipDeprecated && field.is_deprecated) return;
|
|
59
|
+
|
|
60
|
+
const name = arrayMarker ? connectFieldName(field) : field.name;
|
|
61
|
+
const path = currentPrefix ? `${currentPrefix}.${name}` : `${name}`;
|
|
62
|
+
|
|
63
|
+
result.push({ path, name, parentPath, field });
|
|
64
|
+
walk(field.children, path, path);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
walk(children, prefix, prefix || null);
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = { flattenConnectFields, connectFieldName };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const yaml = require('yaml');
|
|
2
2
|
const renderYamlList = require('./renderYamlList');
|
|
3
3
|
const handlebars = require('handlebars');
|
|
4
|
+
const { connectFieldName } = require('./flattenConnectFields');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Renders the children of a configuration object into AsciiDoc.
|
|
@@ -56,11 +57,10 @@ module.exports = function renderConnectFields(children, prefix = '') {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
let block = '';
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
: child.name;
|
|
60
|
+
// Only append [] if kind is array and name does not already end with [].
|
|
61
|
+
// Shared with the delta report and the fields-only table so all three
|
|
62
|
+
// producers agree on what a field path looks like.
|
|
63
|
+
const nameWithArray = connectFieldName(child);
|
|
64
64
|
const currentPath = prefix
|
|
65
65
|
? `${prefix}.${nameWithArray}`
|
|
66
66
|
: `${nameWithArray}`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { execSync } = require('child_process');
|
|
2
|
+
const { flattenConnectFields } = require('./helpers/flattenConnectFields');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Generate a JSON diff report between two connector index objects.
|
|
@@ -54,22 +55,29 @@ function generateConnectorDiffJson(oldIndex, newIndex, opts = {}) {
|
|
|
54
55
|
if (!(cKey in oldMap)) return;
|
|
55
56
|
const oldFields = new Set(oldMap[cKey].fields || []);
|
|
56
57
|
const newFieldsArr = newMap[cKey].fields || [];
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
const added = collapseToTopmost(
|
|
59
|
+
newFieldsArr.filter(fName => !oldFields.has(fName)),
|
|
60
|
+
newMap[cKey].parents
|
|
61
|
+
);
|
|
62
|
+
added.forEach(fName => {
|
|
63
|
+
const rawFieldObj = newMap[cKey].fieldMap.get(fName) || null;
|
|
64
|
+
// A field that arrives already deprecated -- or sits under a
|
|
65
|
+
// deprecated ancestor group -- gets no heading on the reference page,
|
|
66
|
+
// so advertising it under "New field support" would link to a fragment
|
|
67
|
+
// that never exists.
|
|
68
|
+
if (isDeprecatedOrDescendsFromDeprecated(fName, newMap[cKey].fieldMap, newMap[cKey].parents)) return;
|
|
69
|
+
newFields.push({
|
|
70
|
+
component: cKey,
|
|
71
|
+
field: fName,
|
|
72
|
+
// Most fields carry no version of their own, so fall back to the
|
|
73
|
+
// version this diff is comparing against: the field is new as of
|
|
74
|
+
// exactly that release. Some fields do carry `version` (268 entries
|
|
75
|
+
// in connect-4.105.0), and that wins, because it can predate the
|
|
76
|
+
// span being compared: inputs:oracledb_cdc/snapshot_mode reports
|
|
77
|
+
// 4.99.0 in the 4.98.0 to 4.103.1 diff.
|
|
78
|
+
introducedIn: (rawFieldObj && (rawFieldObj.introducedInVersion || rawFieldObj.version)) || opts.newVersion || null,
|
|
79
|
+
description: rawFieldObj && rawFieldObj.description
|
|
80
|
+
});
|
|
73
81
|
});
|
|
74
82
|
});
|
|
75
83
|
|
|
@@ -79,13 +87,15 @@ function generateConnectorDiffJson(oldIndex, newIndex, opts = {}) {
|
|
|
79
87
|
if (!(cKey in newMap)) return;
|
|
80
88
|
const newFieldsSet = new Set(newMap[cKey].fields || []);
|
|
81
89
|
const oldFieldsArr = oldMap[cKey].fields || [];
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
const removed = collapseToTopmost(
|
|
91
|
+
oldFieldsArr.filter(fName => !newFieldsSet.has(fName)),
|
|
92
|
+
oldMap[cKey].parents
|
|
93
|
+
);
|
|
94
|
+
removed.forEach(fName => {
|
|
95
|
+
removedFields.push({
|
|
96
|
+
component: cKey,
|
|
97
|
+
field: fName
|
|
98
|
+
});
|
|
89
99
|
});
|
|
90
100
|
});
|
|
91
101
|
|
|
@@ -172,26 +182,11 @@ function generateConnectorDiffJson(oldIndex, newIndex, opts = {}) {
|
|
|
172
182
|
// Check fields that exist in both versions
|
|
173
183
|
const commonFields = oldFieldsArr.filter(f => newFieldsArr.includes(f));
|
|
174
184
|
commonFields.forEach(fName => {
|
|
175
|
-
const
|
|
185
|
+
const oldFieldObj = oldMap[cKey].fieldMap.get(fName) || null;
|
|
186
|
+
const newFieldObj = newMap[cKey].fieldMap.get(fName) || null;
|
|
176
187
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (type === 'config') {
|
|
180
|
-
oldFieldObj = (oldMap[cKey].raw.children || []).find(f => f.name === fName);
|
|
181
|
-
} else {
|
|
182
|
-
oldFieldObj = (oldMap[cKey].raw.config?.children || []).find(f => f.name === fName);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Get new field object
|
|
186
|
-
let newFieldObj = null;
|
|
187
|
-
if (type === 'config') {
|
|
188
|
-
newFieldObj = (newMap[cKey].raw.children || []).find(f => f.name === fName);
|
|
189
|
-
} else {
|
|
190
|
-
newFieldObj = (newMap[cKey].raw.config?.children || []).find(f => f.name === fName);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const oldDeprecated = oldFieldObj && (oldFieldObj.is_deprecated === true || oldFieldObj.deprecated === true || (oldFieldObj.status || '').toLowerCase() === 'deprecated');
|
|
194
|
-
const newDeprecated = newFieldObj && (newFieldObj.is_deprecated === true || newFieldObj.deprecated === true || (newFieldObj.status || '').toLowerCase() === 'deprecated');
|
|
188
|
+
const oldDeprecated = isDeprecatedField(oldFieldObj);
|
|
189
|
+
const newDeprecated = isDeprecatedField(newFieldObj);
|
|
195
190
|
|
|
196
191
|
if (!oldDeprecated && newDeprecated) {
|
|
197
192
|
deprecatedFields.push({
|
|
@@ -380,6 +375,67 @@ function discoverComponentKeys(obj) {
|
|
|
380
375
|
return Object.keys(obj).filter(key => Array.isArray(obj[key]));
|
|
381
376
|
}
|
|
382
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Whether a field is marked deprecated.
|
|
380
|
+
*
|
|
381
|
+
* Three markers have been used by the source data over time. Only
|
|
382
|
+
* `is_deprecated` appears in current releases (verified across connect-4.63.0,
|
|
383
|
+
* 4.104.0 and 4.105.0: 85, 75 and 75 fields, zero uses of the other two), and
|
|
384
|
+
* it is the one renderConnectFields keys on when it decides not to render a
|
|
385
|
+
* heading for a field.
|
|
386
|
+
*
|
|
387
|
+
* @param {object} field - Field definition, or null
|
|
388
|
+
* @returns {boolean} True when the field is deprecated
|
|
389
|
+
*/
|
|
390
|
+
function isDeprecatedField(field) {
|
|
391
|
+
if (!field) return false;
|
|
392
|
+
return field.is_deprecated === true ||
|
|
393
|
+
field.deprecated === true ||
|
|
394
|
+
(field.status || '').toLowerCase() === 'deprecated';
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* True if `fName` or any of its ancestor fields is deprecated.
|
|
399
|
+
*
|
|
400
|
+
* renderConnectFields never renders a field under a deprecated group (the
|
|
401
|
+
* whole group is hidden), so a leaf-only check reports a field added under an
|
|
402
|
+
* existing-but-deprecated group in "New field support" even though it never
|
|
403
|
+
* appears on the page. Walking the parent chain via `parents` is what
|
|
404
|
+
* catches that.
|
|
405
|
+
*/
|
|
406
|
+
function isDeprecatedOrDescendsFromDeprecated(fName, fieldMap, parents) {
|
|
407
|
+
let current = fName;
|
|
408
|
+
while (current) {
|
|
409
|
+
if (isDeprecatedField(fieldMap.get(current))) return true;
|
|
410
|
+
current = parents && parents.get(current);
|
|
411
|
+
}
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Drop paths whose parent changed in the same way, keeping only the topmost
|
|
417
|
+
* field of each changed subtree.
|
|
418
|
+
*
|
|
419
|
+
* Adding or removing one group adds or removes every field under it, and the
|
|
420
|
+
* flattened field list contains all of them. Reporting each descendant turns
|
|
421
|
+
* a single change into one row per node: removing `batching` from
|
|
422
|
+
* outputs:redpanda_migrator would list `batching` plus batching.count,
|
|
423
|
+
* .byte_size, .period, .check and .processors, and the group row already says
|
|
424
|
+
* all of that. Only the fields added to or removed from a group that still
|
|
425
|
+
* exists are news.
|
|
426
|
+
*
|
|
427
|
+
* @param {Array<string>} changedPaths - Paths that are new (or removed)
|
|
428
|
+
* @param {Map<string, (string|null)>} parents - Path to parent path
|
|
429
|
+
* @returns {Array<string>} The topmost changed path of each subtree, in order
|
|
430
|
+
*/
|
|
431
|
+
function collapseToTopmost(changedPaths, parents) {
|
|
432
|
+
const changed = new Set(changedPaths);
|
|
433
|
+
return changedPaths.filter(path => {
|
|
434
|
+
const parent = parents && parents.get(path);
|
|
435
|
+
return !(parent && changed.has(parent));
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
383
439
|
function buildComponentMap(indexObj) {
|
|
384
440
|
const map = {};
|
|
385
441
|
const types = discoverComponentKeys(indexObj);
|
|
@@ -402,7 +458,14 @@ function buildComponentMap(indexObj) {
|
|
|
402
458
|
}
|
|
403
459
|
}
|
|
404
460
|
|
|
405
|
-
|
|
461
|
+
// arrayMarker keeps the paths identical to the headings
|
|
462
|
+
// renderConnectFields emits, so a field name in the what's-new table is
|
|
463
|
+
// a config path a reader can paste into YAML (`sasl[].aws.tcp`, not the
|
|
464
|
+
// invalid `sasl.aws.tcp`).
|
|
465
|
+
const flattened = flattenConnectFields(childArray, { arrayMarker: true });
|
|
466
|
+
const fieldNames = flattened.map(f => f.path);
|
|
467
|
+
const fieldMap = new Map(flattened.map(f => [f.path, f.field]));
|
|
468
|
+
const parents = new Map(flattened.map(f => [f.path, f.parentPath]));
|
|
406
469
|
|
|
407
470
|
// Preserve platform metadata for accurate diff comparison
|
|
408
471
|
const metadata = {
|
|
@@ -414,6 +477,8 @@ function buildComponentMap(indexObj) {
|
|
|
414
477
|
map[lookupKey] = {
|
|
415
478
|
raw: component,
|
|
416
479
|
fields: fieldNames,
|
|
480
|
+
fieldMap: fieldMap,
|
|
481
|
+
parents: parents,
|
|
417
482
|
metadata: metadata
|
|
418
483
|
};
|
|
419
484
|
});
|
|
@@ -499,8 +564,11 @@ function getRpkConnectVersion() {
|
|
|
499
564
|
* • which connectors/components are brand-new
|
|
500
565
|
* • which new fields appeared under existing connectors (including “config” entries)
|
|
501
566
|
* • for each new component/field, if the raw object contains “version” or “introducedInVersion” or “requiresVersion” metadata, print it
|
|
567
|
+
* @param {object} oldIndex - Previous version connector index
|
|
568
|
+
* @param {object} newIndex - Current version connector index
|
|
569
|
+
* @param {object} [opts] - { newVersion } used as the introducedIn fallback
|
|
502
570
|
*/
|
|
503
|
-
function printDeltaReport(oldIndex, newIndex) {
|
|
571
|
+
function printDeltaReport(oldIndex, newIndex, opts = {}) {
|
|
504
572
|
const oldMap = buildComponentMap(oldIndex);
|
|
505
573
|
const newMap = buildComponentMap(newIndex);
|
|
506
574
|
|
|
@@ -513,27 +581,24 @@ function printDeltaReport(oldIndex, newIndex) {
|
|
|
513
581
|
if (!(cKey in oldMap)) return; // skip brand-new components here
|
|
514
582
|
const oldFields = new Set(oldMap[cKey].fields || []);
|
|
515
583
|
const newFieldsArr = newMap[cKey].fields || [];
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
requiresVersion: requiresVer,
|
|
535
|
-
});
|
|
536
|
-
}
|
|
584
|
+
const added = collapseToTopmost(
|
|
585
|
+
newFieldsArr.filter(fName => !oldFields.has(fName)),
|
|
586
|
+
newMap[cKey].parents
|
|
587
|
+
);
|
|
588
|
+
added.forEach(fName => {
|
|
589
|
+
const rawFieldObj = newMap[cKey].fieldMap.get(fName) || null;
|
|
590
|
+
if (isDeprecatedField(rawFieldObj)) return;
|
|
591
|
+
// Same fallback as generateConnectorDiffJson, so the console report and
|
|
592
|
+
// the published table cannot disagree about the same input.
|
|
593
|
+
const introducedIn = (rawFieldObj && (rawFieldObj.introducedInVersion || rawFieldObj.version)) || opts.newVersion || null;
|
|
594
|
+
const requiresVer = rawFieldObj && rawFieldObj.requiresVersion;
|
|
595
|
+
|
|
596
|
+
newFields.push({
|
|
597
|
+
component: cKey,
|
|
598
|
+
field: fName,
|
|
599
|
+
introducedIn,
|
|
600
|
+
requiresVersion: requiresVer,
|
|
601
|
+
});
|
|
537
602
|
});
|
|
538
603
|
});
|
|
539
604
|
|
|
@@ -560,21 +625,10 @@ function printDeltaReport(oldIndex, newIndex) {
|
|
|
560
625
|
const commonFields = oldFieldsArr.filter(f => newFieldsArr.includes(f));
|
|
561
626
|
|
|
562
627
|
commonFields.forEach(fName => {
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
} else {
|
|
568
|
-
oldFieldObj = (oldMap[cKey].raw.config?.children || []).find(f => f.name === fName);
|
|
569
|
-
}
|
|
570
|
-
let newFieldObj = null;
|
|
571
|
-
if (type === 'config') {
|
|
572
|
-
newFieldObj = (newMap[cKey].raw.children || []).find(f => f.name === fName);
|
|
573
|
-
} else {
|
|
574
|
-
newFieldObj = (newMap[cKey].raw.config?.children || []).find(f => f.name === fName);
|
|
575
|
-
}
|
|
576
|
-
const oldDeprecated = oldFieldObj && (oldFieldObj.is_deprecated === true || oldFieldObj.deprecated === true || (oldFieldObj.status || '').toLowerCase() === 'deprecated');
|
|
577
|
-
const newDeprecated = newFieldObj && (newFieldObj.is_deprecated === true || newFieldObj.deprecated === true || (newFieldObj.status || '').toLowerCase() === 'deprecated');
|
|
628
|
+
const oldFieldObj = oldMap[cKey].fieldMap.get(fName) || null;
|
|
629
|
+
const newFieldObj = newMap[cKey].fieldMap.get(fName) || null;
|
|
630
|
+
const oldDeprecated = isDeprecatedField(oldFieldObj);
|
|
631
|
+
const newDeprecated = isDeprecatedField(newFieldObj);
|
|
578
632
|
if (!oldDeprecated && newDeprecated) {
|
|
579
633
|
deprecatedFieldsList.push({ component: cKey, field: fName });
|
|
580
634
|
}
|
|
@@ -413,7 +413,7 @@ function updateWhatsNew ({ dataDir, oldVersion, newVersion, binaryAnalysis }) {
|
|
|
413
413
|
if (regularFields.length > 0) {
|
|
414
414
|
section += '\n=== New field support\n\n'
|
|
415
415
|
section += 'This release adds support for the following new fields:\n\n'
|
|
416
|
-
section += buildFieldsTable(regularFields, capToTwoSentences)
|
|
416
|
+
section += buildFieldsTable(regularFields, capToTwoSentences, { showIntroducedIn: true })
|
|
417
417
|
}
|
|
418
418
|
}
|
|
419
419
|
|
|
@@ -553,24 +553,35 @@ function fieldAnchor (fieldName) {
|
|
|
553
553
|
* @param {Function} capFn - Caption function
|
|
554
554
|
* @returns {string} AsciiDoc table
|
|
555
555
|
*/
|
|
556
|
-
function buildFieldsTable (fields, capFn) {
|
|
556
|
+
function buildFieldsTable (fields, capFn, opts = {}) {
|
|
557
|
+
const { showIntroducedIn = false } = opts
|
|
557
558
|
const byField = {}
|
|
558
559
|
for (const field of fields) {
|
|
559
560
|
const [type, compName] = field.component.split(':')
|
|
560
|
-
|
|
561
|
-
|
|
561
|
+
// Two components can gain the same field path in different releases
|
|
562
|
+
// (`urls` arrived in 3.58.0 for one and 4.23.0 for another). Merging those
|
|
563
|
+
// into a single row would publish the first version for both, so when the
|
|
564
|
+
// version is on show it is part of the row's identity.
|
|
565
|
+
const key = showIntroducedIn
|
|
566
|
+
? `${field.field}\u0000${field.introducedIn || ''}`
|
|
567
|
+
: field.field
|
|
568
|
+
if (!byField[key]) {
|
|
569
|
+
byField[key] = {
|
|
570
|
+
field: field.field,
|
|
562
571
|
description: field.description,
|
|
572
|
+
introducedIn: field.introducedIn,
|
|
563
573
|
components: []
|
|
564
574
|
}
|
|
565
575
|
}
|
|
566
|
-
byField[
|
|
576
|
+
byField[key].components.push({ type, name: compName })
|
|
567
577
|
}
|
|
568
578
|
|
|
569
|
-
let section = '[cols="1m,3,2a"]\n'
|
|
579
|
+
let section = showIntroducedIn ? '[cols="1m,3,2a,1m"]\n' : '[cols="1m,3,2a"]\n'
|
|
570
580
|
section += '|===\n'
|
|
571
|
-
section += '|Field |Description |Affected components\n\n'
|
|
581
|
+
section += showIntroducedIn ? '|Field |Description |Affected components |Introduced in\n\n' : '|Field |Description |Affected components\n\n'
|
|
572
582
|
|
|
573
|
-
for (const
|
|
583
|
+
for (const info of Object.values(byField)) {
|
|
584
|
+
const fieldName = info.field
|
|
574
585
|
const byType = {}
|
|
575
586
|
for (const comp of info.components) {
|
|
576
587
|
if (!byType[comp.type]) byType[comp.type] = []
|
|
@@ -595,7 +606,9 @@ function buildFieldsTable (fields, capFn) {
|
|
|
595
606
|
|
|
596
607
|
section += `|${fieldName}\n`
|
|
597
608
|
section += `|${desc}\n`
|
|
598
|
-
section += `|${componentList}\n
|
|
609
|
+
section += `|${componentList}\n`
|
|
610
|
+
if (showIntroducedIn) section += `|${info.introducedIn || '-'}\n`
|
|
611
|
+
section += '\n'
|
|
599
612
|
}
|
|
600
613
|
|
|
601
614
|
section += '|===\n\n'
|
|
@@ -1475,7 +1488,7 @@ async function handleRpcnConnectorDocs (options) {
|
|
|
1475
1488
|
}
|
|
1476
1489
|
}
|
|
1477
1490
|
|
|
1478
|
-
printDeltaReport(oldIndexForDiff, newIndex)
|
|
1491
|
+
printDeltaReport(oldIndexForDiff, newIndex, { newVersion })
|
|
1479
1492
|
|
|
1480
1493
|
const { generateConnectorDiffJson } = require('./report-delta.js')
|
|
1481
1494
|
diffJson = generateConnectorDiffJson(
|