@redpanda-data/docs-extensions-and-macros 5.7.0 → 5.8.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.
- package/bin/doc-tools.js +15 -0
- package/extensions/add-faq-structured-data.js +3 -0
- package/extensions/add-git-dates.js +3 -0
- package/extensions/add-global-attributes.js +2 -0
- package/extensions/add-llms-directive.js +3 -0
- package/extensions/add-markdown-urls-to-sitemap.js +3 -0
- package/extensions/add-pages-to-root.js +2 -0
- package/extensions/aggregate-terms.js +2 -0
- package/extensions/algolia-indexer/index.js +2 -0
- package/extensions/archive-attachments.js +2 -0
- package/extensions/collect-bloblang-samples.js +2 -0
- package/extensions/compute-end-of-life.js +3 -0
- package/extensions/conditional-home-redirect.js +3 -0
- package/extensions/convert-llms-to-txt.js +3 -0
- package/extensions/convert-to-markdown.js +2 -0
- package/extensions/find-related-docs.js +3 -0
- package/extensions/find-related-labs.js +3 -0
- package/extensions/generate-fields-only-pages.js +3 -0
- package/extensions/generate-index-data.js +3 -0
- package/extensions/generate-rp-connect-categories.js +3 -0
- package/extensions/generate-rp-connect-info.js +3 -0
- package/extensions/git-full-clone.js +3 -0
- package/extensions/modify-connect-tag-playbook.js +3 -0
- package/extensions/process-context-switcher.js +3 -0
- package/extensions/produce-redirects.js +3 -0
- package/extensions/replace-attributes-in-attachments.js +3 -0
- package/extensions/resolve-xrefs-in-attachments.js +3 -0
- package/extensions/set-available-attachment-versions.js +3 -0
- package/extensions/unified-navigation.js +3 -0
- package/extensions/unlisted-pages.js +3 -0
- package/extensions/unpublish-pages.js +3 -0
- package/extensions/util/raise-listener-limit.js +28 -0
- package/extensions/validate-attributes.js +3 -0
- package/extensions/version-fetcher/set-latest-version.js +3 -0
- package/package.json +1 -1
- package/tools/redpanda-connect/generate-rpcn-connector-docs.js +108 -2
- package/tools/redpanda-connect/templates/bloblang-functions-overview.hbs +2 -0
- package/tools/redpanda-connect/templates/bloblang-methods-overview.hbs +2 -0
- package/tools/redpanda-connect/templates/connector.hbs +13 -1
- package/tools/rpk-docs/generate-plugin-stubs.js +56 -9
- package/tools/rpk-docs/templates/command.hbs +23 -5
package/bin/doc-tools.js
CHANGED
|
@@ -1660,6 +1660,21 @@ automation
|
|
|
1660
1660
|
return match
|
|
1661
1661
|
}
|
|
1662
1662
|
})
|
|
1663
|
+
// Antora resolves page metadata with a header-only parse that stops at
|
|
1664
|
+
// the first blank line. The chart README templates emit :description:
|
|
1665
|
+
// below the title's blank line, so the page shipped the generic site
|
|
1666
|
+
// meta description despite carrying one (found on k-connect-helm-spec,
|
|
1667
|
+
// DOC-2414 investigation). Relocate the first :description: into the
|
|
1668
|
+
// header, directly under the title.
|
|
1669
|
+
const descMatch = doc.match(/^:description:[^\n]*$/m)
|
|
1670
|
+
if (descMatch) {
|
|
1671
|
+
const headerEnd = doc.indexOf('\n\n')
|
|
1672
|
+
if (headerEnd !== -1 && doc.indexOf(descMatch[0]) > headerEnd) {
|
|
1673
|
+
doc = doc.replace(descMatch[0] + '\n', '')
|
|
1674
|
+
doc = doc.replace(/^(= .+)$/m, `$1\n${descMatch[0]}`)
|
|
1675
|
+
doc = doc.replace(/\n{3,}/g, '\n\n')
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1663
1678
|
fs.writeFileSync(outFile, doc, 'utf8')
|
|
1664
1679
|
|
|
1665
1680
|
console.log(`Done: Wrote ${outFile}`)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Generates FAQPage JSON-LD structured data for SEO.
|
|
5
7
|
*
|
|
@@ -147,6 +149,7 @@ function generateFaqJsonLd(faqs, baseUrl) {
|
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
module.exports.register = function () {
|
|
152
|
+
raiseListenerLimit(this)
|
|
150
153
|
const logger = this.getLogger('add-faq-structured-data-extension')
|
|
151
154
|
let playbook
|
|
152
155
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Adds Git commit dates to pages as attributes.
|
|
5
7
|
*
|
|
@@ -179,6 +181,7 @@ async function getTreeFiles (git, gitdir, oid, prefix, cache, treeCache) {
|
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
module.exports.register = function () {
|
|
184
|
+
raiseListenerLimit(this)
|
|
182
185
|
const logger = this.getLogger('add-git-dates-extension')
|
|
183
186
|
const context = this
|
|
184
187
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
1
2
|
/* Example use in the playbook
|
|
2
3
|
* antora:
|
|
3
4
|
extensions:
|
|
@@ -12,6 +13,7 @@ const _ = require('lodash');
|
|
|
12
13
|
const ATTRIBUTES_PATH = 'modules/ROOT/partials/'; // Default path within the 'shared' component
|
|
13
14
|
|
|
14
15
|
module.exports.register = function ({ config }) {
|
|
16
|
+
raiseListenerLimit(this)
|
|
15
17
|
const logger = this.getLogger('global-attributes-extension');
|
|
16
18
|
|
|
17
19
|
/**
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Adds llms.txt directive to HTML pages for agent-friendly documentation.
|
|
5
7
|
*
|
|
@@ -16,6 +18,7 @@
|
|
|
16
18
|
const { formatLlmsDirective } = require('../extension-utils/llms-utils')
|
|
17
19
|
|
|
18
20
|
module.exports.register = function () {
|
|
21
|
+
raiseListenerLimit(this)
|
|
19
22
|
const logger = this.getLogger('add-llms-directive-extension')
|
|
20
23
|
|
|
21
24
|
this.on('pagesComposed', ({ contentCatalog }) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Adds markdown URL entries to sitemap.xml files for AI-friendly documentation.
|
|
5
7
|
*
|
|
@@ -21,6 +23,7 @@ const { parseStringPromise } = require('xml2js')
|
|
|
21
23
|
const { toMarkdownUrl } = require('../extension-utils/url-utils')
|
|
22
24
|
|
|
23
25
|
module.exports.register = function () {
|
|
26
|
+
raiseListenerLimit(this)
|
|
24
27
|
const logger = this.getLogger('add-markdown-urls-to-sitemap-extension')
|
|
25
28
|
|
|
26
29
|
this.on('beforePublish', async ({ siteCatalog }) => {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
1
2
|
module.exports.register = function ({ config }) {
|
|
3
|
+
raiseListenerLimit(this)
|
|
2
4
|
this.on('beforePublish', ({ siteCatalog, contentCatalog }) => {
|
|
3
5
|
const logger = this.getLogger('add-pages-to-site-root');
|
|
4
6
|
if (!config || !config.files || !config.files.length) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
1
2
|
/* Example use in the playbook
|
|
2
3
|
* antora:
|
|
3
4
|
extensions:
|
|
@@ -10,6 +11,7 @@ const path = require('path');
|
|
|
10
11
|
const TERMS_PATH = 'modules/terms/partials/'; // Default path within the 'shared' component
|
|
11
12
|
|
|
12
13
|
module.exports.register = function ({ config }) {
|
|
14
|
+
raiseListenerLimit(this)
|
|
13
15
|
const logger = this.getLogger('term-aggregation-extension');
|
|
14
16
|
|
|
15
17
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const generateIndex = require('./generate-index')
|
|
4
|
+
const { raiseListenerLimit } = require('../util/raise-listener-limit')
|
|
4
5
|
const algoliasearch = require('algoliasearch')
|
|
5
6
|
const http = require('http')
|
|
6
7
|
const https = require('https')
|
|
@@ -21,6 +22,7 @@ function register ({
|
|
|
21
22
|
...unknownOptions
|
|
22
23
|
}
|
|
23
24
|
}) {
|
|
25
|
+
raiseListenerLimit(this)
|
|
24
26
|
const logger = this.getLogger('algolia-indexer-extension')
|
|
25
27
|
|
|
26
28
|
// Validate required environment variables
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
1
2
|
"use strict";
|
|
2
3
|
|
|
3
4
|
const fs = require("fs");
|
|
@@ -35,6 +36,7 @@ async function createTarInMemory(tempDir) {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
module.exports.register = function ({ config }) {
|
|
39
|
+
raiseListenerLimit(this)
|
|
38
40
|
const logger = this.getLogger("archive-attachments-extension");
|
|
39
41
|
const archives = config.data?.archives || [];
|
|
40
42
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
1
2
|
const yaml = require('js-yaml');
|
|
2
3
|
|
|
3
4
|
module.exports.register = function () {
|
|
5
|
+
raiseListenerLimit(this)
|
|
4
6
|
const logger = this.getLogger('collect-bloblang-samples');
|
|
5
7
|
|
|
6
8
|
this.on('contentClassified', ({ contentCatalog }) => {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const calculateEOL = require('./util/calculate-eol.js');
|
|
4
6
|
|
|
5
7
|
module.exports.register = function ({ config }) {
|
|
8
|
+
raiseListenerLimit(this)
|
|
6
9
|
this.on('contentClassified', ({ contentCatalog }) => {
|
|
7
10
|
const logger = this.getLogger("compute-end-of-life-extension");
|
|
8
11
|
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict'
|
|
10
10
|
|
|
11
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
12
|
+
|
|
11
13
|
module.exports.register = function () {
|
|
14
|
+
raiseListenerLimit(this)
|
|
12
15
|
const logger = this.getLogger('conditional-home-redirect')
|
|
13
16
|
let shouldRedirect = false
|
|
14
17
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const { toMarkdownUrl } = require('../extension-utils/url-utils');
|
|
4
6
|
const { stripMarkdownMetadata } = require('../extension-utils/llms-utils');
|
|
5
7
|
|
|
@@ -20,6 +22,7 @@ const { stripMarkdownMetadata } = require('../extension-utils/llms-utils');
|
|
|
20
22
|
* Must run after convert-to-markdown extension to access page.markdownContents.
|
|
21
23
|
*/
|
|
22
24
|
module.exports.register = function () {
|
|
25
|
+
raiseListenerLimit(this)
|
|
23
26
|
const logger = this.getLogger('convert-llms-to-txt-extension');
|
|
24
27
|
let siteUrl = '';
|
|
25
28
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
1
2
|
const path = require('path')
|
|
2
3
|
const os = require('os')
|
|
3
4
|
const yaml = require('js-yaml')
|
|
@@ -187,6 +188,7 @@ function generateFrontmatter(page) {
|
|
|
187
188
|
}
|
|
188
189
|
|
|
189
190
|
module.exports.register = function () {
|
|
191
|
+
raiseListenerLimit(this)
|
|
190
192
|
const logger = this.getLogger('convert-to-markdown-extension')
|
|
191
193
|
let playbook
|
|
192
194
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
module.exports.register = function ({ config }) {
|
|
6
|
+
raiseListenerLimit(this)
|
|
4
7
|
const logger = this.getLogger('related-docs-extension');
|
|
5
8
|
|
|
6
9
|
this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
module.exports.register = function ({ config }) {
|
|
6
|
+
raiseListenerLimit(this)
|
|
4
7
|
const logger = this.getLogger('related-labs-extension');
|
|
5
8
|
|
|
6
9
|
this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const fs = require('fs')
|
|
4
6
|
const path = require('path')
|
|
5
7
|
const os = require('os')
|
|
@@ -121,6 +123,7 @@ const DEFAULTS = {
|
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
module.exports.register = function ({ config }) {
|
|
126
|
+
raiseListenerLimit(this)
|
|
124
127
|
const logger = this.getLogger('generate-fields-only-pages-extension')
|
|
125
128
|
|
|
126
129
|
// Merge config with defaults
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
2
4
|
const _ = require('lodash');
|
|
3
5
|
|
|
4
6
|
module.exports.register = function ({ config }) {
|
|
7
|
+
raiseListenerLimit(this)
|
|
5
8
|
const logger = this.getLogger('generate-index-data-extension');
|
|
6
9
|
|
|
7
10
|
this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Redpanda Connect Category Aggregation Extension
|
|
5
7
|
*
|
|
@@ -11,6 +13,7 @@
|
|
|
11
13
|
* Ensure generate-rp-connect-info is listed BEFORE this extension in your playbook.
|
|
12
14
|
*/
|
|
13
15
|
module.exports.register = function ({ config }) {
|
|
16
|
+
raiseListenerLimit(this)
|
|
14
17
|
const logger = this.getLogger('redpanda-connect-category-aggregation-extension')
|
|
15
18
|
|
|
16
19
|
this.on('contentClassified', ({ contentCatalog }) => {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
2
4
|
const fs = require('fs')
|
|
3
5
|
const path = require('path')
|
|
4
6
|
const Papa = require('papaparse')
|
|
@@ -11,6 +13,7 @@ const DEFAULTS = {
|
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
module.exports.register = function ({ config }) {
|
|
16
|
+
raiseListenerLimit(this)
|
|
14
17
|
const logger = this.getLogger('redpanda-connect-info-extension')
|
|
15
18
|
const { getAntoraValue } = require('../cli-utils/antora-utils')
|
|
16
19
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const { execSync } = require('child_process')
|
|
4
6
|
const fs = require('fs')
|
|
5
7
|
const path = require('path')
|
|
@@ -33,6 +35,7 @@ const { getGitHubToken } = require('../cli-utils/github-token')
|
|
|
33
35
|
*/
|
|
34
36
|
|
|
35
37
|
module.exports.register = function ({ config, playbook }) {
|
|
38
|
+
raiseListenerLimit(this)
|
|
36
39
|
const logger = this.getLogger('git-full-clone-extension')
|
|
37
40
|
|
|
38
41
|
logger.info('✓ git-full-clone extension loaded')
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const GetLatestConnectTag = require('./version-fetcher/get-latest-connect');
|
|
4
6
|
|
|
5
7
|
module.exports.register = function ({ config }) {
|
|
8
|
+
raiseListenerLimit(this)
|
|
6
9
|
const logger = this.getLogger('modify-connect-tag-playbook-extension');
|
|
7
10
|
|
|
8
11
|
this.on('contextStarted', async ({ playbook }) => {
|
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
'use strict';
|
|
19
19
|
|
|
20
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
21
|
+
|
|
20
22
|
module.exports.register = function ({ config }) {
|
|
23
|
+
raiseListenerLimit(this)
|
|
21
24
|
const logger = this.getLogger('context-switcher-extension');
|
|
22
25
|
|
|
23
26
|
this.on('documentsConverted', async ({ contentCatalog }) => {
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const File = require('vinyl')
|
|
4
6
|
const { posix: path } = require('path')
|
|
5
7
|
|
|
6
8
|
const ENCODED_SPACE_RX = /%20/g
|
|
7
9
|
|
|
8
10
|
module.exports.register = function () {
|
|
11
|
+
raiseListenerLimit(this)
|
|
9
12
|
this.once('contextStarted', () => {
|
|
10
13
|
const { publishFiles: produceRedirectsDelegate } = this.getFunctions()
|
|
11
14
|
this.replaceFunctions({
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const semver = require('semver');
|
|
4
6
|
const micromatch = require('micromatch');
|
|
5
7
|
const formatVersion = require('./util/format-version.js');
|
|
@@ -24,6 +26,7 @@ const sanitize = require('./util/sanitize-attributes.js');
|
|
|
24
26
|
* - ...
|
|
25
27
|
*/
|
|
26
28
|
module.exports.register = function ({ config }) {
|
|
29
|
+
raiseListenerLimit(this)
|
|
27
30
|
const logger = this.getLogger('replace-attributes-extension');
|
|
28
31
|
const replacements = config.data?.replacements || [];
|
|
29
32
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Resolves AsciiDoc xrefs in JSON attachment files to HTML links.
|
|
5
7
|
*
|
|
@@ -19,6 +21,7 @@
|
|
|
19
21
|
*/
|
|
20
22
|
|
|
21
23
|
module.exports.register = function () {
|
|
24
|
+
raiseListenerLimit(this)
|
|
22
25
|
const logger = this.getLogger('resolve-xrefs-in-attachments')
|
|
23
26
|
|
|
24
27
|
this.on('contentClassified', ({ contentCatalog }) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const semver = require('semver')
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -34,6 +36,7 @@ const PROPERTIES_JSON_RX = /^redpanda-properties-(v\d+\.\d+\.\d+(?:-[\w.]+)?)\.j
|
|
|
34
36
|
const CONNECT_JSON_RX = /^connect-(\d+\.\d+\.\d+(?:-[\w.]+)?)\.json$/
|
|
35
37
|
|
|
36
38
|
module.exports.register = function () {
|
|
39
|
+
raiseListenerLimit(this)
|
|
37
40
|
const logger = this.getLogger('set-available-attachment-versions-extension')
|
|
38
41
|
|
|
39
42
|
this.once('contentClassified', ({ contentCatalog }) => {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
const yaml = require('js-yaml')
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -35,6 +37,7 @@ const yaml = require('js-yaml')
|
|
|
35
37
|
*/
|
|
36
38
|
|
|
37
39
|
module.exports.register = function () {
|
|
40
|
+
raiseListenerLimit(this)
|
|
38
41
|
const logger = this.getLogger('unified-navigation-extension')
|
|
39
42
|
|
|
40
43
|
this.on('navigationBuilt', ({ contentCatalog }) => {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
module.exports.register = function ({ config }) {
|
|
6
|
+
raiseListenerLimit(this)
|
|
4
7
|
const { addToNavigation, unlistedPagesHeading = 'Unlisted Pages' } = config;
|
|
5
8
|
const logger = this.getLogger('unlisted-pages-extension');
|
|
6
9
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
module.exports.register = function () {
|
|
6
|
+
raiseListenerLimit(this)
|
|
4
7
|
const logger = this.getLogger('unpublish-pages-extension');
|
|
5
8
|
|
|
6
9
|
this.on('documentsConverted', ({ siteCatalog, contentCatalog }) => {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Antora's GeneratorContext is one shared EventEmitter for every registered
|
|
4
|
+
// extension, and Redpanda playbooks register enough of them that per-event
|
|
5
|
+
// listener counts legitimately exceed Node's default threshold of 10. Node
|
|
6
|
+
// then prints MaxListenersExceededWarning ("Possible EventEmitter memory
|
|
7
|
+
// leak detected. 11 contentClassified listeners added to [GeneratorContext]")
|
|
8
|
+
// in build logs even though each extension adds exactly one listener per
|
|
9
|
+
// event per build.
|
|
10
|
+
//
|
|
11
|
+
// Every extension in this package raises the limit before subscribing, so
|
|
12
|
+
// the suppression holds no matter which subset of extensions a playbook
|
|
13
|
+
// registers or in what order. The cap is bounded rather than unlimited (0)
|
|
14
|
+
// to keep Node's leak detection meaningful for pathological cases.
|
|
15
|
+
const GENERATOR_CONTEXT_MAX_LISTENERS = 64
|
|
16
|
+
|
|
17
|
+
function raiseListenerLimit (context) {
|
|
18
|
+
if (
|
|
19
|
+
typeof context.getMaxListeners === 'function' &&
|
|
20
|
+
typeof context.setMaxListeners === 'function' &&
|
|
21
|
+
context.getMaxListeners() !== 0 &&
|
|
22
|
+
context.getMaxListeners() < GENERATOR_CONTEXT_MAX_LISTENERS
|
|
23
|
+
) {
|
|
24
|
+
context.setMaxListeners(GENERATOR_CONTEXT_MAX_LISTENERS)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { raiseListenerLimit, GENERATOR_CONTEXT_MAX_LISTENERS }
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
const { raiseListenerLimit } = require('./util/raise-listener-limit')
|
|
10
|
+
|
|
9
11
|
module.exports.register = function ({ config }) {
|
|
12
|
+
raiseListenerLimit(this)
|
|
10
13
|
const logger = this.getLogger('attribute-validation-extension');
|
|
11
14
|
|
|
12
15
|
this.on('documentsConverted', async ({ contentCatalog, siteCatalog }) => {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { raiseListenerLimit } = require('../util/raise-listener-limit')
|
|
4
|
+
|
|
3
5
|
module.exports.register = function ({ config }) {
|
|
6
|
+
raiseListenerLimit(this)
|
|
4
7
|
const GetLatestRedpandaVersion = require('./get-latest-redpanda-version');
|
|
5
8
|
const GetLatestConsoleVersion = require('./get-latest-console-version');
|
|
6
9
|
const GetLatestDockerTag = require('./fetch-latest-docker-tag');
|
package/package.json
CHANGED
|
@@ -55,7 +55,10 @@ function mergeOverrides(target, overrides) {
|
|
|
55
55
|
throw new Error('Target must be a valid object');
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
// 'summary' earns its place here the hard way: overrides.json has carried
|
|
59
|
+
// summary overrides (zmq4, ffi) that were silently dropped because the key
|
|
60
|
+
// fell through every branch below. Summaries feed page meta descriptions.
|
|
61
|
+
const scalarKeys = ['description', 'summary', 'type', 'annotated_field', 'version'];
|
|
59
62
|
|
|
60
63
|
for (const key in overrides) {
|
|
61
64
|
// === Handle annotated_options ===
|
|
@@ -674,17 +677,120 @@ async function generateRpcnConnectorDocs(options) {
|
|
|
674
677
|
}
|
|
675
678
|
}
|
|
676
679
|
|
|
680
|
+
// Self-heal published page headers: pages are one-time drafts, so pages
|
|
681
|
+
// created before the template emitted :description: never got one.
|
|
682
|
+
let descriptionBackfill = { backfilled: [], skippedNoSummary: [] };
|
|
683
|
+
if (!writeFullDrafts) {
|
|
684
|
+
descriptionBackfill = backfillPageDescriptions(dataObj);
|
|
685
|
+
}
|
|
686
|
+
|
|
677
687
|
return {
|
|
678
688
|
partialsWritten,
|
|
679
689
|
draftsWritten,
|
|
680
690
|
partialFiles,
|
|
681
691
|
draftFiles,
|
|
682
|
-
lostSectionWarnings
|
|
692
|
+
lostSectionWarnings,
|
|
693
|
+
descriptionBackfill
|
|
683
694
|
};
|
|
684
695
|
}
|
|
685
696
|
|
|
697
|
+
|
|
698
|
+
// Connector page families that have per-component pages under
|
|
699
|
+
// modules/components/pages/. Other data keys (config, bloblang-functions,
|
|
700
|
+
// bloblang-methods) have no per-component page to backfill.
|
|
701
|
+
const PAGE_TYPE_DIRS = new Set([
|
|
702
|
+
'inputs', 'outputs', 'processors', 'caches', 'buffers', 'metrics',
|
|
703
|
+
'tracers', 'scanners', 'rate-limits', 'rate_limits'
|
|
704
|
+
]);
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Insert a tagged :description: into existing connector page headers that
|
|
708
|
+
* lack one, sourced from the component's summary in the connector data.
|
|
709
|
+
*
|
|
710
|
+
* Connector pages are one-time first drafts: pages drafted before the
|
|
711
|
+
* template emitted :description: never got one, and nothing rewrote them,
|
|
712
|
+
* so hundreds of published pages ship the generic site meta description
|
|
713
|
+
* even though ~97% of components carry a summary in the source data. This
|
|
714
|
+
* runs on every generation, so the page set self-heals and stays healed.
|
|
715
|
+
*
|
|
716
|
+
* The inserted block matches the connector template's shape: the meta tag
|
|
717
|
+
* region lets single-source stubs inherit the description as a header
|
|
718
|
+
* attribute (see the template comment in connector.hbs).
|
|
719
|
+
*
|
|
720
|
+
* @param {Object} connectorData - Parsed connector data (typed arrays)
|
|
721
|
+
* @param {Object} [options]
|
|
722
|
+
* @param {string} [options.pagesRoot] - Pages directory (default: modules/components/pages under cwd)
|
|
723
|
+
* @param {boolean} [options.dryRun] - Report without writing
|
|
724
|
+
* @returns {{backfilled: string[], skippedNoSummary: string[]}}
|
|
725
|
+
*/
|
|
726
|
+
function backfillPageDescriptions (connectorData, { pagesRoot, dryRun = false } = {}) {
|
|
727
|
+
const root = pagesRoot || path.resolve(process.cwd(), 'modules/components/pages');
|
|
728
|
+
const results = { backfilled: [], skippedNoSummary: [] };
|
|
729
|
+
if (!fs.existsSync(root)) return results;
|
|
730
|
+
|
|
731
|
+
for (const [dataKey, items] of Object.entries(connectorData)) {
|
|
732
|
+
if (!PAGE_TYPE_DIRS.has(dataKey) || !Array.isArray(items)) continue;
|
|
733
|
+
// The data uses 'rate-limits' while the pages directory is
|
|
734
|
+
// 'rate_limits'. Resolve whichever spelling exists on disk.
|
|
735
|
+
const typeDir = fs.existsSync(path.join(root, dataKey))
|
|
736
|
+
? dataKey
|
|
737
|
+
: dataKey.replace(/-/g, '_');
|
|
738
|
+
for (const item of items) {
|
|
739
|
+
if (!item || !item.name) continue;
|
|
740
|
+
const pagePath = path.join(root, typeDir, `${item.name}.adoc`);
|
|
741
|
+
if (!fs.existsSync(pagePath)) continue;
|
|
742
|
+
|
|
743
|
+
const content = fs.readFileSync(pagePath, 'utf8');
|
|
744
|
+
const lines = content.split('\n');
|
|
745
|
+
const headerEnd = lines.findIndex((l) => l.trim() === '');
|
|
746
|
+
const header = lines.slice(0, headerEnd === -1 ? lines.length : headerEnd);
|
|
747
|
+
if (header.some((l) => l.startsWith(':description:'))) continue;
|
|
748
|
+
|
|
749
|
+
// Meta descriptions are read as plain text by search results, link
|
|
750
|
+
// previews, and assistants, so flatten AsciiDoc markup mechanically:
|
|
751
|
+
// xrefs and links become their labels, inline code loses its
|
|
752
|
+
// backticks. No prose is edited.
|
|
753
|
+
const summary = (item.summary || '')
|
|
754
|
+
.replace(/(?:xref|link):[^\[\]]+\[([^\]]*)\]/g, '$1')
|
|
755
|
+
// Bare URL macros (no xref:/link: prefix) and internal xref shorthand
|
|
756
|
+
// also appear in source summaries and render literally if left in place.
|
|
757
|
+
.replace(/https?:\/\/[^\s\[\]]+\[([^\]]*)\]/g, '$1')
|
|
758
|
+
.replace(/<<[^,>]+,([^>]+)>>/g, '$1')
|
|
759
|
+
.replace(/<<([^>]+)>>/g, '$1')
|
|
760
|
+
// Strip the "open in new tab" caret that AsciiDoc URL macros carry
|
|
761
|
+
// inside the link text, e.g. [Open Telemetry collector^].
|
|
762
|
+
.replace(/\^/g, '')
|
|
763
|
+
.replace(/`([^`]*)`/g, '$1')
|
|
764
|
+
.replace(/\s+/g, ' ')
|
|
765
|
+
.trim();
|
|
766
|
+
if (!summary) {
|
|
767
|
+
results.skippedNoSummary.push(`${typeDir}/${item.name}`);
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
const insertAt = headerEnd === -1 ? lines.length : headerEnd;
|
|
772
|
+
lines.splice(insertAt, 0, '// tag::meta[]', `:description: ${summary}`, '// end::meta[]');
|
|
773
|
+
if (!dryRun) fs.writeFileSync(pagePath, lines.join('\n'), 'utf8');
|
|
774
|
+
results.backfilled.push(`${typeDir}/${item.name}`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (results.backfilled.length) {
|
|
779
|
+
console.log(`Backfilled :description: into ${results.backfilled.length} connector page header(s) from source summaries`);
|
|
780
|
+
}
|
|
781
|
+
if (results.skippedNoSummary.length) {
|
|
782
|
+
console.warn(
|
|
783
|
+
`\u26a0 ${results.skippedNoSummary.length} connector page(s) lack both a header description and a source summary: ` +
|
|
784
|
+
results.skippedNoSummary.join(', ') +
|
|
785
|
+
'. Author these in the overrides file or upstream.'
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
return results;
|
|
789
|
+
}
|
|
790
|
+
|
|
686
791
|
module.exports = {
|
|
687
792
|
generateRpcnConnectorDocs,
|
|
793
|
+
backfillPageDescriptions,
|
|
688
794
|
mergeOverrides,
|
|
689
795
|
resolveReferences
|
|
690
796
|
};
|
|
@@ -3,7 +3,19 @@
|
|
|
3
3
|
:type: {{type}}
|
|
4
4
|
{{#if support}}:support: {{support}}{{/if}}
|
|
5
5
|
:categories: [{{join categories ", "}}]
|
|
6
|
-
|
|
6
|
+
{{#if summary}}
|
|
7
|
+
// tag::meta[]
|
|
8
|
+
:description: {{{summary}}}
|
|
9
|
+
// end::meta[]
|
|
10
|
+
{{else if description}}
|
|
11
|
+
// tag::meta[]
|
|
12
|
+
:description: {{description}}
|
|
13
|
+
// end::meta[]
|
|
14
|
+
{{/if}}
|
|
15
|
+
{{!-- No fallback line when neither exists: an emitted TODO would become
|
|
16
|
+
the attribute VALUE and stubs would inherit it into their meta tags.
|
|
17
|
+
Missing descriptions are the tracked editorial backlog
|
|
18
|
+
(cloud-docs .github/description-allowlist.txt). --}}
|
|
7
19
|
|
|
8
20
|
component_type_dropdown::[]
|
|
9
21
|
|
|
@@ -23,7 +23,7 @@ const { spawnSync } = require('child_process')
|
|
|
23
23
|
* authoritative: dashified filenames cannot be reversed unambiguously
|
|
24
24
|
* (rpk-ai-llm-provider could be `llm provider` or `llm-provider`).
|
|
25
25
|
* @param {string} partialsDir - Directory of generated .adoc partials
|
|
26
|
-
* @returns {Array<{file: string, title: string, description: string|undefined}>} Sorted by command path
|
|
26
|
+
* @returns {Array<{file: string, title: string, description: string|undefined, hasMetaTag: boolean}>} Sorted by command path
|
|
27
27
|
*/
|
|
28
28
|
function readPartialTitles(partialsDir) {
|
|
29
29
|
const partials = []
|
|
@@ -35,11 +35,18 @@ function readPartialTitles(partialsDir) {
|
|
|
35
35
|
console.warn(`Warning: no title line in ${file}; skipping`)
|
|
36
36
|
continue
|
|
37
37
|
}
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
38
|
+
// Antora resolves page metadata with a header-only parse that never
|
|
39
|
+
// sees the body include, so the stub must carry the description in its
|
|
40
|
+
// own header. Partials generated with doc-tools >= 5.4 carry a nested
|
|
41
|
+
// meta tag region around :description: that stubs include dynamically;
|
|
42
|
+
// older partials fall back to a literal copy of the header description.
|
|
41
43
|
const description = (content.match(/^:description:[ \t]*(.+)$/m) || [])[1]
|
|
42
|
-
partials.push({
|
|
44
|
+
partials.push({
|
|
45
|
+
file,
|
|
46
|
+
title: match[1].trim(),
|
|
47
|
+
description: description && description.trim(),
|
|
48
|
+
hasMetaTag: content.includes('tag::meta['),
|
|
49
|
+
})
|
|
43
50
|
}
|
|
44
51
|
// Hierarchical order: sort by command words so parents precede children
|
|
45
52
|
partials.sort((a, b) => {
|
|
@@ -121,11 +128,23 @@ function inferIncludePrefix(stubDir, plugin) {
|
|
|
121
128
|
* @param {string} [params.description] - Meta description from the partial header
|
|
122
129
|
* @param {string} params.includePrefix - Antora resource prefix
|
|
123
130
|
* @param {Array<string>} params.attributes - Page attribute lines
|
|
131
|
+
* @param {boolean} [params.hasMetaTag] - Partial carries a tag::meta[] region (doc-tools >= 5.4)
|
|
124
132
|
* @returns {string}
|
|
125
133
|
*/
|
|
126
|
-
function renderStub({ title, file, description, includePrefix, attributes }) {
|
|
134
|
+
function renderStub({ title, file, description, includePrefix, attributes, hasMetaTag }) {
|
|
127
135
|
const lines = [`= ${title}`]
|
|
128
|
-
|
|
136
|
+
// The description mechanism is always the first header line after the
|
|
137
|
+
// title: a header include for partials with a meta tag region, or a
|
|
138
|
+
// literal copy as the fallback for partials generated before 5.4. Antora
|
|
139
|
+
// resolves page metadata with a header-only parse that stops at the first
|
|
140
|
+
// blank line, so either form must sit above it — an include below the
|
|
141
|
+
// blank line is never evaluated for attributes and the page ships the
|
|
142
|
+
// generic site description.
|
|
143
|
+
if (hasMetaTag) {
|
|
144
|
+
lines.push(`include::${includePrefix}${file}[tag=meta]`)
|
|
145
|
+
} else if (description) {
|
|
146
|
+
lines.push(`:description: ${description}`)
|
|
147
|
+
}
|
|
129
148
|
for (const attr of attributes) lines.push(attr)
|
|
130
149
|
lines.push('')
|
|
131
150
|
lines.push(`include::${includePrefix}${file}[tag=single-source]`)
|
|
@@ -162,6 +181,7 @@ function reconcileStubs({
|
|
|
162
181
|
const existingStubs = fs.readdirSync(stubDir).filter(f => f.endsWith('.adoc'))
|
|
163
182
|
|
|
164
183
|
const created = []
|
|
184
|
+
const upgraded_ = []
|
|
165
185
|
const deleted = []
|
|
166
186
|
const keptNonStub = []
|
|
167
187
|
const skippedAliasTargets = []
|
|
@@ -206,7 +226,34 @@ function reconcileStubs({
|
|
|
206
226
|
fs.existsSync(stubDir) ? fs.readdirSync(stubDir).filter(f => f.endsWith('.adoc')) : []
|
|
207
227
|
)
|
|
208
228
|
for (const partial of partials) {
|
|
209
|
-
if (remainingStubs.has(partial.file))
|
|
229
|
+
if (remainingStubs.has(partial.file)) {
|
|
230
|
+
// Existing stub: upgrade it in place when the partial has gained the
|
|
231
|
+
// meta tag region and the stub does not yet include it. The header
|
|
232
|
+
// include is what lets the stub inherit :description: as page
|
|
233
|
+
// metadata, so upgrading here makes the consumer repo self-heal on
|
|
234
|
+
// the next sync instead of needing a hand-written migration PR.
|
|
235
|
+
if (partial.hasMetaTag && !dryRun) {
|
|
236
|
+
const stubPath = path.join(stubDir, partial.file)
|
|
237
|
+
const stubContent = fs.readFileSync(stubPath, 'utf8')
|
|
238
|
+
if (!stubContent.includes('[tag=meta]')) {
|
|
239
|
+
const metaInclude = `include::${includePrefix}${partial.file}[tag=meta]`
|
|
240
|
+
// A later attribute entry overrides an earlier one (verified
|
|
241
|
+
// empirically against an Antora build), so a literal
|
|
242
|
+
// :description: below the include would win and leave the
|
|
243
|
+
// include dead weight. These are generated reference stubs, so
|
|
244
|
+
// any literal is a static backfill the include supersedes:
|
|
245
|
+
// strip it. Hand-maintained prose stubs never pass through this
|
|
246
|
+
// reconciler, so intentionally curated descriptions are safe.
|
|
247
|
+
let upgraded = stubContent.replace(/^:description: .*\n/m, '')
|
|
248
|
+
upgraded = upgraded.replace(/^(= .+)$/m, `$1\n${metaInclude}`)
|
|
249
|
+
if (upgraded !== stubContent) {
|
|
250
|
+
fs.writeFileSync(stubPath, upgraded, 'utf8')
|
|
251
|
+
upgraded_.push(partial.file)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
continue
|
|
256
|
+
}
|
|
210
257
|
if (aliasClaims.has(partial.file)) {
|
|
211
258
|
skippedAliasTargets.push({ file: partial.file, claimedBy: aliasClaims.get(partial.file) })
|
|
212
259
|
continue
|
|
@@ -285,7 +332,7 @@ function reconcileStubs({
|
|
|
285
332
|
}
|
|
286
333
|
}
|
|
287
334
|
|
|
288
|
-
return { created, deleted, keptNonStub, navUpdated, renameCandidates, skippedAliasTargets }
|
|
335
|
+
return { created, upgraded: upgraded_, deleted, keptNonStub, navUpdated, renameCandidates, skippedAliasTargets }
|
|
289
336
|
}
|
|
290
337
|
|
|
291
338
|
module.exports = {
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
page at worst. Availability pages are excluded from cloud by not
|
|
7
7
|
generating a stub for them in cloud-docs. --}}
|
|
8
8
|
= {{commandPath}}
|
|
9
|
+
{{!-- Comment lines are legal inside an AsciiDoc header, so the meta tag
|
|
10
|
+
region can wrap the page's single description. Stub pages inherit it
|
|
11
|
+
with a header include (see the note at the single-source tag). --}}
|
|
12
|
+
// tag::meta[]
|
|
9
13
|
:description: {{{wrapDescriptionPassthrough shortDesc}}}
|
|
14
|
+
// end::meta[]
|
|
10
15
|
{{#if pageAliases}}
|
|
11
16
|
:page-aliases: {{{pageAliases}}}
|
|
12
17
|
{{/if}}
|
|
@@ -23,11 +28,24 @@
|
|
|
23
28
|
{{/each}}
|
|
24
29
|
|
|
25
30
|
// tag::single-source[]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
single-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
{{!-- Stub pages inherit this page's description by including the header's
|
|
32
|
+
meta tag region as a HEADER attribute. A stub that only includes
|
|
33
|
+
tag=single-source after a blank line never gets it: Antora resolves
|
|
34
|
+
page metadata with a header-only parse that stops at the stub's first
|
|
35
|
+
blank line, so the include is never evaluated for attributes and the
|
|
36
|
+
page ships the generic site description (verified empirically,
|
|
37
|
+
2026-08-05, including that a headerless include destroys the body).
|
|
38
|
+
The working stub shape is two includes:
|
|
39
|
+
|
|
40
|
+
= Page title
|
|
41
|
+
include::...page.adoc[tag=meta] <- header: no blank line above
|
|
42
|
+
<- blank line ends the header
|
|
43
|
+
include::...page.adoc[tag=single-source]
|
|
44
|
+
|
|
45
|
+
Earlier revisions repeated :description: inside this region on the
|
|
46
|
+
wrong belief that it reached stub metadata by itself; it never did.
|
|
47
|
+
page-aliases and page-platforms deliberately stay outside both tag
|
|
48
|
+
regions: consumers must not inherit alias registrations. --}}
|
|
31
49
|
{{!-- Deprecation notice --}}
|
|
32
50
|
{{#if deprecated}}
|
|
33
51
|
[CAUTION]
|