MichengLiang/asciidoc-abundant-tree
GitHub: MichengLiang/asciidoc-abundant-tree
将 AsciiDoc 文件解析为保留源码坐标、xref 绑定和结构语义的 TypeScript 对象树,支持 JSON 和 RDF 1.2 投影输出,专供文档静态分析使用。
Stars: 0 | Forks: 0
# asciidoc-abundant-tree
[](https://www.npmjs.com/package/asciidoc-abundant-tree)
[](https://github.com/MichengLiang/asciidoc-abundant-tree/actions/workflows/ci.yml)
[](https://github.com/MichengLiang/asciidoc-abundant-tree/actions/workflows/pages.yml)
[](./LICENSE)
[](./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, 云安全监控, 安全插件, 抽象语法树, 文档解析, 自动化攻击, 静态分析