ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

深入解析 Move Prover Docgen 文档生成器的三种输出模式:以 `some` 脚本基线文件为例

深入解析 Move Prover Docgen 文档生成器的三种输出模式:以 `some` 脚本基线文件为例 深入解析 Move Prover Docgen 文档生成器的三种输出模式以some脚本基线文件为例【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址: https://gitcode.com/gh_mirrors/di/diem导读本篇技术文章以 Diem 仓库中 Move Prover 文档生成器Docgen的测试基线文件 some_script.spec_inline_no_fold.md 为核心剖析 Docgen 对 Move 脚本/模块源码生成 Markdown 文档的完整过程与输出结构。文章将结合同目录下的some_script.move源文件、spec_inline.md/spec_separate.md两个对照基线以及 docgen.rs 与 testsuite.rs 的源码实现讲解 Docgen 的调用方式、核心命令行参数、三种文档布局模式的差异与原理帮助读者掌握 Move Prover 文档生成工具的实际用法与基线测试机制。Docgen 是什么Move Prover 内嵌的文档生成器DocgenDocumentation Generator是 Move Prover 项目的一个组成部分其完整说明位于 language/move-prover/doc/user/docgen.md。它的定位并不仅仅是为 Move 代码生成注释文档而是被内嵌进 Move Prover 进程中目标是未来能够利用 Prover 的形式化推理能力为文档补充派生信息并在生成的文档中标注验证结果。在仓库中的代码实现上Docgen 的核心逻辑集中在 docgen/src/docgen.rs该文件定义了Docgen结构体及其完整的文档生成流程包括根模板解析parse_root_template、模块信息计算compute_module_infos、模块文档生成gen_module、函数/结构体/规范块文档生成等。源码中的KEYWORDS与WEAK_KEYWORDS常量列表见 docgen.rs揭示了其对 Move 关键字与规范语言弱关键字的语法高亮规则——前者包含abort、acquires、spec、script等保留字后者包含aborts_if、ensures、forall、schema等仅在特定语法上下文起特殊作用的弱关键字。文档生成器不做完整语法分析因此弱关键字的高亮可能产生少量误报。调用方式与核心命令行参数根据 doc/user/docgen.md 的说明Docgen 通过 move-prover 二进制在 Diem 工作区中调用cargo run -p move-prover -- --docgen flags .. sources常用参数如下表参数说明默认值-dpathMove 依赖的搜索路径供 Move 编译使用无--doc-pathpath已生成文档的搜索路径用于交叉引用doc--doc-spec-inlinetrue\|false规范spec是随函数声明内联展示还是统一放在文档末尾的独立章节true--doc-include-impltrue\|false是否包含函数实现体true--doc-include-privatetrue\|false是否包含私有函数false--outputpath生成的 Markdown 文件存放位置doc命令行完整帮助可通过cargo run -p move-prover -- --help查看。从源码 docgen.rs 可以看到这些参数最终被映射到DocgenOptions结构体的字段specs_inlined对应--doc-spec-inline、include_impl、include_private_fun、collapsed_sections实现与规范是否使用details折叠块、section_level_start、toc_depth、output_directory、doc_path、root_doc_templates、references_file等。默认配置中include_private_fun: true、specs_inlined: true、include_impl: true、collapsed_sections: true、toc_depth: 3、output_directory: doc、doc_path: vec![doc]——注意include_private_fun的源码默认值true与命令行帮助中标注的默认值false存在差异实际行为以DocgenOptions::default()为准。测试基线文件some_script.spec_inline_no_fold.md解读源文件一个什么也不做只是 abort的脚本三个基线文件spec_inline.md、spec_inline_no_fold.md、spec_separate.md都由同一个 Move 脚本源码 some_script.move 生成script { /// This script does really nothing but just aborts. fun someT(_account: signer) { abort 1 } }这是一个极简的脚本级script-levelMove 程序定义泛型函数someT接收一个signer账户参数未使用故命名为_account函数体直接执行abort 1以错误码 1 中止执行。其文档注释使用///语法内容为 This script does really nothing but just aborts.这正是 docgen.md 中文档注释需放在被注释项之前规则的体现。基线文件内容逐段解析some_script.spec_inline_no_fold.md全文结构如下a namesome/a # Script some precode/code/pre This script does really nothing but just aborts. precodebpublic/b(bscript/b) bfun/b a hrefsome_script.md#somesome/alt;Tgt;(_account: signer) /code/pre ##### Implementation precodebfun/b a hrefsome_script.md#somesome/alt;Tgt;(_account: signer) { babort/b 1 } /code/pre其各部分含义锚点与标题a namesome/a是为脚本生成的 HTML 锚点供文档内交叉链接定位紧随其后的是# Script \some一级标题其中Script是 Docgen 对脚本script与模块module的区分修饰词——源码module_modifier函数[docgen.rs](https://link.gitcode.com/i/64525373eda5e57c5d32ed8fe11a9483#L498-L504)会根据名称是否为脚本返回Script或Module。空代码块precode/code/pre是脚本的使用信息区域usage脚本没有use语句因此该代码块为空。对照模块场景docgen.rs 会在此处列出模块引用的其他模块use 模块名;。文档注释即源文件中///注释的内容。函数签名代码块bpublic/b(bscript/b) bfun/b a hrefsome_script.md#somesome/alt;Tgt;(_account: signer)。注意这里的b标签是 Docgen 的代码装饰code decoration——关键字加粗高亮a hrefsome_script.md#somesome/a则是标识符解析identifier resolution的结果some被解析到声明处并生成指向some_script.md#some的超链接。Implementation 小节在spec_inline_no_fold模式下函数实现体以##### Implementation小节的形式直接展开不折叠函数体abort 1中的abort同样以b加粗some生成交叉链接。与另外两种模式的差异inline / separate / no_fold将同一源文件在三种模式下生成的基线并排对比可以直观看出 Docgen 的布局控制效果输出文件specs_inlinedcollapsed_sections表现特征some_script.spec_inline.mdtruetrue实现体包裹在detailssummaryImplementation/summary.../details中默认折叠点击展开some_script.spec_inline_no_fold.mdtruefalse实现体以##### Implementation小节直接平铺展示不做折叠some_script.spec_separate.mdfalsetrue实现体同样折叠当规范不内联时规范统一挪到文档末尾的独立章节由于some脚本没有 spec 块三种模式在规范内联/分离上的差异在此示例中不显著但no_fold 与其余二者的关键差异清晰可见spec_inline.md与spec_separate.md中实现体被details/summary折叠而spec_inline_no_fold.md中实现体以普通小节直接呈现这正是collapsed_sections false的产物。该测试用例的设计意图正是验证不折叠小节模式下输出结构的正确性。基线测试机制testsuite.rs 如何驱动三种模式docgen/tests/testsuite.rs 是驱动这些基线文件生成的测试框架。其测试流程如下通过datatest_stable::harness!(test_runner, tests/sources, r.*\.move|.*_template\.md)自动发现tests/sources目录下所有.move文件与_template.md模板文件作为测试输入。test_runner为每个输入构造 move-prover 调用参数固定附加FLAGS--verbosewarn、--dependency../../move-stdlib/modules、--dependency../../diem-framework/modules、--docgen见 testsuite.rs并在源码中直接设置include_specs true、include_impl true、include_private_fun true。对同一输入依次运行三组配置并生成三个基线文件testsuite.rsspecs_inlined true折叠开启 → 后缀spec_inline.mdspecs_inlined false折叠开启 → 后缀spec_separate.mdspecs_inlined truecollapsed_sections false→ 后缀spec_inline_no_fold.mdtest_docgen函数调用run_move_prover实际执行文档生成将输出写入临时目录再通过verify_or_update_baseline与既有基线文件比对testsuite.rs。对于_template.md根模板文件测试还会把同前缀的所有.notest_move文件作为源码加入并将模板路径写入options.docgen.root_doc_templatestestsuite.rs。文档生成的核心机制注释、装饰与交叉引用文档注释的书写规范根据 docgen.md 的Documentation Comments一节Move 源码中支持两种文档注释语法///单行形式与/** ... */块形式且必须放在被注释项之前。可带文档注释的条目包括模块、结构体、结构体字段、函数、spec 块以及单个 spec 块成员。一段连续的注释序列会被合并为一个文档块例如以下四种写法对函数f完全等价/// This is a documentation comment for f. /// This is another documentation comment for f. fun f() { ... }/// This is a documentation comment for f. /** This is another documentation comment for f. */ fun f() { ... }/** This is a documentation comment for f. This is another documentation comment for f. */ fun f() { ... }some_script.move中/// This script does really nothing but just aborts.即为该规范的最小可运行实例。代码装饰关键字加粗与标识符超链接Docgen 生成文档时会对代码进行两类装饰见 docgen.md 的 Code Decoration 一节关键字高亮如abort、public、script等关键字以b.../b加粗显示。由于 Move spec 语言存在大量弱关键字在特定语法上下文才有特殊含义的标识符而生成器目前不做语法分析高亮可能存在少量误报。标识符解析与超链接生成器尝试将代码中的标识符解析到文档化代码的声明处成功后生成指向声明的链接。例如在模块文档中T、Self::T、DiemAccount::T、0x1::DiemAccount:T都会解析为指向T声明的链接。此解析是启发式的目前不考虑别名alias与use声明且简单的名字如foo只有在其后紧跟(或时才会解析到函数foo避免与函数误匹配建议使用foo()或Self::foo的形式。在some脚本基线中可以看到这两类装饰的落地bpublic/b(bscript/b) bfun/b是关键字加粗a hrefsome_script.md#somesome/a是标识符解析后生成的锚点链接babort/b 1则是实现体中的关键字加粗。注释中的 Markdown 与章节层级调整文档注释可以使用任意 Markdown推荐兼容 GitHub 的 Markdown 风味也可以使用章节标题。Docgen 会把注释中的章节标题自动降一级放入整体文档上下文。例如模块注释中的# Overview在生成后的模块文档中会变为## Overview# Module 0x1::DiemAccount This is the Diem account module. ## Overview ... ## Details ...规范块的归属规则由于 spec 块可以出现在 Move 源码任意位置Docgen 需要一套规则来确定其归属。根据 docgen.md 的 Organization of Specification Blocks 一节所有 schema 与 module spec 块会与前面最近的函数或结构体 spec 块关联若前面没有则归入模块。命名 spec 块如spec S { ... }、spec f { ... }通过目标名显式指定归属可以出现在文件任何位置声明之前、文件末尾等。需要注意的陷阱spec schema与spec module会跟随前一个显式目标例如spec f之后的spec schema FEnsures会归入f而spec f之前的spec schema FAbortsIf可能意外归入之前的结构体S。若想强制后续 spec 块回到模块级可以插入一个空的spec module {}块——它不声明任何性质不会出现在生成文档中但会重置归属module M { fun f(): T { ... } spec f { aborts_if f_aborts(); ensures result f_result(); } // This goes with the documentation of function f spec fun f_aborts() { .. } spec module {} // This goes with the documentation of the module spec fun f_result(): T { .. } }对应到生成逻辑docgen.rs 中的organize_spec_blocks负责构建SpecBlockTarget - spec 块列表的映射随后gen_module依据specs_inlined选项决定是内联在声明旁渲染SpecBlockTarget::Module渲染为 Module Specification 小节还是统一在文档末尾的gen_spec_section中渲染docgen.rs。更多能力根模板、索引、引用文件与关系图从DocgenOptions的定义docgen.rs还可以看到 Docgen 的更多扩展能力根文档模板root_doc_templates允许提供一个 Markdown 模板文件通过占位符控制生成内容的排布。占位符形式为以 Markdown 引用标记开头的一行支持三种 {{move-include NAME_OF_MODULE_OR_SCRIPT}}在模板中嵌入某模块/脚本的生成内容被嵌入的模块不再单独生成文件交叉引用透明工作 {{move-toc}}插入目录TOC {{move-index}}插入当前上下文中所有模块与脚本的索引。模板文件本身同样遵循文档注释的处理规则含交叉引用创建与 Move 代码高亮其解析逻辑见parse_root_templatedocgen.rs。仓库中 root_template.md 及其配套的root_template_*.notest_move文件即为此能力的测试用例。引用文件references_file一个可选的引用定义文件其内容会被追加到每个生成的 Markdown 文档末尾。依赖图与调用图include_dep_diagrams/include_call_diagrams通过外部 Graphviz 工具dot生成模块依赖关系图前向/后向与函数调用关系图SVG生成逻辑见gen_dependency_diagram与gen_call_diagramdocgen.rs并要求环境中安装 Graphviz 的dot命令。目录深度控制toc_depth控制目录中展示的小节最大层级默认 3生成逻辑见gen_tocdocgen.rs。小结以some_script.spec_inline_no_fold.md为切入点可以看到Move Prover 的 Docgen 是一套功能完整的 Move 文档生成方案它内嵌于 Move Prover 进程支持///与/** */文档注释、关键字高亮与标识符交叉链接、spec 块内联/分离两种布局以及实现体折叠/不折叠两种呈现方式。三种后缀spec_inline/spec_separate/spec_inline_no_fold的基线文件并非文档而是测试套件对生成结果的预期输出用于在 testsuite.rs 中以verify_or_update_baseline机制验证 Docgen 行为。若需在自己的 Move 项目中生成 API 文档可在 Diem 工作区中执行cargo run -p move-prover -- --docgen并配合--doc-spec-inline、--doc-include-impl、--doc-include-private、--output等参数按需定制输出布局。参考文件索引关联文档本文主体some_script.spec_inline_no_fold.md对照基线some_script.spec_inline.md、some_script.spec_separate.md测试输入源码some_script.move用户文档language/move-prover/doc/user/docgen.md生成器实现language/move-prover/docgen/src/docgen.rs测试框架language/move-prover/docgen/tests/testsuite.rs根模板测试样例language/move-prover/docgen/tests/sources/root_template.md【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址: https://gitcode.com/gh_mirrors/di/diem创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表