
Dagger TypeScript SDK 中 ModuleGeneratorsOpts 类型别名include 模式过滤与 GeneratorGroup 详解【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger导读本文聚焦 Dagger TypeScript SDKdagger.io/daggerv0.19 版本 API 参考中的ModuleGeneratorsOpts类型别名。它定义了Module.generators()方法的可选参数核心能力是通过include?: string[]按 glob 模式筛选模块定义的生成器generator。读完本文你将掌握该选项的精确类型签名、pattern 的匹配语义包含 glob 通配与路径包含两种规则、在模块树上的底层实现Rollup 机制以及它如何与GeneratorGroup、Generator、Changeset等对象协作完成代码生成流水线。ModuleGeneratorsOpts 类型定义ModuleGeneratorsOpts在 Dagger 的 TypeScript 客户端 API 中定义为一个object类型的别名仅包含一个可选属性export type ModuleGeneratorsOpts { /** * Only include generators matching the specified patterns */ include?: string[] }完整源码见 sdk/typescript/src/api/client.gen.ts#L2297-L2302。该文件是由 codegen 自动生成的客户端类型定义对应 Go 侧由 cmd/codegen 驱动生成因此该类型与 GraphQL schema 中的generators参数一一对应。其结构要点属性类型必填语义includestring[]可选只包含匹配指定模式pattern的生成器该选项由Module.generators()方法消费方法签名如下见 sdk/typescript/src/api/client.gen.ts#L11801-L11809/** * Return all generators defined by the module * param opts.include Only include generators matching the specified patterns * experimental */ generators (opts?: ModuleGeneratorsOpts): GeneratorGroup { const ctx this._ctx.select(generators, { ...opts }) return new GeneratorGroup(ctx) }调用后返回一个GeneratorGroup对象opts中的include会作为 GraphQL 查询参数被展开并传递给引擎。该 API 在注释中被标记为experimental说明 generators 相关能力仍处于演进中。include 参数从类型签名到引擎实现include参数负责在模块树module tree上执行一次过滤只有路径匹配给定模式的生成器节点会被纳入返回的GeneratorGroup。从源码结构看该参数最终被转换为引擎侧的字符串切片进入core.GeneratorGroup的构造逻辑。在 Go 引擎侧core/generators.go#L215-L235 的NewGeneratorGroup是核心入口func NewGeneratorGroup(ctx context.Context, mod dagql.ObjectResult[*Module], include []string) (*GeneratorGroup, error) { rootNode, err : NewModTree(ctx, mod) if err ! nil { return nil, err } generatorNodes, err : rootNode.RollupGenerator(ctx, include, nil) if err ! nil { return nil, err } generators : make([]*Generator, 0, len(generatorNodes)) for _, generatorNode : range generatorNodes { generators append(generators, Generator{Node: generatorNode}) } return GeneratorGroup{ Node: rootNode, Generators: generators, }, nil }流程分三步以当前模块为根构造模块树NewModTree调用RollupGenerator沿树遍历仅保留匹配include模式的生成器节点将每个节点包装为Generator对象连同根节点一起组装成GeneratorGroup返回。匹配语义glob 通配 路径包含include中的每个 pattern 如何与生成器节点匹配定义在 core/modtree.go 的ModTreeNode.Match与ModTreePath.Glob中。先看Matchcore/modtree.go#L985-L1005func (node *ModTreeNode) Match(ctx context.Context, patterns []string) (bool, error) { if node.Parent nil { // The root node matches everything return true, nil } if len(patterns) 0 { return true, nil } for _, pattern : range patterns { if match, err : node.Path().Glob(ctx, pattern); err ! nil { return false, err } else if match { return true, nil } patternAsPath : NewModTreePath(pattern) if patternAsPath.Contains(ctx, node.Path()) { return true, nil } } return false, nil }匹配规则可以归纳为根节点永远匹配用于保留树根空include所有节点都匹配即不过滤pattern 命中任一 pattern 满足下面任一条即匹配glob 通配匹配将 pattern 与节点路径统一转换为 CLI 风格kebab-case并用/连接后通过doublestar.PathMatch支持*、**等通配符进行匹配路径包含匹配把 pattern 本身当作路径前缀若它是当前节点路径的祖先/前缀Contains也视为匹配。再看 glob 的实现core/modtree.go#L971-L983func (p ModTreePath) Glob(ctx context.Context, pattern string) (bool, error) { // Normalize both pattern and path to CLI case (kebab-case) for consistent matching slashPattern : strings.Join(NewModTreePath(pattern).CliCase(), /) slashPath : strings.Join(p.CliCase(), /) if match, err : doublestar.PathMatch(slashPattern, slashPath); err ! nil { return false, err } else if match { return true, nil } return false, nil }ModTreePath使用:作为路径分隔符见 core/modtree.go#L921-L925节点的命令路径示例为my-mod:generate这样的形式。匹配前pattern 和节点路径都会被CliCase()规范化为 kebab-case 并用/连接因此 pattern 书写时既可以用:分隔模块树路径风格也可以直接用/glob 风格引擎都会统一处理。Rollup 遍历RollupGeneratorcore/modtree.go#L895-L899是RollupNodes的薄封装专门挑选支持 generator 能力的节点// Walk the tree and return all generator nodes, with include and exclude filters applied. func (node *ModTreeNode) RollupGenerator(ctx context.Context, include []string, exclude []string) ([]*ModTreeNode, error) { return node.RollupNodes(ctx, supportsGenerator, include, exclude) }RollupNodescore/modtree.go#L850-L886负责真正的递归遍历与过滤在节点不匹配时记录调试信息并跳过。值得注意的是RollupGenerator的签名还预留了exclude参数当前传入nil意味着过滤机制在设计上同时支持 include/exclude 双向过滤ModuleGeneratorsOpts目前仅暴露了include一侧。GeneratorGroupinclude 过滤后的执行单元generators()返回的GeneratorGroup是一个惰性lazy客户端对象只有真正调用其执行方法时才会向引擎发起 GraphQL 查询。在 Go 引擎中GeneratorGroup的能力通过 core/schema/generators.go 中的generatorsSchema暴露给 GraphQLlist列出组内所有Generator及其详情core/schema/generators.go#L73run执行组内全部选中的生成器core/schema/generators.go#L85changes取回上次运行产生的变更集合多生成器间若冲突可指定onConflict策略core/schema/generators.go#L118-L134isEmpty判断所有生成器是否都没有产生变更core/schema/generators.go#L110-L116loadFailures返回收集生成器过程中被容忍的加载失败信息core/schema/generators.go#L77。组内每个GeneratorGo 侧定义见 core/generators.go#L20-L30持有自己的Node模块树节点、是否已完成标志、以及Changeset结果。它可以是常规生成器来自某个模块的 generator 函数通过node.RunGenerator执行合成生成器synthetic引擎内置的生成器由SyntheticGeneratorSpeccore/generators.go#L35-L41描述名称、路径、描述与 provider由引擎侧的 runner 执行。执行时GeneratorGroup.Run见 core/generators.go#L249-L287组内生成器通过 util/parallel 并行调度include过滤在构造组时就已经完成因此未被选中的生成器不会出现在执行队列中。使用示例include最常见的用途是在大型模块含大量生成器中只运行子集节省时间并聚焦变更。以 TypeScript 客户端为例import { connect } from dagger.io/dagger connect(async (client) { const module client.currentModule() // 运行模块中所有生成器 const all await module.generators().run() // 仅运行路径匹配 sdk:generate 的生成器 const filtered await module.generators({ include: [sdk:generate], }) await filtered.run() // 使用 glob 通配匹配 foo 开头的两层路径 const globbed await module.generators({ include: [foo:*], }) // 使用路径前缀包含匹配选择整个子树上所有生成器 const subtree await module.generators({ include: [docs], }) })Pattern 使用要点依据 core/modtree.go 的匹配实现不传include或传空数组时选中模块树上的全部生成器单个 pattern 可用:模块树路径分隔符或/书写最终都会归一化为 kebab-case 的/路径再做 glob 匹配支持*/**等 doublestar 通配语法pattern 若为某个生成器的路径前缀同样会命中该子树上的全部生成器生成器路径本质上是命令路径CommandPath如my-mod:generate书写 pattern 时以此为准。与其他 SDK 的对应关系ModuleGeneratorsOpts并非 TypeScript 独有——codegen 为每个 SDK 生成了对等的选项类型。以 Go SDK 生成的客户端为例sdk/typescript/runtime/internal/dagger/dagger.gen.go#L10751-L10760// ModuleGeneratorsOpts contains options for Module.Generators type ModuleGeneratorsOpts struct { // Only include generators matching the specified patterns Include []string json:include,omitempty } func (r *Module) Generators(opts ...ModuleGeneratorsOpts) *GeneratorGroup { ... }此外CurrentModuleGeneratorsOpts与WorkspaceGeneratorsOpts分别服务于CurrentModule.generators()与Workspace.generators()也声明了完全相同的include?: string[]语义见 sdk/typescript/src/api/client.gen.ts#L1032 与 sdk/typescript/src/api/client.gen.ts#L3235说明“按 pattern 过滤生成器”是该 API 家族的统一约定。测试与验证线索若要深入验证include过滤行为仓库中相关的测试用例集中在 core/integration/generators_sdk_settings_test.go 与 core/integration/generators_test.go它们覆盖了生成器收集、运行与冲突合并等场景模块树遍历与匹配逻辑另有 core/schema/generators.go 配套的单元测试可参考。运行集成测试前需要先确保本机 Dagger 引擎可启动参考 README.md 的安装与开发说明。总结ModuleGeneratorsOpts虽只包含一个include属性却是 Dagger 生成器generator体系入口处的关键筛选项它控制Module.generators()返回哪个GeneratorGroup进而决定哪些代码生成器会被并行执行、产生哪些Changeset。其匹配语义glob 通配 路径包含与模块树 Rollup 机制在引擎层有清晰的实现路径可参考 core/generators.go 与 core/modtree.go。在编写复杂模块时合理使用include能让生成器执行更加精准可控是提升开发效率的实用手段。【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考