@redpanda-data/docs-extensions-and-macros
Version:
Antora extensions and macros developed for Redpanda documentation.
106 lines (95 loc) • 4.2 kB
JavaScript
const semver = require('semver')
/**
* Points UI templates at generated JSON attachments that actually exist.
*
* The docs-ui head-meta partial builds <meta name="properties-json-url"> and
* <meta name="connect-json-url"> tags from version attributes such as
* latest-redpanda-tag and latest-connect-version. Those attributes track the
* newest GitHub release, which can be ahead of the newest generated JSON in
* the content catalog. When that happens the template's production fallback
* URL points at a file that does not exist, and every page view requests a
* guaranteed 404.
*
* This extension scans the catalog on contentClassified and sets, per
* component version:
*
* - available-properties-tag: newest redpanda-properties-<tag>.json attachment
* in the reference module of each streaming (ROOT) component version
* - available-connect-version: newest connect-<version>.json attachment in the
* components module of the connect component
* - page-disable-property-tooltips: 'true' on streaming versions that have no
* properties JSON at all, so browsers never request a URL that cannot exist
*
* Attributes already set (for example, pinned in antora.yml) are never
* overwritten.
*/
const PROPERTIES_COMPONENTS = ['ROOT', 'streaming']
const CONNECT_COMPONENTS = ['connect', 'redpanda-connect']
const PROPERTIES_JSON_RX = /^redpanda-properties-(v\d+\.\d+\.\d+(?:-[\w.]+)?)\.json$/
const CONNECT_JSON_RX = /^connect-(\d+\.\d+\.\d+(?:-[\w.]+)?)\.json$/
module.exports.register = function () {
const logger = this.getLogger('set-available-attachment-versions-extension')
this.once('contentClassified', ({ contentCatalog }) => {
contentCatalog.getComponents().forEach((component) => {
const isProperties = PROPERTIES_COMPONENTS.includes(component.name)
const isConnect = CONNECT_COMPONENTS.includes(component.name)
if (!isProperties && !isConnect) return
component.versions.forEach((compVer) => {
const attributes = ((compVer.asciidoc = compVer.asciidoc || {}).attributes =
compVer.asciidoc.attributes || {})
const attachments = contentCatalog.findBy({
component: component.name,
version: compVer.version,
family: 'attachment',
})
if (isProperties) {
const newest = findNewestVersion(attachments, 'reference', PROPERTIES_JSON_RX)
if (newest) {
if (!attributes['available-properties-tag']) {
attributes['available-properties-tag'] = newest
logger.info(
`Set available-properties-tag=${newest} for ${component.name}@${compVer.version}`
)
}
} else if (attributes['latest-redpanda-tag'] && !attributes['available-properties-tag']) {
// Tooltips would request a JSON that does not exist for this version
if (!attributes['page-disable-property-tooltips']) {
attributes['page-disable-property-tooltips'] = 'true'
logger.info(
`No properties JSON found for ${component.name}@${compVer.version}; disabling property tooltips`
)
}
}
}
if (isConnect) {
const newest = findNewestVersion(attachments, 'components', CONNECT_JSON_RX)
if (newest && !attributes['available-connect-version']) {
attributes['available-connect-version'] = newest
logger.info(
`Set available-connect-version=${newest} for ${component.name}@${compVer.version}`
)
}
}
})
})
})
}
function findNewestVersion (attachments, module, rx) {
let newestRaw = null
let newestSemver = null
attachments.forEach((attachment) => {
if (attachment.src.module !== module) return
const basename = attachment.src.relative.split('/').pop()
const match = basename.match(rx)
if (!match) return
const raw = match[1]
const parsed = semver.coerce(raw, { includePrerelease: true })
if (!parsed) return
if (!newestSemver || semver.gt(parsed, newestSemver)) {
newestSemver = parsed
newestRaw = raw
}
})
return newestRaw
}