You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在pandoc-filter的stdio模式下补充文档末尾的闭合details标签?

背景

我写了一个pandoc-filter,它利用HTML的details和summary元素(配合下方的CSS),在pandoc把Markdown转成HTML时生成可折叠区块。
区块以Markdown标题行(比如### Section title)开头,假设级别为N的标题之后,下一个标题的级别不会超过N+2。

Javascript代码

let level = 0;
filter.stdio(function ({ t, c }, format, meta) {
  if (t === "Header") {
    const content = [
      filter.RawBlock("html", `<details open><summary>`),
      filter.Header(...c),
      filter.RawBlock("html", `</summary>`)
    ];
    for (let i = c[0]; i <= level; i++)
      content.unshift(filter.RawBlock("html", `</details>`));
    level = c[0];
    return content;
  }
});

CSS代码

details:not([open]) > summary {
  list-style: disclosure-closed;
}
details[open] > summary {
  list-style: disclosure-open;
}
问题描述

这个过滤器能正常运行,但会生成无效HTML(浏览器会自动修正):文档末尾缺少</details>闭合标签。因为filter.stdio传入的处理函数不会在文档结束时被调用,我找不到添加这些闭合标签的方法。

比如,把它应用到本文的Markdown源时,会生成如下details和summary标签(省略其他标签):

示例CSS:

summary { margin-left: 1em; }
details:not([open])>summary {
  list-style: disclosure-closed;
}
details[open]>summary {
  list-style: disclosure-open;
}

示例HTML:

<details open>
  <summary>
    <h1>The context</h1>
  </summary>
  ...
  <details open>
    <summary>
      <h2>Javascript</h2>
    </summary>
    ...
  </details>
  <details open>
    <summary>
      <h2>CSS</h2>
    </summary>
    ...
  </details>
</details>
<details open>
  <summary>
    <h1>The problem</h1>
  </summary>
  ...
<!-- The </details> end tag is missing. -->

我可以通过编写解析整个Markdown文档JSON表示的pandoc过滤器来解决此问题,但希望继续使用filter.stdio这种逐节点处理的方式。请问如何在filter.stdio模式下添加缺失的</details>闭合标签?


解决方案

要在filter.stdio模式下补全末尾缺失的</details>,可以监听输入流的结束事件,在文档处理完成后追加需要的闭合标签。具体修改如下:

修改后的Javascript代码:

let level = 0;
const filter = require('pandoc-filter');

filter.stdio(function ({ t, c }, format, meta) {
  if (t === "Header") {
    const content = [
      filter.RawBlock("html", `<details open><summary>`),
      filter.Header(...c),
      filter.RawBlock("html", `</summary>`)
    ];
    for (let i = c[0]; i <= level; i++)
      content.unshift(filter.RawBlock("html", `</details>`));
    level = c[0];
    return content;
  }
});

// 监听输入流结束,补全剩余的</details>标签
process.stdin.on('end', () => {
  let closeTags = '';
  // 根据当前层级生成对应数量的闭合标签
  for (let i = 1; i <= level; i++) {
    closeTags += '</details>\n';
  }
  if (closeTags) {
    // 输出符合pandoc AST格式的RawBlock节点
    process.stdout.write(JSON.stringify([
      { t: 'RawBlock', c: ['html', closeTags] }
    ]));
  }
});

原理说明

pandoc过滤器通过stdin接收文档的AST(JSON格式),处理后通过stdout输出修改后的AST。当输入流结束时,手动生成包含闭合标签的RawBlock节点并输出,pandoc会自动将这些节点追加到文档末尾,从而补全所有未闭合的details标签。

注意事项

  • 确保代码正确引入了pandoc-filter模块
  • 输出的JSON必须符合pandoc AST的格式,这里生成单个RawBlock节点的数组即可

内容的提问来源于stack exchange,提问作者Heiko Theißen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:04:57