扩展用例

本页提供了一个简单示例目录,展示如何通过使用扩展功能来增强 Antora 的功能。每一部分都介绍了不同的使用案例,并提供了可作为起点的扩展代码。

您还可以参考 Antora 项目提供的官方扩展项目,学习更复杂的示例。

排除私人内容源

如果某些贡献者或 CI 作业没有权限访问 playbook 中的私有内容源,可以使用扩展来过滤它们,而不必修改 playbook 文件。

该扩展在 playbookBuilt 事件期间运行。它会检索 playbook,遍历内容源,并移除任何被检测为私有并因此需要身份验证的内容源。我们将依靠一个约定来向扩展传达哪个内容源是私有的。这个约定就是使用以 git@ 开头的 SSH URL。Antora 会自动将 SSH URL 转换为 HTTP URL,因此使用这种语法只是为了提示用户和扩展,该 URL 是私有的,需要进行身份验证。

Example 1. exclude-private-content-sources-extension.js
module.exports.register = function () {
  this.on('playbookBuilt', function ({ playbook }) {
    playbook.content.sources = playbook.content.sources
      .filter(({ url }) => !url.startsWith('git@'))
    this.updateVariables({ playbook })
  })
}

该扩展之所以有效,是因为在该事件结束之前,游戏本都是可变的,Antora 会在事件结束时冻结游戏本。调用 this.updateVariables 替换生成器上下文中的 playbook 变量并不是必需的,但这里用来表达意图和证明扩展的未来性。

报告未列出的页面

创建新页面后,很容易忘记将其添加到导航中,以便读者访问。我们可以使用扩展来识别不在导航中的页面,并使用记录器报告它们。

该扩展在 navigationBuilt 事件期间运行。它会遍历每个组件版本,检索其内部导航条目的扁平化列表,然后检查是否有任何页面不在该列表中,并通过 URL 对页面进行比较。如果发现任何此类页面,就会创建相关报告,并将其添加到导航中。

Example 2. unlisted-pages-extension.js
module.exports.register = function ({ config }) {
  const { addToNavigation, unlistedPagesHeading = 'Unlisted Pages' } = config
  const logger = this.getLogger('unlisted-pagesAlian-extension')
  this
    .on('navigationBuilt', ({ contentCatalog }) => {
      contentCatalog.getComponents().forEach(({ versions }) => {
        versions.forEach(({ name: component, version, navigation: nav, url: defaultUrl }) => {
          const navEntriesByUrl = getNavEntriesByUrl(nav)
          const unlistedPages = contentCatalog
            .findBy({ component, version, family: 'page' })
            .filter((page) => page.out)
            .reduce((collector, page) => {
              if ((page.pub.url in navEntriesByUrl) || page.pub.url === defaultUrl) return collector
              logger.warn({ file: page.src, source: page.src.origin }, 'detected unlisted page')
              return collector.concat(page)
            }, [])
          if (unlistedPages.length && addToNavigation) {
            nav.push({
              content: unlistedPagesHeading,
              items: unlistedPages.map((page) => {
                return { content: page.asciidoc.navtitle, url: page.pub.url, urlType: 'internal' }
              }),
              root: true,
            })
          }
        })
      })
    })
}

function getNavEntriesByUrl (items = [], accum = {}) {
  items.forEach((item) => {
    if (item.urlType === 'internal') accum[item.url.split('#')[0]] = item
    getNavEntriesByUrl(item.items, accum)
  })
  return accum
}

您可以在 扩展教程 中阅读有关此扩展的更多信息以及如何配置它。

取消发布未列出的页面

与其报告未列出的页面,不如将这些页面从发布中删除。这也是使用导航来决定发布哪些页面的一种方法。

该扩展在 navigationBuilt 事件期间运行。它会遍历每个组件版本,检索其内部导航项的扁平化列表,然后检查是否有任何页面不在该列表中,并通过 URL 对页面进行比较。如果发现任何此类页面,就会取消发布。

Example 3. unpublish-unlisted-pages-extension.js
module.exports.register = function ({ config }) {
  this
    .on('navigationBuilt', ({ contentCatalog }) => {
      contentCatalog.getComponents().forEach(({ versions }) => {
        versions.forEach(({ name: component, version, navigation: nav, url: defaultUrl }) => {
          const navEntriesByUrl = getNavEntriesByUrl(nav)
          const unlistedPages = contentCatalog
            .findBy({ component, version, family: 'page' })
            .filter((page) => page.out)
            .reduce((collector, page) => {
              if ((page.pub.url in navEntriesByUrl) || page.pub.url === defaultUrl) return collector
              return collector.concat(page)
            }, [])
          if (unlistedPages.length) unlistedPages.forEach((page) => delete page.out)
        })
      })
    })
}

function getNavEntriesByUrl (items = [], accum = {}) {
  items.forEach((item) => {
    if (item.urlType === 'internal') accum[item.url.split('#')[0]] = item
    getNavEntriesByUrl(item.items, accum)
  })
  return accum
}

从页面中移除 out 属性后,页面将无法发布,但仍可使用 include 指令进行引用。或者,你也可以选择从内容目录中完全删除页面。