MichengLiang/asciidoc-abundant-tree

GitHub: MichengLiang/asciidoc-abundant-tree

将 AsciiDoc 文件解析为保留源码坐标、xref 绑定和结构语义的 TypeScript 对象树,支持 JSON 和 RDF 1.2 投影输出,专供文档静态分析使用。

Stars: 0 | Forks: 0

# asciidoc-abundant-tree [![npm version](https://img.shields.io/npm/v/asciidoc-abundant-tree.svg)](https://www.npmjs.com/package/asciidoc-abundant-tree) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/f65e448c60211759.svg)](https://github.com/MichengLiang/asciidoc-abundant-tree/actions/workflows/ci.yml) [![Pages](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/413b6068e9211805.svg)](https://github.com/MichengLiang/asciidoc-abundant-tree/actions/workflows/pages.yml) [![License](https://img.shields.io/npm/l/asciidoc-abundant-tree.svg)](./LICENSE) [![Node.js](https://img.shields.io/node/v/asciidoc-abundant-tree.svg)](./package.json) `asciidoc-abundant-tree` 将 AsciiDoc 源文件或显式的 book-entry 包含图转换为具备源码感知能力、可用于分析的文档树。 该包专为那些需要的输出多于渲染后的 HTML、但不需要完整的 AsciiDoc 语言服务器的工具而设计。Asciidoctor 在转换和官方引用解析方面表现出色,但其公开的输出结构并非设计为用于下游静态分析的紧凑源码映射。该包保留了 Asciidoctor 在 AsciiDoc 语义方面的权威性,并添加了一个 TypeScript object model,在一个 object 中完整保留了编写的源码层面、source spans、block 结构、target catalog、xref occurrences 以及官方的 xref bindings。 美观的树状格式专为终端阅读而设计。其结构特意贴近 `docutils` 的 `pformat()` 风格:object headlines 包含紧凑的标量属性,嵌套的 objects 保持稳定的缩进,而多行源码文本作为缩进的 body 打印,而不是被挤压进转义的属性中。 ## 它能为您提供什么 - 用于 `.adoc` 文件的单个 `AbundantDocument` object。 - Section、paragraph、description list、listing、table、title、metadata、target、anchor 和 xref nodes。 - 用于恢复原始编写表面的原始源码文本和 source spans。 - 用于 sections、blocks、listings、tables、inline anchors 和 block anchors 的 target catalog。 - Xref occurrence 记录保留了原始 target 文本、labels、local/external/unresolved scope、所属 section 以及已解析的 target 类型。 - 用于 xrefs 的官方 Asciidoctor binding 数据:`href`、`resolvedId`、`resolvedType` 和 `reftext`。 - 用于终端检查的美观树状输出和用于自动化的 JSON 输出。 - 显式 book-entry 模式,用于解析入口文件及其支持的包含完整文件的 includes,并带有原始源码坐标。 - 通过单个 `rdf12` 投影输出 RDF 1.2 graph、Turtle 和 JSON-LD,可用于源码感知的 graph 查询、前端消费以及基于行的 edit loops。 主要的产出物是 TypeScript object。美观文本、JSON、RDF 1.2 Turtle 和 RDF 1.2 JSON-LD 都是同一个已解析文档的投影。 ## 文档 - 在线书架: - RDF 1.2 标题投影规范:[AsciiDoc `AbundantDocument` 到 RDF 1.2 标题投影图规约](https://michengliang.github.io/asciidoc-abundant-tree/books/06-rdf12-line-projection/book.html) - 生成的书籍源码:[`docs/bookshelf/build/adoc/books/06-rdf12-line-projection.adoc`](./docs/bookshelf/build/adoc/books/06-rdf12-line-projection.adoc) - 紧凑的预览示例:[`samples/rdf12-projection-preview.adoc`](./samples/rdf12-projection-preview.adoc) - Book-entry 示例:[`samples/book-entry-demo/book.adoc`](./samples/book-entry-demo/book.adoc) - 源码:[`docs/bookshelf`](./docs/bookshelf/) RDF 1.2 投影书籍指定了 package runtime 使用的 graph vocabulary 和 query contract。公开的 runtime surface 通过 `rdf12(document, options)` API 和 CLI `--format rdf12` / `--format rdf12-json-ld` 暴露该投影。 ## 何时使用 在构建以下内容时使用此 package: - 文档分析器 - xref 和 anchor 审计 - 源码感知的迁移工具 - 文档清点脚本 - 需要行和列证据的编写诊断 - 将编写的 AsciiDoc 与 Asciidoctor 已解析模型进行比较的实验 当工具需要回答以下问题时,它尤其有用: - 源文件中的这个 xref 写在哪里? - 这个 target 是来自 section、listing、table、block ID 还是 inline anchor? - 哪个 section 包含此 occurrence? - Asciidoctor 将这个 xref 解析成了什么? - 是什么源码文本生成了这个 block 或 metadata 层? - 哪些 RDF resources 和 reified relations 表示相同的源码间隔、xref occurrence 或编写的表面? ## RDF 1.2 投影 `rdf12` 投影从 `AbundantDocument` 派生出 RDF 1.2 graph。源文档仍然是 fact source,`AbundantDocument` 是 input contract,而 RDF graph 是可查询的投影。 Projection resources 使用从文档坐标系生成的确定性 IRI,而不是作者字符串或排序事实。Heading nodes 通过 `aat:addressLabel`、`aat:generatedAddressLabel` 和 `aat:headline` 直接暴露其 label 空间。Query code 可以使用这些字段查找 headings,然后读取 `relativePath`、`startLine` 和 `endLine` 以进行源码检查或修补。 该 graph 包含源文档 provenance、heading nodes、direct heading containment、same-parent child order、global heading preorder、selector binding、xref edge evidence、用于已解析 xref relations 的 RDF 1.2 reifiers、direct field predicates 和 payload complex property objects。`aat:containsDirectly` 表达直接的父子 heading 关系,`aat:childOrder` 对同一父级下的直接子级进行排序,`aat:documentOrder` 按逻辑 preorder 对所有 headings 进行排序。源码坐标字段(如 `relativePath`、`startLine`、`endLine`、`headingLine` 和 `raw`)描述了原始源码位置和切片;它们不是 heading 顺序的备选方案。Xref edges 将 raw selectors、payload selectors 和官方 Asciidoctor 证据保留为独立的事实。属性列表(如 `[#delivery.policy, status=active]`)将显式 ID 保留为 `aat:addressLabel`,将 `.policy` 保留为 `aat:role`,并将命名字段保留为直接的 `aat:` predicate(如 `aat:status`)。 来自 listings、tables、blocks、inline anchors 和 payload blocks 的本地非 heading target ID 会成为所属 heading 上的 `aat:addressLabel` 值。它们参与到 heading label 空间中,而不会创建 listing、table、block、anchor 或 payload-block 结构 resources。 RDF 1.2 heading projection 不会发出 `aat:previousSibling`。需要有序文档树的消费者应读取 `aat:containsDirectly`,按数字 `aat:childOrder` 对每个父级的直接子级进行排序,并使用数字 `aat:documentOrder` 进行整篇文档的 preorder 遍历。IRI 词法顺序、Turtle 文本顺序、`relativePath` 和源码行值不是排序 contract。 JSON-LD 输出是相同 RDF graph 的前端友好型投影。RDF 1.2 triple terms 被表示为结构化的 `rdf12:TripleTerm` objects,而不是平铺的字符串。 下面的预览示例保持了足够小的源码以便于浏览,同时仍展示了主要的投影表面。它是从 [`samples/rdf12-projection-preview.adoc`](./samples/rdf12-projection-preview.adoc) 的实际 CLI 输出中裁剪出来的。 AsciiDoc 源码: ``` = 投影预览 [#delivery.policy, status=active] == 配送策略 配送策略依赖 xref:capacity[运力规则, rel=depends-on, payload=rel-delivery]。 [.banana, for=delivery] [source,json] ---- {"owner":{"team":"ops"},"risk":{"signals":["capacity"]}} ---- [#rel-delivery.pear] [source,yaml] ---- reason: risk-control signals: - capacity ---- [#capacity.rule, status=active] == 运力规则 运力规则决定是否降级。 ``` 投影出的 Turtle: ``` @prefix aat: . @prefix rel: . @prefix rdf: . a aat:Heading; aat:addressLabel "delivery", "rel-delivery"; aat:headline "配送策略"; aat:role "policy"; aat:payload ; rel:depends-on . aat:payloadKind "node"; aat:role "banana"; aat:forSelector "delivery"; aat:format "json"; aat:raw "{\"owner\":{\"team\":\"ops\"},\"risk\":{\"signals\":[\"capacity\"]}}". rdf:reifies <<( rel:depends-on )>>; a aat:XrefEdge; aat:sourceHeading ; aat:targetHeading ; aat:targetSelector "capacity"; aat:payloadSelector "rel-delivery"; aat:payload ; aat:rel "depends-on". aat:payloadKind "edge"; aat:payloadId "rel-delivery"; aat:role "pear"; aat:format "yaml"; aat:raw "reason: risk-control\nsignals:\n - capacity". ``` 发布验证涵盖了具有语义 graph 比较的 RDF 投影、Turtle roundtrip 检查、JSON-LD shape 检查、selector 歧义情况、source-span 边界情况、payload binding 规则、relation predicate fallback 以及 CLI `rdf12` / `rdf12-json-ld` 冒烟测试输出。 ## 当前边界 这个 package 刻意保持较窄的范围。 该模型专为静态分析和源码检查而设计。它不是一个完整的 AsciiDoc 实现。 ## 安装 ``` pnpm add asciidoc-abundant-tree ``` ``` npm install asciidoc-abundant-tree ``` ## CLI 无需安装项目依赖即可尝试: ``` npx asciidoc-abundant-tree path/to/file.adoc --format tree ``` ``` asciidoc-abundant-tree asciidoc-abundant-tree --json asciidoc-abundant-tree --format tree asciidoc-abundant-tree --format json asciidoc-abundant-tree --format rdf12 asciidoc-abundant-tree --format rdf12-json-ld asciidoc-abundant-tree --mode book-entry --document-root --format json asciidoc-abundant-tree --help ``` 默认输出是美观的树状结构: ``` children[]
children[] ``` JSON 输出保留相同的 object 字段,并省略 `undefined` 值: ``` asciidoc-abundant-tree docs/index.adoc --json > tree.json ``` RDF 1.2 输出将 Turtle 文本直接写入 stdout: ``` asciidoc-abundant-tree docs/index.adoc --format rdf12 > projection.ttl ``` RDF 1.2 JSON-LD 输出将相同的 graph 作为 JSON 文档写入,供前端消费者使用: ``` asciidoc-abundant-tree docs/index.adoc --format rdf12-json-ld > projection.jsonld ``` Book-entry 模式将入口文件和支持的完整文件 include 指令解析为一个逻辑文档。它始终是显式的: ``` asciidoc-abundant-tree samples/book-entry-demo/book.adoc \ --mode book-entry \ --document-root samples/book-entry-demo \ --format json ``` 在 book-entry 模式中如果省略 `--document-root`,CLI 会使用当前工作目录。在单文件模式下,`--document-root` 不会改变解析器输入的构建方式;RDF 输出仍会将其作为投影根。 演示书籍将入口文件、被包含的章节和一个 assets 目录保留在一个示例树下。其 JSON、美观树和 RDF 1.2 输出会暴露原始的 `relativePath` 值(例如 `chapters/01-overview.adoc` 和 `chapters/02-operations.adoc`),而不是将入口文件视为每个 node 的源码。 CLI 仅暴露用于 RDF 输出的 `rdf12` 和 `rdf12-json-ld`。它不接受 `rdf`、`ttl` 或 `turtle` 作为公开的 format aliases。 ## Library API ``` import { formatAbundantTree, parseAbundantTree, rdf12, serializeAbundantTreeToJson, } from "asciidoc-abundant-tree"; const document = parseAbundantTree({ sourcePath: "docs/index.adoc", }); const book = parseAbundantTree({ sourcePath: "samples/book-entry-demo/book.adoc", mode: "book-entry", documentRoot: "samples/book-entry-demo", }); const prettyText = formatAbundantTree(document); const jsonData = serializeAbundantTreeToJson(document); const projection = rdf12(document, { documentRoot: process.cwd(), }); const graph = projection.graph; const ttl = projection.ttl; const jsonLd = projection.jsonLd; ``` 公开的 `rdf12(document, options)` 调用返回一个包含 `graph`、`ttl` 和 `jsonLd` 的投影结果。`graph` 是项目自有的 RDF 1.2 graph 模型;`ttl` 中的 Turtle 1.2 文本通过将 `rdf:reifies` objects 写入为 triple terms(而不是字符串字面量)来保留 RDF 1.2 reifier 语义。`jsonLd` 中的 JSON-LD 文本通过显式的 `rdf12:TripleTerm` objects 保留相同的 triple-term 结构。该投影用于源码感知的 query contracts:它记录 heading slices、xref edge evidence、direct field predicates 和不透明的 payload raw 文本,但不会 lint 文档、验证跨文件 targets 或解释 payload raw 内容。 ## Object Layers 输出将编写的源码事实与官方 Asciidoctor 事实分离开来。 Source-layer 字段描述文件表面:raw 文本、source 行、line span、source span、语法、target、label、ID、roles、attributes、metadata span 和 content span。 Official-layer 字段描述 Asciidoctor 结果:context、node name、href、resolved ID、resolved type 和 reftext。 这种分离很重要。Raw xref targets 不会被官方的 bindings 覆盖,而官方的 xref 数据也不会从转换后的 HTML 中的普通链接推断出来。每个源码的 xref occurrence 都会从针对该 occurrence 的 Asciidoctor xref 转换中接收其官方 binding。 ## 示例任务 列出未解析的 local xrefs: ``` import { parseAbundantTree } from "asciidoc-abundant-tree"; const document = parseAbundantTree({ sourcePath: "docs/index.adoc" }); for (const xref of document.xrefOccurrences) { if (xref.scope === "unresolved") { console.log(`${xref.target} at line ${xref.sourceSpan?.start.line}`); } } ``` 检查 target 类型: ``` import { parseAbundantTree } from "asciidoc-abundant-tree"; const document = parseAbundantTree({ sourcePath: "docs/index.adoc" }); const byKind = new Map(); for (const target of document.targets) { byKind.set(target.targetType, (byKind.get(target.targetType) ?? 0) + 1); } console.log(Object.fromEntries(byKind)); ``` ## 开发 ``` pnpm install pnpm test pnpm test:coverage pnpm typecheck pnpm lint pnpm build pnpm pack:check ``` 从源码运行 CLI: ``` pnpm dev samples/reference-links.adoc pnpm dev samples/reference-links.adoc --json pnpm dev samples/reference-links.adoc --format rdf12 pnpm dev samples/book-entry-demo/book.adoc --mode book-entry --document-root samples/book-entry-demo --format json ``` ## 发布状态 该 package 可用于单文件源码分析、显式的 book-entry include 图、xref/target 审计以及 RDF 1.2 heading projection。Object model 和 RDF vocabulary 刻意保持小巧和保守。在生产工作流中,建议固定次要版本,并在将其应用于大型文档系统之前,对照您自己的 fixtures 检查 JSON 和 RDF 结构。 GitHub Actions 发布工作流在推送 `v*` 标签时运行,带 provenance 发布到 npm,并在发布尚不存在时根据 `CHANGELOG.md` 创建 GitHub Release。 ## 许可证 Apache-2.0。详见 [LICENSE](./LICENSE)。 ## 更新日志 详见 [CHANGELOG.md](./CHANGELOG.md)。
标签:AsciiDoc, MITM代理, odt, TypeScript, 云安全监控, 安全插件, 抽象语法树, 文档解析, 自动化攻击, 静态分析