使用上下文变量

Antora 扩展的主要目标是允许您编写在关键转换点挂钩生成过程的代码,并访问当时流经系统的变量。 一旦您开始访问这些上下文变量,扩展的乐趣就真正开始了。

访问上下文变量

上下文变量是在事件触发时处于范围内并且生成器绑定到生成器上下文的变量。通过从扩展访问上下文变量,您可以:

  • 读取对象的属性

  • 调用对象的方法,或

  • 修改对象的属性(前提是对象未被冻结)。

更新上下文变量 中,你将学习如何用对象的代理来替换变量,这是另一种选择。

每个事件监听器的第一个位置参数是一个上下文变量对象。你应该使用 对象重构(object destructuring) 从该对象中挑选出单个变量(例如,{ playbook })。每个事件的范围内变量在 生成器事件参考 页面上有定义。

让我们在扩展的基础上检索网站目录,并在其中添加 .nojekyll 文件,作为使用补充用户界面的替代方案。

Example 1. nojekyll-extension.js
module.exports.register = function () {
  this.on('beforePublish', ({ siteCatalog }) => {
    siteCatalog.addFile({ contents: Buffer.alloc(0), out: { path: '.nojekyll' } })
  })
}

Example 1 中,使用 { siteCatalog } 从上下文中检索站点目录。要检索多个变量,请使用逗号分隔变量名(例如,{ playbook, siteCatalog })。

也可以使用 getVariables 方法直接从生成器上下文中获取上下文变量:

const { siteCatalog } = this.getVariables()

内置上下文变量 外,扩展还可以访问其他扩展记录和发布的上下文变量。

更新上下文变量

虽然大多数扩展会读取上下文变量并与引用对象的方法交互,但它们也可以添加或替换上下文变量。其中一个用例就是定义新变量,供其他扩展或同一扩展的监听器访问。这是通过生成器传递额外数据的一种方法。另一个用例是替换生成器使用的内置变量,也许是通过代理的方式。如果您需要大幅改变 Antora 的行为,但又无法通过添加或删除目录中的文件来实现,那么您可能就需要这样做。

让我们考虑这样一个用例:我们要代理内容目录,以防止它注册任何别名。在 Example 2 中,我们监听 contentClassified 事件,检索 contentCatalog 上下文变量,并用对象的代理替换该变量。

Example 2. Replace variable with a proxy of the object
module.exports.register = function () {
  this.on('contentClassified', function ({ contentCatalog }) {
    contentCatalog = new Proxy(contentCatalog, {
      get(target, property) {
        return property === 'registerPageAlias' ? () => undefined : target[property]
      },
    })
    this.updateVariables({ contentCatalog })
  })
}
Example 2 为您提供了用自己的实现替换 registerPageAlias 函数的起点。

请注意,前面的示例使用了正式 function 关键字来声明监听器,而不是箭头函数。通过这种方式定义函数,我们可以访问标准 this 关键字,它是对生成器上下文的引用。注册监听器时,Antora 会将函数绑定到生成器上下文,这样就可以在函数中使用标准 this 关键字访问生成器上下文。

上下文变量锁定

一旦内置上下文变量被认为已经建立,通常是在引入该变量的事件发生后,该变量就会被锁定。这条规则也有例外,但大体上是成立的。被锁定的变量不能被替换。任何尝试都会导致错误。

被锁定的内置变量以及何时被锁定,请参见 生成器事件参考 页面。

锁定内置变量有两个原因。首先,如果变量必须被替换,它会发出信号。其次,它允许网站生成器和其他扩展程序存储该变量的本地引用,而不必担心检查它是否已被替换。

锁定的变量只能防止变量本身被替换。修改变量引用的对象仍然是可能的,比如添加、更新或删除对象的某个属性。唯一的例外是 playbook,它是一个冻结对象。