@redpanda-data/docs-extensions-and-macros 5.54.0 → 5.56.0

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.
Files changed (87) hide show
  1. package/bin/doc-tools-mcp.js +4 -5
  2. package/bin/doc-tools.js +354 -9
  3. package/bin/mcp-tools/generated-docs-review.js +26 -9
  4. package/bin/mcp-tools/overrides-audit.js +1 -1
  5. package/bin/mcp-tools/rpcn-docs.js +4 -14
  6. package/cli-utils/docs-links-to-xrefs.js +174 -0
  7. package/cli-utils/format-helm-spec.js +4 -3
  8. package/cli-utils/generated-marker.js +43 -0
  9. package/cli-utils/helm-commented-values.js +125 -21
  10. package/cli-utils/self-managed-docs-branch.js +36 -30
  11. package/extension-utils/html-utils.js +27 -0
  12. package/extension-utils/llms-utils.js +6 -2
  13. package/extension-utils/metadata-candidates.js +304 -0
  14. package/extension-utils/metadata-check.js +174 -0
  15. package/extension-utils/metadata-suggest.js +573 -0
  16. package/extension-utils/taxonomy-categories.js +106 -0
  17. package/extension-utils/taxonomy.js +566 -0
  18. package/extensions/REFERENCE.adoc +110 -8
  19. package/extensions/add-git-dates.js +13 -1
  20. package/extensions/aggregate-terms.js +34 -20
  21. package/extensions/algolia-indexer/generate-index.js +13 -1
  22. package/extensions/algolia-indexer/index.js +4 -2
  23. package/extensions/convert-sitemap-to-markdown.js +47 -12
  24. package/extensions/convert-to-markdown.js +176 -0
  25. package/extensions/generate-fields-only-pages.js +14 -0
  26. package/extensions/modify-connect-tag-playbook.js +181 -3
  27. package/extensions/resolve-xrefs-in-attachments.js +1 -12
  28. package/extensions/url-to-xref.js +92 -22
  29. package/extensions/util/connect-docs-asset.js +6 -5
  30. package/extensions/validate-attributes.js +10 -1
  31. package/extensions/version-fetcher/fetch-latest-docker-tag.js +35 -13
  32. package/extensions/version-fetcher/get-latest-redpanda-helm-version-from-operator.js +64 -40
  33. package/extensions/version-fetcher/list-connect-releases.js +3 -3
  34. package/extensions/version-fetcher/release-lines.js +64 -0
  35. package/extensions/version-fetcher/set-latest-version.js +73 -3
  36. package/macros/README.adoc +1 -0
  37. package/macros/REFERENCE.adoc +99 -0
  38. package/macros/badge.js +5 -8
  39. package/macros/enterprise.js +2 -5
  40. package/macros/glossary.js +4 -14
  41. package/macros/iceberg-explorer.js +242 -0
  42. package/macros/prop.js +3 -13
  43. package/mcp/USER_GUIDE.adoc +25 -135
  44. package/package.json +5 -2
  45. package/tools/check-metadata/index.js +523 -0
  46. package/tools/cloud-regions/cloud-regions-table-adoc.hbs +1 -2
  47. package/tools/cloud-regions/cloud-regions-table-md.hbs +2 -2
  48. package/tools/cloud-regions/render-cloud-regions.js +3 -0
  49. package/tools/dispatch-graph/check-dispatch-graph.js +790 -0
  50. package/tools/dispatch-graph/classify-runs.js +128 -0
  51. package/tools/dispatch-graph/parse-workflows.js +499 -0
  52. package/tools/doc-impact-recording/index.js +190 -0
  53. package/tools/enterprise-features/detect-gating-changes.js +393 -0
  54. package/tools/enterprise-features/verify.js +2 -1
  55. package/tools/gen-rpk-ascii.py +7 -1
  56. package/tools/lint-strings/fixtures/connect/lint_connect.go +8 -0
  57. package/tools/lint-strings/fixtures/crd/lint_types.go +4 -1
  58. package/tools/lint-strings/fixtures/rpk-pr461/delete.base.go +42 -0
  59. package/tools/lint-strings/fixtures/rpk-pr461/delete.head.go +45 -0
  60. package/tools/lint-strings/fixtures/rpk-pr461/reviewer-comments.json +1 -0
  61. package/tools/lint-strings/index.js +133 -3
  62. package/tools/lint-strings/rules/verbatim-asciidoc.js +166 -1
  63. package/tools/lint-strings/surfaces/connect.js +72 -12
  64. package/tools/lint-strings/surfaces/crd.js +10 -6
  65. package/tools/metrics/metrics.py +11 -0
  66. package/tools/overrides-audit/README.adoc +1 -2
  67. package/tools/overrides-audit/adapters/properties.js +1 -1
  68. package/tools/overrides-audit/index.js +3 -4
  69. package/tools/property-extractor/generate-handlebars-docs.js +9 -1
  70. package/tools/property-extractor/helpers/applyPropertyLinks.js +35 -0
  71. package/tools/redpanda-connect/AUTOMATION.md +3 -36
  72. package/tools/redpanda-connect/README.adoc +5 -33
  73. package/tools/redpanda-connect/generate-rpcn-connector-docs.js +32 -11
  74. package/tools/redpanda-connect/pr-summary-formatter.js +6 -4
  75. package/tools/redpanda-connect/report-delta.js +6 -3
  76. package/tools/redpanda-connect/rpcn-connector-docs-handler.js +42 -25
  77. package/tools/redpanda-connect/templates/bloblang-function.hbs +1 -1
  78. package/tools/redpanda-connect/templates/descriptions-partials.hbs +1 -1
  79. package/tools/redpanda-connect/templates/examples-partials.hbs +1 -1
  80. package/tools/redpanda-connect/templates/fields-partials.hbs +2 -2
  81. package/tools/redpanda-connect/templates/metadata-partials.hbs +1 -1
  82. package/tools/redpanda-release-notes/generate-release-notes.js +116 -1
  83. package/tools/rpk-docs/generate-rpk-docs.js +2 -0
  84. package/tools/rpk-docs/generate-x-env-partial.js +7 -4
  85. package/tools/rpk-docs/helpers/index.js +4 -1
  86. package/tools/rpk-docs/templates/command.hbs +2 -2
  87. package/tools/overrides-audit/adapters/connect.js +0 -144
@@ -23,6 +23,16 @@ These output files are stored in a versioned folder under `docs/autogenerated/<v
23
23
 
24
24
  logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
25
25
 
26
+
27
+ def generated_marker(generator, source, hint=""):
28
+ """Same marker shape as cli-utils/generated-marker.js (no version, so a
29
+ release does not rewrite every file); convert-to-markdown reads it."""
30
+ marker = (
31
+ "// This content is autogenerated. Do not edit manually. "
32
+ f"Generated by doc-tools ({generator}) from {source.rstrip('.')}."
33
+ )
34
+ return marker + (f" {hint.strip()}" if hint.strip() else "")
35
+
26
36
  def fetch_metrics(url):
27
37
  """Fetch metrics from the given URL."""
28
38
  try:
@@ -123,6 +133,7 @@ def parse_metrics(metrics_text):
123
133
  def output_asciidoc(metrics, adoc_file):
124
134
  """Output metrics as AsciiDoc."""
125
135
  with open(adoc_file, "w") as f:
136
+ f.write(generated_marker("metrics-docs", "the metrics Redpanda exposes, defined in redpanda-data/streaming-enterprise") + "\n\n")
126
137
  for name, data in metrics.items():
127
138
  f.write(f"=== {name}\n\n")
128
139
  f.write(f"{data['description']}\n\n")
@@ -22,7 +22,7 @@ npx doc-tools overrides audit \
22
22
  --format human
23
23
 
24
24
  # Standalone
25
- node tools/overrides-audit/index.js --overrides <path> --extracted <path> [--surface properties|rpk|connect] [--format json|human] [--output <file>]
25
+ node tools/overrides-audit/index.js --overrides <path> --extracted <path> [--surface properties|rpk] [--format json|human] [--output <file>]
26
26
  ----
27
27
 
28
28
  IMPORTANT: `--extracted` must be the property extractor's *raw* output (the `--output` file), never the enhanced output (`--enhanced-output`) or the versioned `redpanda-properties-<tag>.json` attachments: those already have overrides applied, so every override would classify as REDUNDANT. The same trap exists for rpk: the versioned `rpk-v<version>.json` files in docs repos are post-override snapshots.
@@ -133,7 +133,6 @@ JSON (default): `{ surface, overrides_file, extracted_file, manifest, summary, c
133
133
 
134
134
  * `properties` (complete): `property-overrides.json` vs the property extractor's raw JSON.
135
135
  * `rpk` (structural): enumerates `rpk-overrides.json` (see `docs-data/rpk-overrides.schema.json`) -- command/flag `description` fields are the upstreamable prose (classified `REVIEW` with a TODO note until source comparison lands; it needs a raw pre-override `--print-tree` snapshot plus the `formatDescription()` pipeline from `tools/rpk-docs`), everything else (`seeAlso`, `pageAliases`, `content`, platform scoping, ...) is `KEEP` by design.
136
- * `connect` (structural): enumerates the rp-connect-docs `overrides.json` (`definitions` + per-component arrays with nested `config.children`); prose fields classify `REVIEW` with a TODO note until `$ref` resolution and plugin-JSON comparison land.
137
136
 
138
137
  == Golden run (local checkouts required)
139
138
 
@@ -4,7 +4,7 @@
4
4
  * Reads docs-data/property-overrides.json and an extracted-properties JSON
5
5
  * (the property extractor's raw --output, WITHOUT overrides applied) and
6
6
  * classifies every override field. This is the complete reference adapter;
7
- * rpk and connect adapters follow the same shape.
7
+ * The rpk adapter follows the same shape.
8
8
  */
9
9
 
10
10
  'use strict'
@@ -12,7 +12,7 @@
12
12
  * node tools/overrides-audit/index.js \
13
13
  * --overrides docs-data/property-overrides.json \
14
14
  * --extracted tools/property-extractor/gen/properties-output.json \
15
- * [--surface properties|rpk|connect] [--format json|human] [--output <file>]
15
+ * [--surface properties|rpk] [--format json|human] [--output <file>]
16
16
  *
17
17
  * Also exposed as `doc-tools overrides audit` and the `audit_overrides`
18
18
  * MCP tool. See README.adoc in this directory for the classification rules
@@ -26,8 +26,7 @@ const path = require('path')
26
26
 
27
27
  const ADAPTERS = {
28
28
  properties: () => require('./adapters/properties'),
29
- rpk: () => require('./adapters/rpk'),
30
- connect: () => require('./adapters/connect')
29
+ rpk: () => require('./adapters/rpk')
31
30
  }
32
31
 
33
32
  /**
@@ -153,7 +152,7 @@ function main (argv) {
153
152
  .description('Classify docs-side override fields against extracted source strings')
154
153
  .requiredOption('--overrides <path>', 'Path to the overrides JSON file (for example docs-data/property-overrides.json)')
155
154
  .option('--extracted <path>', 'Path to the extracted source JSON (property extractor raw output; required for the properties surface)')
156
- .option('--surface <surface>', 'Override surface: properties, rpk, or connect', 'properties')
155
+ .option('--surface <surface>', 'Override surface: properties or rpk', 'properties')
157
156
  .option('--format <format>', 'Output format: json or human', 'json')
158
157
  .option('--output <path>', 'Also write the JSON result to this file')
159
158
  .action((options) => {
@@ -2,10 +2,18 @@
2
2
  // writer already has open. The previous pointer was a Confluence page, and
3
3
  // Confluence is retired, so it sent every writer who read this line to a dead
4
4
  // end. A repo-relative path cannot rot the same way.
5
- const AUTOGEN_NOTICE = '// This content is autogenerated. Do not edit manually. To change a description, add a link, or scope text to one docs build, edit docs-data/property-overrides.json (fields are documented in docs-data/property-overrides.schema.json and docs-data/README.adoc) and regenerate.\n';
6
5
  'use strict';
7
6
 
8
7
  const fs = require('fs');
8
+ const { generatedMarker } = require('../../cli-utils/generated-marker');
9
+
10
+ // The marker's shape is shared by every generator and read by the
11
+ // convert-to-markdown extension, which exports it to the Markdown twins.
12
+ const AUTOGEN_NOTICE = generatedMarker(
13
+ 'property-docs',
14
+ 'the configuration property definitions in redpanda-data/streaming-enterprise',
15
+ 'To change a description, add a link, or scope text to one docs build, edit docs-data/property-overrides.json (fields are documented in docs-data/property-overrides.schema.json and docs-data/README.adoc) and regenerate.'
16
+ ) + '\n';
9
17
  const bigIntJson = require('../../cli-utils/big-int-json');
10
18
  const path = require('path');
11
19
  const handlebars = require('handlebars');
@@ -419,6 +419,39 @@ function normalizeIncludes(propName, raw, warnings) {
419
419
  return out;
420
420
  }
421
421
 
422
+ /**
423
+ * Remove the inline copies of `includes` that the attachment write-back appended.
424
+ *
425
+ * generate-handlebars-docs.js writes each include back into the description
426
+ * on disk, so the attachment's tooltip still renders it, and leaves `includes`
427
+ * in place. A run that reads that file again (a reused gen/<tag>-properties.json,
428
+ * or generate-docs run twice without re-extraction) sees the directive in the
429
+ * description and in `includes`, and the template rendered it twice. Only the
430
+ * exact shapes the write-back produces are
431
+ * removed, so an include a human put in the prose is left alone.
432
+ *
433
+ * @param {string|undefined} description - Flattened description.
434
+ * @param {Array<{target: string, cloud_only?: boolean, self_managed_only?: boolean}>} items - Normalized includes.
435
+ * @returns {string|undefined}
436
+ */
437
+ function stripInlineIncludes(description, items) {
438
+ if (typeof description !== 'string' || !description.includes('include::')) return description;
439
+ let text = description;
440
+ // The write-back appends in order, so peel from the end.
441
+ for (const item of [...items].reverse()) {
442
+ const directive = `include::${item.target}`;
443
+ let block = directive;
444
+ if (item.cloud_only) block = `ifdef::env-cloud[]\n${directive}\nendif::[]`;
445
+ else if (item.self_managed_only) block = `ifndef::env-cloud[]\n${directive}\nendif::[]`;
446
+ if (text.endsWith(`\n\n${block}`)) {
447
+ text = text.slice(0, -(block.length + 2));
448
+ } else if (text === block) {
449
+ text = '';
450
+ }
451
+ }
452
+ return text;
453
+ }
454
+
422
455
  /**
423
456
  * Why the Cloud build cannot reach a link target, or null when it can.
424
457
  *
@@ -471,6 +504,7 @@ function applyPropertyLinks(properties) {
471
504
  }
472
505
  if (prop.includes !== undefined) {
473
506
  prop.includes = normalizeIncludes(propName, prop.includes, warnings);
507
+ prop.description = stripInlineIncludes(prop.description, prop.includes);
474
508
  }
475
509
  if (Array.isArray(prop.admonitions)) {
476
510
  prop.admonitions = prop.admonitions.filter((item) => {
@@ -589,3 +623,4 @@ module.exports.applyLinksToText = applyLinksToText;
589
623
  module.exports.renderLink = renderLink;
590
624
  module.exports.cloudUnreachable = cloudUnreachable;
591
625
  module.exports.normalizeIncludes = normalizeIncludes;
626
+ module.exports.stripInlineIncludes = stripInlineIncludes;
@@ -581,7 +581,7 @@ npx doc-tools generate rpcn-connector-docs \
581
581
  | `--draft-missing` | Generate full page drafts for new connectors | false |
582
582
  | `--update-whats-new` | Update whats-new.adoc with changes | false |
583
583
  | `--include-bloblang` | Include Bloblang functions/methods | false |
584
- | `--overrides <path>` | JSON file with description overrides | `docs-data/overrides.json` |
584
+ | `--overrides <path>` | Optional JSON file with description overrides | None |
585
585
 
586
586
  ### Examples
587
587
 
@@ -766,41 +766,8 @@ Templates are in `tools/redpanda-connect/templates/`:
766
766
  - `connector-examples.hbs` - Examples template
767
767
  - `connector-full.hbs` - Full page draft template
768
768
 
769
- ### Updating Overrides
770
- Override file: `docs-data/overrides.json` (or `--overrides` flag)
771
-
772
- ```json
773
- {
774
- "inputs": {
775
- "kafka": {
776
- "fields": {
777
- "addresses": {
778
- "description": "Custom description override",
779
- "examples": ["localhost:9092"]
780
- }
781
- }
782
- }
783
- }
784
- }
785
- ```
786
-
787
- Supports `$ref` syntax for deduplication:
788
- ```json
789
- {
790
- "inputs": {
791
- "kafka": {
792
- "fields": {
793
- "tls": { "$ref": "#/common/tls" }
794
- }
795
- }
796
- },
797
- "common": {
798
- "tls": {
799
- "description": "TLS configuration (reused across components)"
800
- }
801
- }
802
- }
803
- ```
769
+ ### Fixing connector descriptions
770
+ Field, component, and Bloblang descriptions come from the component specs in `redpanda-data/connect` and `redpanda-data/benthos`. To fix wrong or missing text, open a PR against the spec. The fix ships in the next Connect release.
804
771
 
805
772
  ## Troubleshooting
806
773
 
@@ -46,11 +46,6 @@ npm install @redpanda-data/docs-extensions-and-macros
46
46
  # Generate connector documentation with latest data
47
47
  npx doc-tools generate rpcn-connector-docs --fetch-connectors
48
48
 
49
- # Generate with custom overrides
50
- npx doc-tools generate rpcn-connector-docs \
51
- --fetch-connectors \
52
- --overrides path/to/overrides.json
53
-
54
49
  # Generate and draft missing connectors
55
50
  npx doc-tools generate rpcn-connector-docs \
56
51
  --fetch-connectors \
@@ -176,11 +171,6 @@ You can generate connector documentation with various options:
176
171
  # Basic generation with fetching latest data
177
172
  npx doc-tools generate rpcn-connector-docs --fetch-connectors
178
173
 
179
- # Generate with custom overrides for descriptions/examples
180
- npx doc-tools generate rpcn-connector-docs \
181
- --fetch-connectors \
182
- --overrides overrides.json
183
-
184
174
  # Draft full pages for connectors missing documentation
185
175
  npx doc-tools generate rpcn-connector-docs \
186
176
  --fetch-connectors \
@@ -202,7 +192,7 @@ npx doc-tools generate rpcn-connector-docs \
202
192
  * `--fetch-connectors` - Fetch latest data using `rpk connect list`
203
193
  * `--connect-version <version>` - Specific Connect version to install and fetch (requires `--fetch-connectors`)
204
194
  * `--draft-missing` - Generate full draft pages for undocumented connectors
205
- * `--overrides <path>` - Apply custom descriptions/examples from JSON
195
+ * `--overrides <path>` - Merge descriptions and examples from an optional JSON file. Nothing is merged unless you pass it
206
196
  * `--data-dir <path>` - Directory containing versioned connect JSON files
207
197
  * `--old-data <path>` - Specific old version file for diff comparison
208
198
  * `--include-bloblang` - Include Bloblang functions/methods
@@ -791,7 +781,9 @@ console.log('<!-- PR_SUMMARY_END -->');
791
781
 
792
782
  === Override system
793
783
 
794
- Overrides allow customizing extracted documentation:
784
+ Connector field, component, and Bloblang descriptions come from the component specs in https://github.com/redpanda-data/connect[redpanda-data/connect^] and https://github.com/redpanda-data/benthos[redpanda-data/benthos^]. To fix wrong or missing text, open a PR against the spec. The fix ships in the next Connect release.
785
+
786
+ The generator can also merge an optional JSON file passed with `--overrides` into the extracted data. Nothing is merged unless you pass the flag:
795
787
 
796
788
  [,json]
797
789
  ----
@@ -840,11 +832,9 @@ Overrides support:
840
832
  * Connector catalog enrichment
841
833
  * Version tracking and change detection
842
834
  * Handlebars template rendering
843
- * Override system for custom documentation
844
835
 
845
836
  === Current limitations
846
837
 
847
- * *Manual override maintenance*: Custom descriptions must be maintained in overrides.json
848
838
  * *Example quality*: Auto-generated examples may not represent best practices
849
839
  * *Duplicate YAML keys*: Some examples contain multiple configurations in one block, creating invalid YAML with duplicate top-level keys (for example, multiple `processors:` keys)
850
840
  * *CSV catalog dependency*: Relies on manually maintained CSV in Connect repository
@@ -876,25 +866,7 @@ This occurs when multiple separate configurations are concatenated into a single
876
866
 
877
867
  === Workarounds
878
868
 
879
- For unsupported patterns or issues, use overrides.json:
880
-
881
- [,json]
882
- ----
883
- {
884
- "inputs": [
885
- {
886
- "name": "problematic_connector",
887
- "description": "Custom description overriding auto-extracted text",
888
- "examples": [
889
- {
890
- "title": "Corrected example",
891
- "config": "input:\n problematic_connector:\n field: value"
892
- }
893
- ]
894
- }
895
- ]
896
- }
897
- ----
869
+ To fix an unsupported pattern, a wrong description, or a broken example, edit the component spec in redpanda-data/connect or redpanda-data/benthos. The fix ships in the next Connect release.
898
870
 
899
871
  == Contributing
900
872
 
@@ -17,6 +17,9 @@ Object.entries(helpers).forEach(([name, fn]) => {
17
17
  }
18
18
  handlebars.registerHelper(name, fn);
19
19
  });
20
+ // The provenance marker the partial templates write on their first line
21
+ const { generatedMarker } = require('../../cli-utils/generated-marker');
22
+ handlebars.registerHelper('generatedMarker', generatedMarker);
20
23
 
21
24
  // Default “main” template (connector.hbs) which invokes partials {{> intro}}, {{> fields}}, {{> examples}}
22
25
  const DEFAULT_TEMPLATE = path.resolve(__dirname, './templates/connector.hbs');
@@ -34,9 +37,12 @@ const { hasStructuralHeadings, hasMarkdownHeadings, firstHeadingDepth, escapePla
34
37
  // section is removed upstream. Kept as an AsciiDoc comment so the file renders
35
38
  // nothing while any lingering include directive still resolves cleanly.
36
39
  const STALE_METADATA_PARTIAL =
37
- '// This content is autogenerated. Do not edit manually. ' +
38
- 'The connector description no longer contains a `== Metadata` section, so this partial is intentionally empty. ' +
39
- 'You can remove the include directive that points at this file from the connector page.\n';
40
+ generatedMarker(
41
+ 'rpcn-connector-docs',
42
+ 'the component spec in redpanda-data/connect',
43
+ 'The connector description no longer contains a `== Metadata` section, so this partial is intentionally empty. ' +
44
+ 'You can remove the include directive that points at this file from the connector page.'
45
+ ) + '\n';
40
46
 
41
47
  // Banner-only content written to a description partial when the connector's
42
48
  // description is removed upstream. Same rationale as STALE_METADATA_PARTIAL:
@@ -50,12 +56,27 @@ const STALE_METADATA_PARTIAL =
50
56
  // every page that includes it, on every build, which is a build failure
51
57
  // wherever Asciidoctor warnings are treated as errors. An empty region
52
58
  // resolves to nothing and says nothing.
53
- const STALE_DESCRIPTION_PARTIAL =
54
- '// This content is autogenerated. Do not edit manually. ' +
55
- 'The connector no longer has a description, so this partial is intentionally empty. ' +
56
- 'You can remove the include directive that points at this file from the connector page.\n' +
59
+ const STALE_DESCRIPTION_REGIONS =
57
60
  '\n// tag::meta[]\n// end::meta[]\n' +
58
61
  '\n// tag::body[]\n// end::body[]\n';
62
+ const STALE_DESCRIPTION_PARTIAL =
63
+ generatedMarker(
64
+ 'rpcn-connector-docs',
65
+ 'the component spec in redpanda-data/connect',
66
+ 'The connector no longer has a description, so this partial is intentionally empty. ' +
67
+ 'You can remove the include directive that points at this file from the connector page.'
68
+ ) + '\n' + STALE_DESCRIPTION_REGIONS;
69
+ // What earlier releases wrote for the same blanked partial. The orphan sweep
70
+ // treats either as already blanked, so a partial emptied before the marker
71
+ // changed is not re-blanked and re-reported. The marker carries no version,
72
+ // so this list grows only when the wording does.
73
+ const STALE_DESCRIPTION_PARTIALS = new Set([
74
+ STALE_DESCRIPTION_PARTIAL,
75
+ '// This content is autogenerated. Do not edit manually. ' +
76
+ 'The connector no longer has a description, so this partial is intentionally empty. ' +
77
+ 'You can remove the include directive that points at this file from the connector page.\n' +
78
+ STALE_DESCRIPTION_REGIONS,
79
+ ]);
59
80
 
60
81
  // Component families with their own reference pages, keyed by the canonical
61
82
  // type directory from typeDirFor(). Other data keys -- `config`, the bloblang
@@ -101,9 +122,9 @@ function mergeOverrides(target, overrides) {
101
122
  throw new Error('Target must be a valid object');
102
123
  }
103
124
 
104
- // 'summary' earns its place here the hard way: overrides.json has carried
105
- // summary overrides (zmq4, ffi) that were silently dropped because the key
106
- // fell through every branch below. Summaries feed page meta descriptions.
125
+ // Scalar keys are replaced outright. 'summary' must be listed: a key that
126
+ // falls through every branch below is silently dropped, and summaries feed
127
+ // page meta descriptions.
107
128
  const scalarKeys = ['description', 'summary', 'type', 'annotated_field', 'version'];
108
129
 
109
130
  for (const key in overrides) {
@@ -932,7 +953,7 @@ async function generateRpcnConnectorDocs(options) {
932
953
  const orphanPath = path.join(typeDirPath, file);
933
954
  // Already blanked on an earlier run: leave it alone so it is not
934
955
  // re-reported forever.
935
- if (fs.readFileSync(orphanPath, 'utf8') === STALE_DESCRIPTION_PARTIAL) continue;
956
+ if (STALE_DESCRIPTION_PARTIALS.has(fs.readFileSync(orphanPath, 'utf8'))) continue;
936
957
  orphans.push({ key, orphanPath });
937
958
  }
938
959
  }
@@ -179,7 +179,7 @@ function renderStyleRegressionWarnings(warnings) {
179
179
  if (!Array.isArray(warnings) || warnings.length === 0) return [];
180
180
  const lines = [];
181
181
  lines.push('> [!WARNING]');
182
- lines.push('> **This update reintroduces house-style issues that the published docs do not have.** The fix belongs upstream in the Connect source, or in `docs-data/overrides.json`: correcting the generated partial is undone by the next regeneration.');
182
+ lines.push('> **This update reintroduces house-style issues that the published docs do not have.** The fix belongs upstream in the connect or benthos component spec: correcting the generated partial is undone by the next regeneration.');
183
183
  for (const w of warnings) {
184
184
  lines.push(`> - \`${w.partial}\` adds: ${w.issues.join(', ')}`);
185
185
  }
@@ -323,7 +323,8 @@ function generateMultiVersionPRSummary(masterDiff, binaryAnalysis = null, drafte
323
323
  lines.push('|-----------|-------|-------------|');
324
324
 
325
325
  newFields.forEach(field => {
326
- const desc = field.description ? truncateToSentence(field.description, 1).replace(/\|/g, '\\|') : '_No description_';
326
+ const text = field.shortDescription || field.description;
327
+ const desc = text ? truncateToSentence(text, 1).replace(/\|/g, '\\|') : '_No description_';
327
328
  lines.push(`| \`${field.component}\` | \`${field.field}\` | ${desc} |`);
328
329
  });
329
330
  lines.push('');
@@ -359,7 +360,8 @@ function generateMultiVersionPRSummary(masterDiff, binaryAnalysis = null, drafte
359
360
  lines.push(`**Deprecated Fields (${summary.deprecatedFields}):**`);
360
361
  lines.push('');
361
362
  deprecatedFields.forEach(field => {
362
- const guidance = field.description ? ` — ${truncateToSentence(field.description, 1)}` : '';
363
+ const text = field.shortDescription || field.description;
364
+ const guidance = text ? ` — ${truncateToSentence(text, 1)}` : '';
363
365
  lines.push(`- \`${field.component}.${field.field}\`${guidance}`);
364
366
  });
365
367
  lines.push('');
@@ -436,7 +438,7 @@ function generateMultiVersionPRSummary(masterDiff, binaryAnalysis = null, drafte
436
438
  allDeprecatedFields.push({
437
439
  component: field.component,
438
440
  field: field.field,
439
- description: field.description,
441
+ description: field.shortDescription || field.description,
440
442
  version: release.toVersion
441
443
  });
442
444
  });
@@ -77,7 +77,8 @@ function generateConnectorDiffJson(oldIndex, newIndex, opts = {}) {
77
77
  // span being compared: inputs:oracledb_cdc/snapshot_mode reports
78
78
  // 4.99.0 in the 4.98.0 to 4.103.1 diff.
79
79
  introducedIn: (rawFieldObj && (rawFieldObj.introducedInVersion || rawFieldObj.version)) || opts.newVersion || null,
80
- description: rawFieldObj && rawFieldObj.description
80
+ description: rawFieldObj && rawFieldObj.description,
81
+ shortDescription: rawFieldObj && rawFieldObj.short_description
81
82
  });
82
83
  });
83
84
  });
@@ -193,7 +194,8 @@ function generateConnectorDiffJson(oldIndex, newIndex, opts = {}) {
193
194
  deprecatedFields.push({
194
195
  component: cKey,
195
196
  field: fName,
196
- description: newFieldObj && newFieldObj.description
197
+ description: newFieldObj && newFieldObj.description,
198
+ shortDescription: newFieldObj && newFieldObj.short_description
197
199
  });
198
200
  }
199
201
 
@@ -212,7 +214,8 @@ function generateConnectorDiffJson(oldIndex, newIndex, opts = {}) {
212
214
  field: fName,
213
215
  oldDefault: oldDefault,
214
216
  newDefault: newDefault,
215
- description: newFieldObj && newFieldObj.description
217
+ description: newFieldObj && newFieldObj.description,
218
+ shortDescription: newFieldObj && newFieldObj.short_description
216
219
  });
217
220
  }
218
221
  }
@@ -30,11 +30,9 @@ function capToTwoSentences (description) {
30
30
  }
31
31
 
32
32
  const abbreviations = [
33
- /https?:\/\/[^\s]+?(?=[.!?](?:\s|$)|\s|$)/gi, // Protect URLs from being split by sentence detection (non-greedy, preserve trailing punctuation)
34
- /\bxref:[^\s[\]]+\[[^\]]*\]/g, // Protect Antora xref macros (e.g. xref:components:processors/try.adoc[`try`]) whose targets contain periods
35
- /\b[\w/-]+\.(?:adoc|md|ya?ml|json|html)\b/gi, // Protect bare doc/config filenames (try.adoc, config.yaml) from splitting
36
- /\bv\d+\.\d+(?:\.\d+)?/gi,
37
- /\d+\.\d+/g,
33
+ // A period inside a token (a URL, an xref target, a filename, a version
34
+ // or a decimal) has no whitespace after it, so it never ends a sentence.
35
+ // Only abbreviations that are followed by a space need protecting.
38
36
  /\be\.g\./gi,
39
37
  /\bi\.e\./gi,
40
38
  /\betc\./gi,
@@ -47,6 +45,21 @@ function capToTwoSentences (description) {
47
45
  /\bNo\./gi
48
46
  ]
49
47
 
48
+ // A table cell takes one paragraph of plain text. Keep only the text before
49
+ // the first blank line or list item, so a description such as
50
+ // "Controls how X is sized:\n\n- `a`: ...\n- `b`: ..." does not leak half a
51
+ // list into the cell. A lead-in that ends with a colon is left unterminated
52
+ // so the sentence match below drops it whenever a complete sentence comes
53
+ // before it ("Configure TCP settings. These controls are useful for:" keeps
54
+ // only the first sentence). Only a lead-in with nothing before it is kept,
55
+ // with the colon turned into a period.
56
+ let colonLeadIn = false
57
+ const firstBlock = description.split(/\n\s*\n|\n(?=\s*(?:[-*]|\d+\.)\s)/)[0].trim()
58
+ if (firstBlock && firstBlock !== description.trim() && !/^(?:[=#]|```|----)/.test(firstBlock)) {
59
+ description = firstBlock
60
+ colonLeadIn = firstBlock.endsWith(':')
61
+ }
62
+
50
63
  let normalized = description
51
64
  const placeholders = []
52
65
 
@@ -64,25 +77,19 @@ function capToTwoSentences (description) {
64
77
  return placeholder
65
78
  })
66
79
 
67
- const sentenceRegex = /[^.!?]+[.!?]+(?:\s|$)/g
68
- const sentences = normalized.match(sentenceRegex)
69
-
70
- // If an unprotected mid-token period prevented the leading text from
71
- // forming a complete match, merge that dropped prefix into the first
72
- // sentence rather than silently discarding it.
73
- if (sentences && sentences.length > 0) {
74
- const firstIndex = normalized.indexOf(sentences[0])
75
- if (firstIndex > 0) {
76
- sentences[0] = normalized.slice(0, firstIndex) + sentences[0]
77
- }
78
- }
80
+ // A sentence ends at punctuation, optionally followed by a closing quote,
81
+ // parenthesis or bracket, then whitespace or the end of the text. Matching
82
+ // lazily up to that boundary keeps a period inside a token, such as the
83
+ // dotted name partition.assignment.strategy, in its sentence. Text after the
84
+ // last match (an unterminated colon lead-in, for example) is dropped.
85
+ const sentences = normalized.match(/[\s\S]+?[.!?]+["')\]`]*(?:\s|$)/g)
79
86
 
80
87
  if (!sentences || sentences.length === 0) {
81
88
  let result = normalized
82
89
  placeholders.forEach(({ placeholder, original }) => {
83
90
  result = result.replace(placeholder, original)
84
91
  })
85
- return result
92
+ return colonLeadIn ? result.replace(/:$/, '.') : result
86
93
  }
87
94
 
88
95
  let maxSentences = 2
@@ -592,7 +599,7 @@ function buildFieldsTable (fields, capFn, opts = {}) {
592
599
  if (!byField[key]) {
593
600
  byField[key] = {
594
601
  field: field.field,
595
- description: field.description,
602
+ description: field.shortDescription || field.description,
596
603
  introducedIn: field.introducedIn,
597
604
  components: []
598
605
  }
@@ -626,7 +633,8 @@ function buildFieldsTable (fields, capFn, opts = {}) {
626
633
  })
627
634
  }
628
635
 
629
- const desc = info.description ? capFn(info.description) : '// TODO: Add description'
636
+ // A | in the description would end the cell and shift the row.
637
+ const desc = info.description ? capFn(info.description).replace(/\|/g, '\\|') : '// TODO: Add description'
630
638
 
631
639
  section += `|${fieldName}\n`
632
640
  section += `|${desc}\n`
@@ -655,7 +663,7 @@ function buildChangedDefaultsTable (changedDefaults, capFn) {
655
663
  field: change.field,
656
664
  oldDefault: change.oldDefault,
657
665
  newDefault: change.newDefault,
658
- description: change.description,
666
+ description: change.shortDescription || change.description,
659
667
  components: []
660
668
  }
661
669
  }
@@ -667,16 +675,25 @@ function buildChangedDefaultsTable (changedDefaults, capFn) {
667
675
  section += '|Field |Old default |New default |Description |Affected components\n\n'
668
676
 
669
677
  for (const [, info] of Object.entries(byFieldAndDefaults)) {
678
+ // Values render as literal inline code, so interpolations like
679
+ // ${!uuid_v4()} and characters like * or _ show as typed.
680
+ // Values render as literal inline code through pass:c, which, unlike
681
+ // `+...+`, also keeps values with ++ or with spaces at either end. Strings
682
+ // that are empty, start or end with whitespace, or contain a newline show
683
+ // as JSON, so " " and "\n" read as the values they are.
670
684
  const formatDefault = (val) => {
671
685
  if (val === undefined || val === null) return 'none'
672
- if (typeof val === 'string') return val
673
- if (typeof val === 'number' || typeof val === 'boolean') return String(val)
674
- return JSON.stringify(val)
686
+ let text
687
+ if (typeof val === 'string') text = (val === '' || /^\s|\s$|\n/.test(val)) ? JSON.stringify(val) : val
688
+ else if (typeof val === 'number' || typeof val === 'boolean') text = String(val)
689
+ else text = JSON.stringify(val)
690
+ return `\`pass:c[${text.replace(/\]/g, '\\]').replace(/\|/g, '\\|')}]\``
675
691
  }
676
692
 
677
693
  const oldVal = formatDefault(info.oldDefault)
678
694
  const newVal = formatDefault(info.newDefault)
679
- const desc = info.description ? capFn(info.description) : '// TODO: Add description'
695
+ // A | in the description would end the cell and shift the row.
696
+ const desc = info.description ? capFn(info.description).replace(/\|/g, '\\|') : '// TODO: Add description'
680
697
 
681
698
  const byType = {}
682
699
  for (const comp of info.components) {
@@ -1,4 +1,4 @@
1
- // 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/1247543314/Generate+reference+docs+for+Redpanda+Connect
1
+ {{{generatedMarker "rpcn-connector-docs" "the Bloblang spec in redpanda-data/connect or redpanda-data/benthos" "This file is a doc-tools preview. The published partials are generated in redpanda-data/connect by `task docs`, and their first line names the file that registers the function or method. To change the text, edit the spec in that file."}}}
2
2
 
3
3
  = {{name}}
4
4
  {{#if signature}}
@@ -1,5 +1,5 @@
1
1
  {{#if (or summary description version)}}
2
- // This content is autogenerated. Do not edit manually. The summary and description come from the connector's definition in the Connect source. To change them, update the connector upstream, or use the doc-tools CLI with the --overrides option: https://redpandadata.atlassian.net/wiki/spaces/DOC/pages/1247543314/Generate+reference+docs+for+Redpanda+Connect
2
+ {{{generatedMarker "rpcn-connector-docs" "the component spec in redpanda-data/connect or redpanda-data/benthos" "The summary and description come from the component spec. This file is a doc-tools preview. The published partials are generated in redpanda-data/connect by `task docs`, and their first line names the file that registers the component. To change the text, edit the component spec in that file."}}}
3
3
  //
4
4
  // Pages consume this partial in two places so both stay fresh:
5
5
  // header: include::...[tag=meta] (sets :description: for search snippets and meta tags)
@@ -1,5 +1,5 @@
1
1
  {{#with examples}}
2
- // 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/1247543314/Generate+reference+docs+for+Redpanda+Connect
2
+ {{{generatedMarker "rpcn-connector-docs" "the component spec in redpanda-data/connect or redpanda-data/benthos" "This file is a doc-tools preview. The published partials are generated in redpanda-data/connect by `task docs`, and their first line names the file that registers the component. To change the text, edit the component spec in that file."}}}
3
3
 
4
4
  == Examples
5
5
 
@@ -1,11 +1,11 @@
1
1
  {{#if this.config.children}}
2
- // 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/1247543314/Generate+reference+docs+for+Redpanda+Connect
2
+ {{{generatedMarker "rpcn-connector-docs" "the component spec in redpanda-data/connect or redpanda-data/benthos" "This file is a doc-tools preview. The published partials are generated in redpanda-data/connect by `task docs`, and their first line names the file that registers the component. To change the text, edit the component spec in that file."}}}
3
3
 
4
4
  == Fields
5
5
 
6
6
  {{{renderConnectFields this.config.children}}}
7
7
  {{else if this.children}}
8
- // 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/1247543314/Generate+reference+docs+for+Redpanda+Connect
8
+ {{{generatedMarker "rpcn-connector-docs" "the component spec in redpanda-data/connect or redpanda-data/benthos" "This file is a doc-tools preview. The published partials are generated in redpanda-data/connect by `task docs`, and their first line names the file that registers the component. To change the text, edit the component spec in that file."}}}
9
9
 
10
10
  == Fields
11
11
 
@@ -1,5 +1,5 @@
1
1
  {{#if (renderConnectMetadata description)}}
2
- // This content is autogenerated. Do not edit manually. Metadata fields come from the connector's description in the Connect source. To change them, update the connector description upstream, or use the doc-tools CLI with the --overrides option: https://redpandadata.atlassian.net/wiki/spaces/DOC/pages/1247543314/Generate+reference+docs+for+Redpanda+Connect
2
+ {{{generatedMarker "rpcn-connector-docs" "the component spec in redpanda-data/connect or redpanda-data/benthos" "Metadata fields come from the `== Metadata` section of the component description. This file is a doc-tools preview. The published partials are generated in redpanda-data/connect by `task docs`, and their first line names the file that registers the component. To change the text, edit the component spec in that file."}}}
3
3
 
4
4
  {{{renderConnectMetadata description}}}
5
5
  {{/if}}