使用上下文变量

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

访问上下文变量

上下文变量是在事件发出时处于作用域中的变量,并且生成器将其绑定到生成器上下文。通过从扩展中访问上下文变量,您可以:

  • 从对象中读取属性,

  • 在对象上调用方法,或

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

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

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

让我们继续扩展我们的扩展,以检索站点目录并添加一个.nojekyll文件作为替代方案,而不是使用补充UI来实现此目的。

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

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

还可以直接从生成器上下文中使用getVariables方法检索上下文变量:

const { siteCatalog } = this.getVariables()

除了内置上下文变量之外,您的扩展还可以访问其他扩展文档和发布的上下文变量。

更新上下文变量

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

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

示例 2. 用对象的代理替换变量
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 })
  })
}
示例 2为您提供了替换registerPageAlias函数的起点。

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

上下文变量锁定

一旦内置上下文变量被视为已建立,通常是在引入它的事件之后,该变量就会被锁定。这个规则有例外,但总体上是成立的。锁定的变量无法被替换。任何尝试这样做的操作都会导致错误。

已锁定的变量以及何时锁定它们在生成器事件参考页面上有指示。

内置变量被锁定的原因有两个。首先,它表示变量应该在必要时被替换。其次,它允许站点生成器和其他扩展存储对该变量的本地引用,而无需担心检查它是否被替换。

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