ARTICLE DETAIL

资讯详情

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

Aspire CLI 的 API 文档命令组:aspire docs api 的设计规格与源码实现解析

Aspire CLI 的 API 文档命令组:aspire docs api 的设计规格与源码实现解析 Aspire CLI 的 API 文档命令组aspire docs api 的设计规格与源码实现解析【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire本文基于 Aspire 仓库中的规格文档 api-docs-commands.md系统讲解aspire docs api命令组的完整设计它如何从aspire.dev的 sitemap 构建 API 参考索引如何按作用域浏览 C# 与 TypeScript 的 API 目录如何用加权词法搜索定位 API 条目以及如何按稳定标识符取回 Markdown 内容。读完本文你将掌握该命令组的命令面、标识符模型、层次模型、缓存机制以及 源码实现 中的评分权重与索引管线细节。设计背景为什么需要独立的 API 文档管线Aspire CLI 的aspire docs命令族负责把aspire.dev站点内容引入命令行。根据规格文档aspire docs api虽然也挂在aspire docs下但走的是与现有 prose 文档命令不同的摄取ingestion管线aspire docs索引的是llms-full.txt面向自然语言文档的单篇式文本aspire docs api索引的是sitemap-0.xml并把直接的 API 页面路由作为可寻址条目addressable items。这一区分决定了整个命令组的核心设计取向API 参考页是层级化的包 → 类型 → 成员组因此 CLI 需要一套稳定的路径式标识符和分作用域的浏览模型而不是一股脑地把所有 API 倒出来。目标与非目标规格文档明确了 5 个设计目标通过 Aspire CLI 暴露 API 参考内容尽可能复用现有的抓取fetch、ETag 与磁盘缓存模式保留 API 层级结构让 CLI 可以浏览目录而不必一次性输出全部 API同时支持 C# 与 TypeScript 的 API 参考页get操作返回 Markdown 格式内容。同时列出 3 个非目标Non-goals界定了功能边界不做无作用域的全量目录列表full unscoped catalog listing不做面向aspire.dev全部内容的通用网页爬虫不做超出 Aspire API 路由结构的跨语言标识符归一化。这组“非目标”在实现中体现得很彻底源码里 ApiReferenceLanguages 明确将受支持语言集合固定为csharp和typescript两种list也始终以 scope 为参数从不返回整个目录。命令面list / search / get 三件套命令组的完整命令面如下aspire docs api list scope [--format json] aspire docs api search query [--language language] [--limit|-n count] [--format json] aspire docs api get id [--format json]这三个子命令在源码中分别由 ApiListCommand.cs、ApiSearchCommand.cs、ApiGetCommand.cs 实现并由父命令 ApiCommand.cs 统一注册到docs命令树下的api节点。list按作用域浏览list接受一个必选的scope位置参数和--format选项。默认以表格渲染表头为 Name、Id、Kind、Group 四列Group 列显示成员组无则为---format json则直接输出 JSON 数组。源码中的实现逻辑值得注意空结果时不会报错退出而是提示“在该 scope 下未找到条目”并返回成功列表按条目Kind的固定顺序排序包/模块 → 类型/符号 → 成员组/成员再按名称排序保证浏览体验稳定。search语言过滤与结果数量控制search的参数组合为--language可选语言过滤、--limit/-n结果数量上限与--format。这里有一个规格文档没有写明、但源码中明确存在的约束var limit Math.Clamp(parseResult.GetValue(s_limitOption) ?? 5, 1, 10);见 ApiSearchCommand.cs结果默认返回 5 条且--limit的值被钳制在 1 到 10 之间。也就是说--limit 50实际等价于 10。此外--language传入了不受支持的语言值时服务层会直接返回空结果集而不是报错。get按标识符取回 Markdownget接受唯一的必选参数id精确的 API 标识符与--format。非 JSON 模式下源码调用InteractionService.DisplayMarkdown(item.Content)直接在终端渲染 Markdown 正文找不到条目时返回失败码并提示该 id 不存在。浏览模型作用域语义list是一个有作用域限制的浏览命令它永远不返回整个 API 目录。支持的 scope 形如aspire docs api list csharp aspire docs api list csharp/package aspire docs api list csharp/package/type aspire docs api list typescript aspire docs api list typescript/module aspire docs api list typescript/module/symbol各 scope 的返回语义如下表继承自规格文档Scope返回内容csharp顶层 C# 包packagescsharp/package包内的类型typescsharp/package/type该类型的成员组页面如methods、properties、constructorstypescript顶层 TypeScript 模块modulestypescript/module模块内的直接符号symbolstypescript/module/symbol符号下的成员members关键约束如果一个 scope 没有子项list返回空结果而不会横向扩展或返回兄弟作用域。从源码看ApiDocsIndexService.ListAsync 的过滤逻辑正是严格的父级匹配——只挑出ParentId与归一化后 scope 相等的条目不做任何“找不到就向上/向旁找”的兜底这与规格中的语义一一对应。标识符模型从路由派生的稳定 IDCLI 使用从 API 路由结构派生的路径式稳定标识符。基本规则是对于 sitemap 支撑的页面标识符等于路由路径中/reference/api/之后的部分去掉尾部斜杠。规格文档给出的示例csharp/aspire.azure.ai.inference csharp/aspire.azure.ai.inference/aspireazureaiinferenceextensions typescript/aspire.hosting.azure.appconfiguration typescript/aspire.hosting.azure.appconfiguration/azureappconfigurationresource typescript/aspire.hosting.azure.appconfiguration/azureappconfigurationresource/runasemulator在实现中这条规则由 sitemap 解析后逐段拼接而来。BuildCSharpItems 根据 URL 段数生成不同层级的条目1 段是包csharp/package2 段是类型csharp/package/type3 段是成员组csharp/package/type/member-groupTypeScript 侧的 BuildTypeScriptItems 同理1 段为模块、2 段为符号或成员、3 段为成员。查找时对 id 做Trim().Trim(/)归一化见 NormalizeId所以用户粘贴标识符时多带一个首尾斜杠也不影响匹配。层次模型与 kind 分类规格文档定义了两条对外暴露的层级链C#language - package - type - member-group pageTypeScriptlanguage - module - symbol - member与 sitemap 结构直接对齐源码中每个条目都带一个kind字段取值由 ApiReferenceKinds 固定为package、module、type、symbol、member、member-group。这里有一个实现层面的细节可以印证规格中“保留 API 层级”的目标TypeScript 的 2 段路径条目其 kind 并非拍脑袋决定而是动态判定的——如果typescript/module/symbol这个 id 同时也是一个包含 3 段子页面的容器即 sitemap 中存在它的子页面则标记为symbol否则标记为member。这保证了list在typescript/module下能正确区分“可继续下钻的符号”与“叶子成员”。搜索行为加权词法匹配与评分权重规格文档规定search对索引执行加权词法匹配weighted lexical matching优先级依次为精确标识符匹配 精确 API 名称匹配 包/模块匹配 类型/符号匹配 成员组匹配 若索引元数据可用的话摘要与描述片段匹配并且要求搜索结果包含足够元数据让用户能直接把返回的标识符复制进aspire docs api get。源码中的 ScoreItem 方法完整实现了这套优先级具体权重常量定义于 ApiDocsIndexService.cs如下常量权重含义ExactIdMatchBonus60.0标识符完全相等加分ExactNameMatchBonus45.0名称完全相等加分NamePrefixMatchBonus32.0名称前缀匹配加分PathSegmentMatchBonus20.0查询词命中 ID 的任一路径段PathPrefixMatchBonus18.0路径段前缀匹配加分PrefixTightnessMaxBonus16前缀“紧致度”上限匹配段与查询词长度差越小加分越高最长额外 16 分NameWeight10.0名称字段词法得分的乘数IdWeight8.0标识符字段词法得分的乘数SummaryWeight4.0摘要字段词法得分的乘数MemberGroupWeight3.0成员组字段词法得分的乘数ParentWeight2.5父级标识符字段词法得分的乘数在此基础上还有两类“宽泛查询”单个长度 ≥5 且不含/ # . ( )等字符的裸词查询的额外处理前缀匹配加分名称或路径段以查询词开头时在 32 / 18 基础分之外再按紧致度加分kind 倾向加分GetBroadQueryKindBonustype/symbol28、package/module16、member-group8使宽泛搜索优先浮出类型和符号。分词方面查询文本经LexicalScoring.Tokenize切分最小词元长度为 2MinTokenLength 2词法得分按“标识符连字符”模式IdentifierWithHyphen计算。结果按分数降序、同分按 id 字典序排列后取前 topK 条。另外规格中“搜索结果应含足够元数据”这一点在输出模型上得到落实每条搜索结果都携带id、name、language、kind、parentId以及实现中额外包含的memberGroup、summary字段可以直接把id复制给get使用。Get 行为直接路由项与 Markdown 解析get按精确标识符解析条目并返回 Markdown 内容。对于标识符直接映射到页面路由的条目规格所称 direct-route items流程是在内存索引中按归一化后的 id 查表命中条目通过抓取器取回该 API 页面的 Markdown将页面中站点相对链接改写为绝对 URL 后返回。第 3 步由 ApiDocsSourceConfiguration.RewriteMarkdownLinks 完成以正则在 Markdown 中匹配](/...)与](#...)形式的本地链接分别补全为站点根和当前页 URL保证终端输出的内容里链接是可点击的。实现中还有一层规格文档只字未提、但对体验很关键的机制——成员索引的懒加载。C# 类型的成员方法、属性等并不全部预先进入 sitemap 级索引而是当get的 id 带有#fragment定位到某个成员或list的 scope 是一个member-group页时才按需抓取对应类型页、用 ApiMemberMarkdownParser 从 Markdown 中解析出成员条目并合并进索引见 GetMemberContainerIdForId 与 EnsureMemberContainersIndexedAsync解析出的成员索引同样落盘缓存。搜索路径同样受益当基础路由搜索无果或未命中成员级条目时服务会按批次MemberSearchBatchSize 8并行展开候选容器页继续搜索。数据来源与缓存策略规格文档规定实现使用三个要素以https://aspire.dev/sitemap-0.xml作为 API 目录来源采用固定的 Markdown 解析规则——在规范 API 页面 URL 后追加.md得到 Markdown 地址对 sitemap 与页面内容都做 ETag 缓存与磁盘持久化。并且要求不要把 sitemap 和 Markdown 端点硬编码进命令处理器。实现遵循了这一点端点全部收敛在 ApiDocsSourceConfiguration.cs 中默认 sitemap URL 为常量DefaultSitemapUrl https://aspire.dev/sitemap-0.xml支持通过配置路径docs:api:sitemapUrl覆盖来源GetSitemapUrl便于测试或对接环境BuildMarkdownUrl 实现“追加.md”规则先剥离 URL fragment再把页面 URL 的 scheme/host/port 重定基rebase到配置的 sitemap 来源主机最后若尚未以.md结尾则追加RebasePageUrl 保证 sitemap 覆盖后条目中的页面 URL 与 sitemap 指向同一主机避免跨源抓取。缓存链路由 ApiDocsFetcher.cs 与 ApiDocsCache.cs 承担在 EnsureIndexedAsync 中体现为四级策略内存已索引则直接返回抓取 sitemap 失败但本地有缓存索引 →降级使用缓存索引并记录告警离线或网络抖动时命令仍然可用sitemap 抓取成功用SourceContentFingerprint.Compute(sitemapContent, IndexSchemaVersion)计算源内容指纹与缓存指纹比对——一致则直接从磁盘缓存加载索引跳过重新解析指纹变化或无缓存→ 解析 sitemap、重建索引并写回磁盘缓存与指纹。IndexSchemaVersion当前为 1是缓存 schema 版本号源码注释说明只要代码变更导致同一 sitemap 会生成不同的索引数组就应提升该版本以使旧缓存自动失效。成员级索引另有独立指纹v2:{基础指纹}与基础索引指纹联动失效。解析管线从 sitemap 到三个命令规格文档将 API 管线描述为五个步骤源码实现与之逐条对应抓取 sitemap_fetcher.FetchSitemapAsync解析 C# 与 TypeScript API 路由ApiSitemapParser.Parse 产出ApiSitemapEntry含语言与路径段构建层次化 API mapBuildBaseItems按语言分派到BuildCSharpItems/BuildTypeScriptItems再经Deduplicate按 id 去重;把构建好的索引持久化到磁盘_cache.SetIndexAsync 指纹写入用索引服务list/search/get。索引构建完成后条目按 id 排序OrderBy(item.Id, OrdinalIgnoreCase)既保证输出稳定也便于list的排序逻辑。输出模型三种 JSON 形状规格定义了三种命令的输出模型实现中的 POCO 类与之对齐并各自带有一条注释提醒改动时与 cli-output-formats.md 保持同步List 输出ApiListItemid、name、language、kind、parentId实现另含memberGroup供表格 Group 列展示Search 输出ApiSearchResultid、name、language、kind、parentId、score实现另含memberGroup、summaryGet 输出ApiContentid、name、language、kind、parentId、url、content实现另含memberGroup--format json均通过System.Text.Json的源生成序列化上下文输出JsonSourceGenerationContext.RelaxedEscaping避免运行时反射序列化开销。测试覆盖规格文档要求的功能测试点在仓库中均有对应测试文件位于 tests/Aspire.Cli.Tests/Mcp/ApiDocs/ 目录规格要求的测试点对应测试文件sitemap 解析与过滤ApiSitemapParserTests.csC# 成员组页面索引 / TypeScript 层次解析 / 作用域 list / 语言过滤 search / 标识符 getApiDocsIndexServiceTests.csETag 感知的抓取行为ApiDocsFetcherTests.cs磁盘持久化的 API 索引缓存ApiDocsCacheTests.cs来源配置URL rebase、Markdown URL 规则、链接改写ApiDocsSourceConfigurationTests.cs成员 Markdown 解析ApiMemberMarkdownParserTests.cs命令层行为表格渲染、JSON 输出、错误分支另有 ApiCommandTests.cs 覆盖。测试中使用 TestApiDocsFetcher 注入伪造的抓取器使整条管线可以在不访问真实站点的情况下验证。小结一个可复用的文档索引模式aspire docs api的设计可以用三句话概括用 sitemap 代替爬虫获得稳定的可寻址条目集合用路由路径派生的标识符让浏览、搜索、取回三个动作共享同一套寻址方案用 ETag 内容指纹 磁盘缓存让索引构建昂贵但可增量、可离线降级。对于想在自己的 CLI 中接入站点参考文档的场景这套“sitemap → 层次索引 → 稳定 ID → 懒加载详情”的管线源码集中在 src/Aspire.Cli/Documentation/ApiDocs/以及docs:api:sitemapUrl这类“来源可配置、端点不硬编码”的做法都是可以直接借鉴的工程实践。【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表