@redpanda-data/docs-extensions-and-macros 4.13.0 → 4.13.2
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-mcp.js +15 -3
- package/bin/doc-tools.js +767 -2088
- package/bin/mcp-tools/property-docs.js +18 -0
- package/bin/mcp-tools/rpcn-docs.js +28 -3
- package/cli-utils/antora-utils.js +53 -2
- package/cli-utils/dependencies.js +313 -0
- package/cli-utils/diff-utils.js +273 -0
- package/cli-utils/doc-tools-utils.js +54 -0
- package/extensions/algolia-indexer/generate-index.js +134 -102
- package/extensions/algolia-indexer/index.js +70 -38
- package/extensions/collect-bloblang-samples.js +2 -1
- package/extensions/generate-rp-connect-categories.js +126 -67
- package/extensions/generate-rp-connect-info.js +291 -137
- package/macros/rp-connect-components.js +34 -5
- package/mcp/CLI_INTERFACE.adoc +384 -0
- package/mcp/COSTS.adoc +167 -0
- package/mcp/DEVELOPMENT.adoc +726 -0
- package/mcp/README.adoc +172 -0
- package/mcp/USER_GUIDE.adoc +1392 -0
- package/mcp/WRITER_EXTENSION_GUIDE.adoc +814 -0
- package/mcp/prompts/README.adoc +183 -0
- package/mcp/prompts/property-docs-guide.md +283 -0
- package/mcp/prompts/review-for-style.md +128 -0
- package/mcp/prompts/rpcn-connector-docs-guide.md +126 -0
- package/mcp/prompts/write-new-guide.md +222 -0
- package/mcp/team-standards/style-guide.md +321 -0
- package/mcp/templates/README.adoc +212 -0
- package/mcp/templates/prompt-review-template.md +80 -0
- package/mcp/templates/prompt-write-template.md +110 -0
- package/mcp/templates/resource-template.md +76 -0
- package/package.json +8 -5
- package/tools/add-commercial-names.js +207 -0
- package/tools/generate-cli-docs.js +6 -2
- package/tools/get-console-version.js +5 -0
- package/tools/get-redpanda-version.js +5 -0
- package/tools/property-extractor/compare-properties.js +3 -3
- package/tools/property-extractor/generate-handlebars-docs.js +14 -14
- package/tools/property-extractor/generate-pr-summary.js +46 -0
- package/tools/property-extractor/pr-summary-formatter.js +375 -0
- package/tools/redpanda-connect/README.adoc +403 -38
- package/tools/redpanda-connect/connector-binary-analyzer.js +588 -0
- package/tools/redpanda-connect/generate-rpcn-connector-docs.js +97 -34
- package/tools/redpanda-connect/parse-csv-connectors.js +1 -1
- package/tools/redpanda-connect/pr-summary-formatter.js +601 -0
- package/tools/redpanda-connect/report-delta.js +69 -2
- package/tools/redpanda-connect/rpcn-connector-docs-handler.js +1180 -0
- package/tools/redpanda-connect/templates/connector.hbs +38 -0
- package/tools/redpanda-connect/templates/intro.hbs +0 -20
- package/tools/redpanda-connect/update-nav.js +205 -0
|
@@ -1,36 +1,54 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Redpanda Connect Category Aggregation Extension
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT: This extension depends on generate-rp-connect-info running first.
|
|
7
|
+
* Both extensions use 'contentClassified' event. The generate-rp-connect-info
|
|
8
|
+
* extension returns a Promise, so Antora will wait for it to complete before
|
|
9
|
+
* running this extension (extensions are processed in playbook order).
|
|
10
|
+
*
|
|
11
|
+
* Ensure generate-rp-connect-info is listed BEFORE this extension in your playbook.
|
|
12
|
+
*/
|
|
3
13
|
module.exports.register = function ({ config }) {
|
|
4
14
|
const logger = this.getLogger('redpanda-connect-category-aggregation-extension')
|
|
5
15
|
|
|
6
|
-
this.
|
|
16
|
+
this.on('contentClassified', ({ contentCatalog }) => {
|
|
7
17
|
const redpandaConnect = contentCatalog.getComponents().find(component => component.name === 'redpanda-connect')
|
|
18
|
+
|
|
8
19
|
if (!redpandaConnect || !redpandaConnect.latest) {
|
|
9
20
|
logger.warn('Could not find the redpanda-connect component. Skipping category creation.')
|
|
10
21
|
return
|
|
11
22
|
}
|
|
12
23
|
|
|
13
24
|
const descriptions = redpandaConnect.latest.asciidoc.attributes.categories
|
|
14
|
-
const
|
|
15
|
-
const certifiedConnectors = redpandaConnect.latest.asciidoc.attributes['certified-components']
|
|
16
|
-
const enterpriseConnectors = redpandaConnect.latest.asciidoc.attributes['enterprise-components']
|
|
25
|
+
const csvData = redpandaConnect.latest.asciidoc.attributes.csvData
|
|
17
26
|
|
|
18
|
-
if (!descriptions
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
logger.error('No certified-components attribute found in redpanda-connect component')
|
|
27
|
-
}
|
|
28
|
-
if (!enterpriseConnectors) {
|
|
29
|
-
logger.error('No enterprise-components attribute found in redpanda-connect component')
|
|
30
|
-
}
|
|
27
|
+
if (!descriptions) {
|
|
28
|
+
logger.error('No categories attribute found in redpanda-connect component')
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!csvData || !csvData.data) {
|
|
33
|
+
logger.error('No csvData attribute found in redpanda-connect component.')
|
|
34
|
+
logger.error('Ensure generate-rp-connect-info extension is listed BEFORE this extension in your playbook.')
|
|
31
35
|
return
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
// Build lookup maps from CSV data
|
|
39
|
+
const supportLookup = new Map()
|
|
40
|
+
for (const row of csvData.data) {
|
|
41
|
+
const connector = row.connector
|
|
42
|
+
if (connector) {
|
|
43
|
+
supportLookup.set(connector, {
|
|
44
|
+
supportLevel: (row.support_level || 'community').toLowerCase(),
|
|
45
|
+
isEnterprise: row.is_licensed === 'Yes'
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
logger.info(`Loaded support data for ${supportLookup.size} connectors from CSV`)
|
|
51
|
+
|
|
34
52
|
const connectCategoriesData = {}
|
|
35
53
|
const flatComponentsData = []
|
|
36
54
|
const driverSupportData = {}
|
|
@@ -38,88 +56,129 @@ module.exports.register = function ({ config }) {
|
|
|
38
56
|
const types = Object.keys(descriptions)
|
|
39
57
|
|
|
40
58
|
// Initialize connectCategoriesData for each type
|
|
41
|
-
|
|
59
|
+
for (const type of types) {
|
|
42
60
|
connectCategoriesData[type] = []
|
|
43
|
-
}
|
|
61
|
+
}
|
|
44
62
|
|
|
45
63
|
try {
|
|
46
64
|
const files = contentCatalog.findBy({ component: 'redpanda-connect', family: 'page' })
|
|
47
65
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const
|
|
66
|
+
for (const file of files) {
|
|
67
|
+
// Prefer using page.asciidoc.attributes when available
|
|
68
|
+
const attrs = file.asciidoc?.attributes || {}
|
|
69
|
+
|
|
70
|
+
// Get attributes - prefer API, fallback to content parsing
|
|
71
|
+
const fileType = attrs.type || extractAttribute(file, 'type')
|
|
72
|
+
const categories = attrs.categories || extractAttribute(file, 'categories')
|
|
73
|
+
const status = attrs.status || extractAttribute(file, 'status')
|
|
74
|
+
const driverSupport = attrs['driver-support'] || extractAttribute(file, 'driver-support')
|
|
75
|
+
const cacheSupport = attrs['cache-support'] || extractAttribute(file, 'cache-support')
|
|
76
|
+
// FIXED: Use correct attribute name (page-commercial-names, not commercial-names)
|
|
77
|
+
const commercialNames = attrs['page-commercial-names'] || extractAttribute(file, 'page-commercial-names')
|
|
78
|
+
|
|
55
79
|
const pubUrl = file.pub.url
|
|
56
80
|
const name = file.src.stem
|
|
57
81
|
|
|
58
|
-
if (
|
|
59
|
-
const fileType = typeMatch[1]
|
|
60
|
-
|
|
61
|
-
let status = statusMatch ? statusMatch[1] : 'community'
|
|
82
|
+
if (!fileType) continue
|
|
62
83
|
|
|
63
|
-
|
|
64
|
-
if (status === 'deprecated') return
|
|
84
|
+
let componentStatus = status || 'community'
|
|
65
85
|
|
|
66
|
-
|
|
86
|
+
// Skip deprecated components
|
|
87
|
+
if (componentStatus === 'deprecated') continue
|
|
67
88
|
|
|
68
|
-
|
|
89
|
+
// Get support level from CSV data
|
|
90
|
+
const csvInfo = supportLookup.get(name)
|
|
91
|
+
const isEnterprise = csvInfo?.isEnterprise || false
|
|
69
92
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
93
|
+
// Determine status from CSV support level (CSV takes precedence)
|
|
94
|
+
if (csvInfo) {
|
|
95
|
+
if (csvInfo.supportLevel === 'certified' || csvInfo.supportLevel === 'enterprise') {
|
|
96
|
+
componentStatus = 'certified'
|
|
73
97
|
} else {
|
|
74
|
-
|
|
98
|
+
componentStatus = csvInfo.supportLevel
|
|
75
99
|
}
|
|
100
|
+
}
|
|
76
101
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
102
|
+
// Parse commercial names and use first as display name
|
|
103
|
+
let commonName = name // Default to connector key name
|
|
104
|
+
if (commercialNames) {
|
|
105
|
+
const names = commercialNames.split(',').map(n => n.trim()).filter(n => n)
|
|
106
|
+
if (names.length > 0) {
|
|
107
|
+
commonName = names[0]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
80
110
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
categories.forEach(category => {
|
|
85
|
-
let categoryObj = connectCategoriesData[fileType].find(cat => cat.name === category)
|
|
111
|
+
// Populate connectCategoriesData
|
|
112
|
+
if (types.includes(fileType) && categories) {
|
|
113
|
+
const categoryList = categories.replace(/[\[\]"]/g, '').split(',').map(cat => cat.trim())
|
|
86
114
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
categoryObj.items = []
|
|
90
|
-
connectCategoriesData[fileType].push(categoryObj)
|
|
91
|
-
}
|
|
115
|
+
for (const category of categoryList) {
|
|
116
|
+
let categoryObj = connectCategoriesData[fileType].find(cat => cat.name === category)
|
|
92
117
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
if (!categoryObj) {
|
|
119
|
+
categoryObj = descriptions[fileType].find(desc => desc.name === category) || { name: category, description: '' }
|
|
120
|
+
categoryObj.items = []
|
|
121
|
+
connectCategoriesData[fileType].push(categoryObj)
|
|
122
|
+
}
|
|
96
123
|
|
|
97
|
-
|
|
98
|
-
let flatItem = flatComponentsData.find(item => item.name === commonName)
|
|
99
|
-
if (!flatItem) {
|
|
100
|
-
flatItem = { name: commonName, originalName: name, support: status, types: [], enterprise: isEnterprise ? true : false}
|
|
101
|
-
flatComponentsData.push(flatItem)
|
|
124
|
+
categoryObj.items.push({ name: commonName, url: pubUrl, status: componentStatus })
|
|
102
125
|
}
|
|
126
|
+
}
|
|
103
127
|
|
|
104
|
-
|
|
105
|
-
|
|
128
|
+
// Populate flatComponentsData
|
|
129
|
+
let flatItem = flatComponentsData.find(item => item.name === commonName)
|
|
130
|
+
if (!flatItem) {
|
|
131
|
+
flatItem = {
|
|
132
|
+
name: commonName,
|
|
133
|
+
originalName: name,
|
|
134
|
+
support: componentStatus,
|
|
135
|
+
types: [],
|
|
136
|
+
enterprise: isEnterprise
|
|
106
137
|
}
|
|
138
|
+
flatComponentsData.push(flatItem)
|
|
139
|
+
}
|
|
107
140
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
141
|
+
if (!flatItem.types.some(t => t.type === fileType)) {
|
|
142
|
+
flatItem.types.push({
|
|
143
|
+
type: fileType,
|
|
144
|
+
url: pubUrl,
|
|
145
|
+
enterprise: isEnterprise,
|
|
146
|
+
support: componentStatus
|
|
147
|
+
})
|
|
111
148
|
}
|
|
112
|
-
|
|
149
|
+
|
|
150
|
+
// Populate support data
|
|
151
|
+
if (driverSupport) driverSupportData[name] = driverSupport
|
|
152
|
+
if (cacheSupport) cacheSupportData[name] = cacheSupport
|
|
153
|
+
}
|
|
113
154
|
|
|
114
155
|
redpandaConnect.latest.asciidoc.attributes.connectCategoriesData = connectCategoriesData
|
|
115
156
|
redpandaConnect.latest.asciidoc.attributes.flatComponentsData = flatComponentsData
|
|
116
157
|
redpandaConnect.latest.asciidoc.attributes.driverSupportData = driverSupportData
|
|
117
158
|
redpandaConnect.latest.asciidoc.attributes.cacheSupportData = cacheSupportData
|
|
118
159
|
|
|
119
|
-
logger.
|
|
120
|
-
logger.debug(
|
|
160
|
+
logger.info(`Processed ${flatComponentsData.length} components across ${types.length} types`)
|
|
161
|
+
logger.debug(`Categories data: ${JSON.stringify(connectCategoriesData, null, 2)}`)
|
|
121
162
|
} catch (error) {
|
|
122
163
|
logger.error(`Error processing Redpanda Connect files: ${error.message}`)
|
|
164
|
+
logger.error(error.stack)
|
|
123
165
|
}
|
|
124
166
|
})
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Extract attribute from file contents when page.asciidoc.attributes is not available.
|
|
170
|
+
* This is a fallback for when attributes haven't been parsed yet.
|
|
171
|
+
*/
|
|
172
|
+
function extractAttribute (file, attrName) {
|
|
173
|
+
if (!file.contents) return null
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const content = file.contents.toString('utf8')
|
|
177
|
+
const regex = new RegExp(`:${attrName}:\\s*(.*)`)
|
|
178
|
+
const match = regex.exec(content)
|
|
179
|
+
return match ? match[1].trim() : null
|
|
180
|
+
} catch {
|
|
181
|
+
return null
|
|
182
|
+
}
|
|
183
|
+
}
|
|
125
184
|
}
|