news 2026/9/10 23:22:35

Medusa TSDoc 写作规范全解:writing-tsdocs 技能与 Medusa 自定义标签体系实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Medusa TSDoc 写作规范全解:writing-tsdocs 技能与 Medusa 自定义标签体系实践

Medusa TSDoc 写作规范全解:writing-tsdocs 技能与 Medusa 自定义标签体系实践

【免费下载链接】medusaThe world's most flexible commerce platform for agents and developers项目地址: https://gitcode.com/GitHub_Trending/me/medusa

本文基于 Medusa 仓库内置的writing-tsdocs技能文档(SKILL.md),系统讲解如何为 Medusa 的 TypeScript 源码补充 TypeDoc(TSDoc)注释:覆盖 HTTP 类型、API 路由、UI 组件、数据模型、服务接口、JS SDK、抽象 Provider、Workflow SDK、core-flows 工作流/步骤与事件常量等十类文件,并结合 tsdoc.json 中定义的 Medusa 自定义标签(@expandable@featureFlag@eventPayload等)与仓库中的真实使用证据,给出一套可直接落地的 TSDoc 写作方法论。

一、技能定位:writing-tsdocs 是什么

writing-tsdocs是 Medusa 仓库.claude/skills/目录下定义的一个 AI 技能(Skill),其职责是:为 Medusa 代码库中的 TypeScript 源文件添加和更新 TypeDoc 注释。技能描述明确列出了它适用的文件范围:

  • HTTP 类型:packages/core/types/src/http
  • API 路由:packages/medusa/src/api
  • UI 组件:packages/design-system/ui/src/components
  • 数据模型:packages/modules 下各模块的src/models/
  • 服务接口与类型:packages/core/types/src
  • JS SDK:packages/core/js-sdk/src
  • 抽象 Provider 与工作流工具:packages/core/utils/src
  • Workflow SDK 组合函数:packages/core/workflows-sdk/src
  • core-flows 工作流与步骤:packages/core/core-flows/src
  • 事件常量:packages/core/utils/src/core-flows/events.ts

技能的工作方式是"主文档 + 参考文件":SKILL.md 规定总约束与快速参考,针对每一种文件类型,再加载reference/目录下对应的 7 份参考文档。

二、硬性约束:写错就是事故

技能文档用CRITICAL标注了六条不可违反的约束,违反任何一条都会产生"不正确或损坏的文档":

  1. 永远不要为未导出的项写文档—— 只处理export的 interface、type、function、class;
  2. 永远不要给测试文件加 TSDoc—— 跳过*.spec.ts*.test.ts__tests__/目录;
  3. 永远不要编造@since版本号—— 只能使用提示词(prompt)中明确给出的版本;
  4. 永远不要删除或修改已有 TSDoc—— 只在缺失处补充;
  5. 永远不要修改逻辑—— 只增改注释块;
  6. Medusa 自定义标签只能用 tsdoc.json 中定义的那些@expandable@featureFlag@since@apiIgnore@schema@tags@version@keep@customNamespace@namespaceMember

这些约束背后的工程考量:TSDoc 是 API 文档的"源头数据",文档生成工具会把它直接编译进对外发布的 API Reference。版本号错误、标签未注册、文档了内部实现,都会直接污染生成产物。

三、文件类型与参考文档的映射关系

技能规定:在写任何 TSDoc 之前,先加载该文件类型对应的参考文档。映射表如下:

路径模式加载的参考文档
packages/core/types/src/http/reference/http-types.md
packages/medusa/src/api/admin//store/reference/api-routes.md
packages/design-system/ui/src/components/reference/ui-components.md
packages/modules/*/src/models/reference/data-models.md
packages/core/types/src/(非 http)、packages/core/js-sdk/src/packages/core/utils/src/(abstract provider)、packages/core/workflows-sdk/src/utils/composer/reference/service-interfaces.md
packages/core/core-flows/src/(workflows / steps)reference/workflows-steps.md
packages/core/utils/src/core-flows/events.tsreference/events.md

四、基础格式与各类型"文档深度矩阵"

4.1 TSDoc 块的基础格式

最基本的格式就是标准 JSDoc 块注释——先一句简要描述,再为每个属性单独写注释:

/** * Brief description. */ export interface Foo { /** * The foo's ID. */ id: string }

4.2 按文件类型决定"写到多深"

技能用一张矩阵规定了十种文件类型各自的文档范围与关键标签。这是全文档体系中最核心的"深度控制"原则:并非所有文件都值得(也需要)完整 JSDoc

文件类型文档范围Medusa 关键标签
HTTP 类型每个导出的 interface/type + 全部属性嵌套对象加@expandable
API 路由仅导出的 handler(极简)@featureFlag@since
UI 组件组件 + 全部 props纯描述
数据模型模型 + 每个属性新增项加@since
服务接口每个方法完整文档@param@returns@example
JS SDK每个公共方法@param@returns@example@tags
Provider类 + 每个抽象方法@param@returns@example
Workflow SDK每个导出函数@param@returns@example
core-flows 工作流工作流导出 + hooks@summary@featureFlag@since
core-flows 步骤步骤导出 + 输入类型@featureFlag@since@example
事件每个事件常量@eventPayload@featureFlag@since

标准 TSDoc/JSDoc 标签(@param@returns@example@deprecated@remarks等)始终允许使用。

五、Medusa 自定义标签体系:以 tsdoc.json 为准

技能文档中提到的自定义标签,其权威定义位于 www/utils/packages/typedoc-config/tsdoc.json。该文件通过"extends": ["typedoc/tsdoc.json"]继承标准 TSDoc 标签集,再用tagDefinitions扩展 Medusa 专属标签。技能速查表中列出的十个标签及用途:

标签语法种类使用场景
@featureFlag <name>block该导出需要开启某个 feature flag 才可用
@expandablemodifier该属性是可通过 API 查询展开的嵌套对象
@since <version>block该导出在此版本新增(仅使用提示词给定的版本)
@apiIgnoremodifier从 API 文档输出中排除
@tags <name>blockSDK 方法分类
@schemablock自定义 schema 文档
@keepmodifier文档生成时保留该属性
@customNamespaceblock分配到自定义文档命名空间

此外,从 tsdoc.json 的完整定义看,仓库中还注册了更多标签,供特定文档场景使用:

  • @eventPayload(block)——事件常量专用,描述事件负载结构;
  • @eventName@workflows@workflowEvent@workflowLock(block)——工作流/事件关联文档;
  • @version(block)、@namespaceMember(modifier)、@parentIgnore(block)、@typeParamDefinition(block);
  • @excludeExternal@mainSignature@docHideSignature(modifier)——控制继承属性与签名在生成文档中的呈现,前两者在 UI 组件文档中实际使用(见下文)。

这一点值得注意:技能文档的速查表是"写作白名单",tsdoc.json 才是"注册全集"。写作者应遵循更严格的那份清单,而读者可以依据 tsdoc.json 理解生成文档中出现的其它标签。

六、十类文件的写作细则

6.1 HTTP 类型:@expandable 与"可展开实体"的判断

HTTP 类型文件位于packages/core/types/src/http/,定义 Medusa REST API 的请求/响应形状。规则要点(详见 reference/http-types.md):

  • 每个导出的interface/type用一句描述;每个属性用对 API 消费者有意义的简短描述;
  • 对"另一个可通过fields查询参数展开获取的 interface"类型的属性使用@expandable
  • 联合/枚举语义字段用项目符号逐一解释取值;
  • 不得对 HTTP 类型使用@param@returns@since——它们是数据形状,不是方法。

@expandable的判断标准是这个标签的核心:被引用类型必须是"完整实体",可通过?fields=+xxx展开获取;标量与内嵌值对象(embedded value object)不加。参考文档给出的经典对比:

export interface AdminOrder { /** * The associated shipping methods. * @expandable */ shipping_methods?: AdminOrderShippingMethod[] /** * The associated customer. * @expandable */ customer?: AdminCustomer | null /** * The order's total amounts. */ summary: BaseOrderSummary // 内嵌值对象——不可独立获取,不加 @expandable }

仓库中的实际使用情况印证了这一规范:在packages/core/types/src/http/下,@expandable已大量出现在 order/common.ts、cart/common.ts、payment/common.ts、collection/common.ts 等核心类型文件中,仅 order 一个文件就有多处使用。

对于语义明确的字符串状态字段,规范给出统一写法:

/** * The order's status: * - `pending` — the order is awaiting payment * - `completed` — the order has been fulfilled and paid * - `cancelled` — the order has been cancelled * - `archived` — the order has been archived */ status: OrderStatus

而继承BaseFilterable的过滤器接口,则按"Filter by xxx."句式逐个说明过滤属性:

/** * The filters to apply when listing orders. */ export interface AdminOrderFilters extends BaseFilterable<AdminOrderFilters> { /** * Filter by order IDs. */ id?: string | string[] /** * Filter by order status. */ status?: OrderStatus | OrderStatus[] }

参考文档还附了一个完整的 Before/After 示例(BaseOrderAdjustmentLine接口从裸字段到逐属性注释),可作为 HTTP 类型文档的样板:接口级一句 "The order adjustment line's details.",属性级明确id归属("The ID of the order this adjustment belongs to.")、created_at/updated_at用 "The date the adjustment was created/last updated." 的固定句式。

6.2 API 路由:极简主义与 Feature Flag 探测

API 路由文件位于packages/medusa/src/api/admin/packages/medusa/src/api/store/,导出GETPOSTDELETEPATCH等命名 handler。规则是反直觉但明确的"越少越好"(详见 reference/api-routes.md):

  • 只给导出的 handler 函数加 TSDoc;
  • 只允许@featureFlag和/或@since,不写完整方法文档;
  • 若 handler 既无 feature flag 又不是新增的,则不加任何 TSDoc
  • 不加@param@returns@example和描述。

Feature flag 的探测方法:查看 handler 函数体内是否调用FeatureFlag.isFeatureEnabled(...)@featureFlag的值取 flag 的 key 字符串(如IndexEngineFeatureFlag.key对应"index_engine");同时检查路由是否基于 flag 在路由注册配置或中间件中条件注册。

条件添加内容
handler 使用FeatureFlag.isFeatureEnabled(XFlag.key)@featureFlag <flag_key>
handler 是本次 diff 中的新增@since <version>
handler 是既有的且无 feature flag什么都不加

典型输出:

/** * @since 2.14.0 * @featureFlag view_configurations */ export const GET = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse<HttpTypes.AdminViewConfigurationListResponse> ) => { /* ... */ }

路由文件中偶尔导出的 validator 或 helper 不属于模块公共面,无需 TSDoc。

6.3 UI 组件:内联 prop 注释、Radix 与 @excludeExternal/@keep

UI 组件位于packages/design-system/ui/src/components/。规则(详见 reference/ui-components.md):

  • 组件用一句描述;props 以内联注释写在解构参数列表中,而不是给Propsinterface 单独写注释(除非该 interface 本身被导出);
  • 基于 Radix UI 的组件,在组件文档中指明所基于的 Radix 原语;纯透传 Radix props、无自定义属性的薄封装组件,只写组件级描述即可;
  • 不给组件加@param/@returns/@since(除非组件是新增且版本已给定)。

内联 prop 文档的正确/错误对照:

// 正确——内联 prop 文档 const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( ( { /** * The button's visual style. */ variant = "primary", /** * The button's size. */ size = "base", /** * Whether to render as the child element instead of a `button`. */ asChild = false, /** * Whether to show a loading spinner. */ isLoading = false, disabled, className, children, ...props }, ref ) => { /* ... */ } )

对于Props继承自原生 HTML 元素类型(如React.ComponentPropsWithoutRef<"div">)的组件,继承来的classNamechildrenstyleid等大量属性不该出现在生成文档中。规范给出两级控制:

  • @excludeExternal:加在组件 TSDoc 块上,抑制所有继承的外部属性;
  • @keep:若某个被继承的属性在本组件中有非平凡行为(如disabled触发自定义视觉状态、onInvalid接入了内部校验),在该 prop 的内联注释中加@keep(可附@defaultValue)使其保留;而classNamestyleid这类通用透传属性绝不@keep

Props只含自定义属性(没有 extends 外部类型),则可省略@excludeExternal

6.4 数据模型:DML 实体与 @since 的"diff 纪律"

数据模型位于packages/modules/*/src/models/,使用 DML(Data Model Language)的model.define(...)定义实体。规则(详见 reference/data-models.md):

  • 模型级const用一句实体描述(完整句或简短名词短语均可);
  • 每个属性一句简短描述;
  • @since <version>只加在本次 diff 中新增(仅出现在新增行)的属性或模型上;
  • 字符串格式不直观的属性(locale 码、货币码、时区)用@example说明;
  • 主键id不写文档(约定俗成);
  • 关系属性统一句式:"The associated [related model]."
/** * A locale supported by a store. * @since 2.14.0 */ const StoreLocale = model.define("StoreLocale", { /** * The BCP 47 language tag code of the locale. * @example "en-US" */ locale_code: model.text().searchable(), /** * The associated store. */ store: model.belongsTo(() => Store, { mappedBy: "supported_locales" }).nullable(), })

关系属性的三种标准句式:

/** The associated store. */ store: model.belongsTo(() => Store, { mappedBy: "supported_locales" }), /** The product's variants. */ variants: model.hasMany(() => ProductVariant, { mappedBy: "product" }), /** The variant's images. */ images: model.manyToMany(() => ProductImage, { mappedBy: "variants" }),

反例清单同样明确:不要给主键id: model.id({ prefix: "pv" }).primaryKey()写文档,不要给本次提交之前就存在的属性补@since

6.5 服务接口、JS SDK、Provider、Workflow SDK:同一套"完整 JSDoc"模式

这四类文件共用同一参考文档(reference/service-interfaces.md),都采用完整 JSDoc模式:

  • 接口/类本身一句描述;
  • 每个公共方法写:描述 +@param+@returns+@example
  • JS SDK 方法额外加@tags <category>(与 SDK 模块分类对应,如@tags products);
  • 方法描述以 "This method [verb phrase]." 开头;
  • 固定格式:@param {Type} name - Description.@returns {Promise<Type>} Description of resolved value.

完整的 retrieve 方法样板:

/** * This method retrieves a product by its ID. * * @param {string} productId - The ID of the product to retrieve. * @param {FindConfig<ProductDTO>} config - The configurations determining how the product is retrieved. Its properties, such as `select` or `relations`, accept the attributes or relations associated with a product. * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. * @returns {Promise<ProductDTO>} The retrieved product. * * @example * const product = await productModuleService.retrieveProduct("prod_123") */ retrieveProduct( productId: string, config?: FindConfig<ProductDTO>, sharedContext?: Context ): Promise<ProductDTO>

几个值得注意的细节:

  • sharedContext参数有固定标准描述:"A context used to share resources, such as transaction manager, between the application and the module."——它几乎出现在所有模块服务方法上,统一措辞可避免文档漂移;
  • 列表方法@example应展示多个真实场景(按 ID 列表、带relations查询),多个场景用标签分段;
  • 抽象 Provider 方法@example以"继承该抽象类的实现类"形式给出,如class MyPaymentProvider extends AbstractPaymentProvider { async initiatePayment(input) { ... } }
  • Workflow SDK 组合函数(如createStep)也要为compensateFn这类可选参数用[compensateFn]方括号标注。

6.6 core-flows 工作流与步骤:@summary、hooks 与 step 输入类型

工作流与步骤文件位于packages/core/core-flows/src/,分别用createWorkflow(...)createStep(...)创建(详见 reference/workflows-steps.md)。

工作流文档要求:

  • 一段描述,说明工作流做什么、何时被使用,并链接到执行它的 API 路由(如适用);
  • @example展示如何调用.run()
  • @summary一行摘要;
  • 每个hooks.*钩子一条@property hooks.xxx条目;
  • 新增时加@since,受 flag 控制时加@featureFlag
export const myWorkflowId = "my-workflow" /** * This workflow [does X]. It's executed by the [Some API Route]. * * You can use this workflow within your own customizations or custom workflows, * allowing you to wrap custom logic around [the operation]. * * @example * const { result } = await myWorkflow(container) * .run({ input: { id: "foo_123" } }) * * @summary * * [One-line summary of what the workflow does.] * * @property hooks.myHook - This hook is called [when/before/after X]. You can * use it to [describe what customization is possible]. */ export const myWorkflow = createWorkflow(myWorkflowId, (input) => { /* ... */ })

钩子文档的标准句式:"This hook is called before/after X. You can use it to ....",逐钩子一条:

* @property hooks.validate - This hook is called before all operations. You can * use it to validate the input or perform any custom validation logic. * * @property hooks.setPricingContext - This hook is called after the cart is * retrieved. You can use it to pass custom pricing context to the workflow.

步骤文档要求:描述步骤做什么(含抛错/返回条件)、@example展示调用方式、@since/@featureFlag(如适用),并为步骤的输入类型 interface 逐属性写描述,且用{@link stepName}交叉引用关联步骤:

/** * The input for the {@link validateCartStep}. */ export interface ValidateCartStepInput { /** * The cart to validate. */ cart: CartWorkflowDTO | CartDTO }

对仅受 flag/版本控制的简单步骤,允许只写"标签型"文档:

/** * @since 2.10.3 * @featureFlag view_configurations */ export const createViewConfigurationStep = createStep(/* ... */)

明确不写文档的对象:*Id字符串常量(如export const addToCartWorkflowId = "add-to-cart")、模块内部未导出的 helper、以及createStep第三个参数(补偿函数——属于内部实现细节)。

6.7 事件常量:@eventPayload 负载结构规范

事件常量位于 packages/core/utils/src/core-flows/events.ts,按命名空间对象分组导出(如CartWorkflowEventsOrderWorkflowEvents)。规则(详见 reference/events.md):

  • 每个事件常量写"何时被发出"的描述("Emitted when [resource] is [action].");
  • 必须包含@eventPayload展示负载结构(TypeScript 代码块,每个属性带内联注释);
  • 事件在本次 diff 中新增时加@since,且@since置于@eventPayload之前,使版本信息先出现;
  • 受 flag 控制时加@featureFlag
  • 命名空间对象本身一般不写文档,除非它确实缺描述且同文件其它命名空间已统一使用@category+@customNamespace模式。

@eventPayload的一个精细规则:字符串 ID 不标注类型,非字符串值必须用(type)标注

/** * Emitted when an order's fulfillment is created. * * @eventPayload * ```ts * { * order_id, // The ID of the order * fulfillment_id, // The ID of the fulfillment * no_notification, // (boolean) Whether to notify the customer * } * ``` */ FULFILLMENT_CREATED: "order.fulfillment_created",

完整的 Before/After 示例(OrderWorkflowEvents三个事件从裸常量到带@eventPayload的注释)是事件文档的基准样板。

仓库实证:当前 events.ts 中已存在 83 处@eventPayload注释,说明该规范已在事件常量文档化中被系统性执行;而@featureFlag也已在packages/medusa/src/api/admin/下多条路由(如admin/index/details/route.tsadmin/locales/route.ts等)中落地。

七、常见错误清单(Common Mistakes)

技能文档最后给出了一份自查清单,覆盖五类高频错误:

  • 为未导出或private项写了文档;
  • 提示词未提供版本号时使用了@since
  • 属性描述超过 2 句话;
  • 给非方法导出(interface、type)加了@param/@returns
  • 文档化了id字段却没有指明它属于哪个资源。

这份清单与前述各参考文档的"What NOT to Document"章节互为呼应,可作为提交前的最后一道检查。

八、体系总结:一套"按类型分级"的文档工程方法

把 SKILL.md 与 7 份参考文档合起来看,Medusa 的 TSDoc 体系有三个可迁移到其它大型 TypeScript 项目的设计思想:

  1. 文档深度与公共面成正比:API 路由 handler 只标 flag/版本,HTTP 类型逐属性注释,服务接口才需要完整 JSDoc +@example。文档预算跟着"消费者是谁"走,而不是对所有代码一刀切;
  2. 自定义标签 = 文档生成器的可编程开关@expandable驱动前端字段展开、@featureFlag驱动文档按 flag 分组、@apiIgnore/@excludeExternal/@keep控制呈现粒度、@eventPayload把事件负载结构嵌入文档——标签不是装饰,而是文档构建流水线的一等输入,其注册必须集中在 tsdoc.json 单点管理;
  3. 事实纪律@since只认提示词给定的版本、只给 diff 新增项打标签、不碰测试文件、不改逻辑——保证文档注释永远可以追溯到一个真实的变更来源。

对维护者而言,这套规范的最佳使用路径是:确认目标文件落在第三节的映射表中哪一行,加载对应参考文档,按第四节的深度矩阵确定文档范围,用第五节的标签表约束自定义标签,最后过一遍第七节的常见错误清单——即可获得与仓库现有 83 处@eventPayload、遍布 http 类型的@expandable同一水准的 TSDoc 输出。

【免费下载链接】medusaThe world's most flexible commerce platform for agents and developers项目地址: https://gitcode.com/GitHub_Trending/me/medusa

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 23:22:20

MCP协议:实现AI工具高效协同的云原生解决方案

1. 项目概述&#xff1a;当AI工具需要相互认识时在AI技术快速发展的今天&#xff0c;各类AI工具如雨后春笋般涌现。但一个现实问题逐渐浮出水面&#xff1a;这些工具之间往往"互不相识"&#xff0c;无法有效协作。这就好比一个团队里每个人都能力出众&#xff0c;却因…

作者头像 李华
网站建设 2026/9/10 23:19:20

8 家降噪算法横评总评:谁在什么场景下最强?

本系列前面几篇讲完了 8 家降噪算法的原理、代码和 5 case 定性观感&#xff0c;本篇把它们放到同一批 332 条音频上做统一 STOI DNSMOS 评测&#xff0c;从性价比、场景敏感度、有参 / 无参一致性等多角度看真实分层。8 家一览&#xff1a;分层算法参数量采样率出处端侧实时R…

作者头像 李华
网站建设 2026/9/10 23:19:17

纽约出租车流量预测:时空图神经网络实战指南

简介&#xff1a;本资源是一份面向人工智能课程学习者与初学者的纽约出租车流量预测实战项目&#xff0c;基于深度学习技术实现时空序列建模&#xff0c;适用于期末大作业、课程设计及深度学习入门实践。压缩包共31个文件&#xff0c;包含9个核心Python源码&#xff08;含GRU、…

作者头像 李华