Dagger TypeScript SDK DirectorySearchOpts 完全指南:Directory.search 搜索选项详解
2026/9/18 6:02:33 网站建设 项目流程

Dagger TypeScript SDK DirectorySearchOpts 完全指南:Directory.search 搜索选项详解

【免费下载链接】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 的Directory.search()方法让你在容器化构建的目录中,用正则表达式或字面量文本进行内容检索,并返回带行号、偏移量与子匹配位置的结构化结果。本文以 TypeScript SDK 参考文档中的DirectorySearchOpts类型别名(docs/versioned_docs/version-0.21/reference/typescript/api/client.gen/type-aliases/DirectorySearchOpts.md)为骨架,结合底层实现与集成测试,逐一讲解全部 11 个选项的语义、默认值、底层 ripgrep 映射以及实战用法。读完本文,你将能精准控制 Dagger 目录搜索的行为边界,写出高效、可预测的检索代码。

DirectorySearchOpts 是什么

DirectorySearchOpts是 Dagger TypeScript SDK 为Directory.search(opts?)方法定义的可选参数对象类型,其定义位于 sdk/typescript/src/api/client.gen.ts,由代码生成器从 Dagger GraphQL API 自动生成,属于client.gen这一层「自动生成客户端」的一部分。

在类型层面,它是这样一个结构:

export type DirectorySearchOpts = { paths?: string[] globs?: string[] pattern: string // 唯一必填项 literal?: boolean multiline?: boolean dotall?: boolean insensitive?: boolean skipIgnored?: boolean skipHidden?: boolean filesOnly?: boolean limit?: number }

其中只有pattern是必填字段,其余均为可选。从 GraphQL 语义看,这些选项对应Directory.search的一个参数对象;对应的search方法在 SDK 中签名如下(sdk/typescript/src/api/client.gen.ts):

search = async (opts?: DirectorySearchOpts): Promise<SearchResult[]> => { ... }

调用后返回SearchResult[],每个SearchResult包含filePathlineNumberabsoluteOffsetmatchedLinessubmatches字段,对应的服务端对象定义在 core/search.go。

必填参数 pattern:要匹配的文本

pattern是唯一必填选项,类型为string,表示要匹配的文本。它的语义受literal选项影响:

  • 默认情况下pattern被当作正则表达式解释;
  • literal: true时,被当作字面量字符串,不进行正则解析。

在底层实现中,pattern 最终以--regexp=<pattern>的形式传给 ripgrep(core/search.go)。值得注意的是,Dagger 使用的正则语法是Rust regex 语法——在 GraphQL Schema 中明确注明:「Uses Rust regex syntax; escape literal ., [, ], {, }, | with backslashes」(core/schema/directory.go)。也就是说:

  • 想匹配字面量的.[]{}|等特殊字符时,需要用反斜杠转义,例如pattern: "foo\\.bar"
  • Rust regex 不支持回溯(backreference)等 PCRE 特性,编写复杂正则时需注意这一点;
  • 更稳妥的做法是使用literal: true直接按字面量匹配,例如在WithReplaced的底层实现中,替换前的查找就强制使用Literal: true(core/file.go)。

控制匹配范围:paths 与 globs

这两个选项负责限定「在哪些文件里搜」,是控制搜索结果规模的第一道闸门。

paths:目录或文件路径列表

paths?: string[],用于指定要搜索的目录或文件路径,与「在哪个目录对象上调用 search」共同决定搜索范围。在服务端实现中,这些路径会经过严格的路径穿越防护处理(core/directory.go):

  • 绝对路径会被转换为相对于当前目录的路径(去掉开头的/);
  • 路径会被filepath.Clean规范化,清理.././等片段;
  • 规范化后若路径试图逃出当前目录(!filepath.IsLocal),会直接报错path cannot escape directory

安全校验通过后,各路径经containerdfs.RootPath解析为实际挂载根下的相对路径,追加在--之后传给 ripgrep(core/directory.go),从而把搜索精确限制在这些文件或子目录内。

globs:glob 模式列表

globs?: string[],用于按文件名模式过滤,例如"*.md"只匹配 Markdown 文件。每个 glob 会被转换为 ripgrep 的--glob=<glob>参数(core/directory.go),支持*?**等通配符。需要注意:

  • globs 与 paths 是叠加关系:先通过 paths 限定搜索起点,再用 globs 过滤具体文件类型;
  • glob 语义遵循 ripgrep 的规则(基于 gitignore 风格),例如"!*.min.js"可用于排除。

集成测试中有专门的 globs 用例(core/integration/directory_test.go):在同时包含main.gotest.goREADME.md的目录里,通过 globs 精确圈定要搜索的文件集。

正则行为控制:literal、multiline 与 dotall

这三个选项直接映射到 ripgrep 的匹配引擎行为,理解它们的组合关系是写出正确搜索的关键。

literal:字面量匹配

literal?: boolean,默认false。当为true时,pattern按字面字符串匹配,底层映射为 ripgrep 的--fixed-strings(core/search.go)。典型场景:搜索代码中恰好含正则元字符的文本(如a[i]foo{2}),或pattern来自用户输入、不可控时,用字面量模式既安全又符合直觉。

multiline:跨行匹配

multiline?: boolean,默认false。开启后允许正则跨越多行进行匹配,底层映射为--multiline(core/search.go)。典型用例是在多行代码结构中定位目标,例如集成测试中搜索:= "Alice"\n\tage这一跨行赋值序列(core/integration/directory_test.go)。

dotall:点号匹配换行符

dotall?: boolean,默认false。它仅在 multiline 模式下有意义:开启后允许正则中的.匹配换行符,底层映射为--multiline-dotall(core/search.go)。组合示例:multiline: true, dotall: true时,.*可以跨越任意字符(包括换行)进行贪婪匹配,例如测试中的:= ".*"\n\s+age模式(core/integration/directory_test.go)。

三者关系总结如下表:

选项默认值底层 ripgrep 参数作用
literalfalse--fixed-stringspattern 按字面量匹配
multilinefalse--multiline允许跨行匹配
dotallfalse--multiline-dotallmultiline 下.可匹配换行

匹配策略:insensitive、filesOnly 与 limit

insensitive:大小写不敏感

insensitive?: boolean,默认false。开启后忽略大小写匹配,底层映射为--ignore-case(core/search.go)。集成测试验证:对内容为Hello\nhello\nHELLO的文件执行search("hello", { insensitive: true }),三条记录全部命中(core/integration/directory_test.go)。

filesOnly:只返回文件名

filesOnly?: boolean,默认false。开启后只返回命中的文件路径,不返回行号、行内容与子匹配,底层映射为--files-with-matches(core/search.go),并切换到「逐行读路径」的结果解析分支(core/search.go),每个结果只有filePath有意义。适合「判断某个文件中是否存在目标文本」的快速探测场景。集成测试确认:匹配World时返回file1.txtsubdir/file3.txt,而matchedLines为空(core/integration/directory_test.go)。

limit:结果数量上限

limit?: number,默认不限。限制返回结果的最大条数。注意其实现方式很特别:它不通过 ripgrep 参数实现——因为 rg 只提供按文件限制结果数的参数,无法直接限制总结果数——而是在解析输出流的过程中,当已收集的结果数达到limit时立即停止解析(core/search.go)。这意味着限制在「结果解析层」生效,底层仍会跑完整个搜索。集成测试验证Limit: 3时只返回 3 条结果(core/integration/directory_test.go)。

文件过滤:skipHidden 与 skipIgnored

skipHidden:跳过隐藏文件

skipHidden?: boolean,默认false。为true时跳过以.开头的隐藏文件(如.env.gitignore自身、.github目录)。其映射逻辑与直觉相反但很实用:只有当skipHiddenfalse时,才会追加--hidden(core/search.go)。这是因为 ripgrep 默认会跳过隐藏文件,而 Dagger 默认要「连隐藏文件一起搜」,于是反过来用--hidden关闭 rg 的默认隐藏行为。

skipIgnored:尊重忽略规则

skipIgnored?: boolean,默认false。为true时尊重.gitignore.ignore.rgignore等忽略规则文件;为false(默认)时忽略这些规则,搜索全部文件。映射逻辑与 skipHidden 对称:默认追加--no-ignore(core/search.go)。集成测试用三种场景验证了这一行为(core/integration/directory_test.go):

  • 默认(skipIgnored: false):tracked.txtignored.logbuild/output.bin全部命中;
  • skipIgnored: true且存在.gitignore:仅tracked.txt命中;
  • skipIgnored: true且存在.rgignore:同样仅tracked.txt命中。

底层实现:每个选项如何变成 ripgrep 参数

DirectorySearchOpts在服务端对应core.SearchOpts结构体(core/search.go),两者字段一一对应。所有布尔选项的默认值都是falselimit为可空指针。将 TypeScript 选项翻译为 GraphQL 参数后,服务端通过RipgrepArgs()方法完成到 ripgrep CLI 参数的最终映射(core/search.go),完整对应关系如下:

选项映射逻辑
literaltrue--fixed-strings
multilinetrue--multiline
dotalltrue--multiline-dotall
insensitivetrue--ignore-case
skipIgnoredfalse(默认)→--no-ignore
skipHiddenfalse(默认)→--hidden
filesOnlytrue--files-with-matchesfalse--json
limit不传参,在结果解析时截断
pattern恒为--regexp=<pattern>
固定行为恒追加--no-follow,禁止跟随符号链接(core/search.go)

搜索执行流程是:Directory.Search挂载目录快照 → 解析出实际根路径 → 组装rg命令(exec.Command("rg", rgArgs...),工作目录设为解析后的目录)→ 调用RunRipgrep解析 JSON 流输出(core/directory.go)。结果解析时逐条读取 ripgrep 的 JSON 输出,组装SearchResult(文件路径、行号、字节偏移、命中的行文本与子匹配区间),并对非 UTF-8 内容做跳过处理(core/search.go)。

实战示例:组合使用各选项

以下是一个综合使用DirectorySearchOpts的 TypeScript 示例,演示如何在一个源码目录中做「大小写不敏感、排除隐藏文件与忽略规则、限定 Go 文件、只返回文件名、最多 20 条」的搜索:

import { connect } from "@dagger.io/dagger" await connect(async (client) => { const src = client.host().directory("./repo") const results = await src.search("TODO|FIXME", { paths: ["src"], // 只搜 src 子目录 globs: ["*.go"], // 只搜 Go 文件 insensitive: true, // 忽略大小写 skipHidden: true, // 跳过隐藏文件 skipIgnored: true, // 尊重 .gitignore 等规则 filesOnly: true, // 只返回文件名 limit: 20, // 最多 20 条结果 }) for (const r of results) { console.log(await r.filePath()) } })

如果需要带上下文的完整检索,去掉filesOnly即可获得SearchResult上的lineNumbermatchedLinessubmatches(子匹配的精确文本与起止偏移),满足代码检查、文档审计等更细粒度的需求。

相关 API 与测试入口

  • 类型定义与 search 方法:sdk/typescript/src/api/client.gen.ts、sdk/typescript/src/api/client.gen.ts
  • 服务端选项与 ripgrep 映射:core/search.go
  • 目录搜索实现(含路径防护):core/directory.go
  • 文件级搜索(File.search复用同一套选项):core/file.go
  • GraphQL 层参数声明:core/schema/directory.go
  • 集成测试(filesOnly / limit / multiline / insensitive / skipIgnored / globs 等全场景):core/integration/directory_test.go

需要说明的是,Dagger 还提供了功能相近但选项略有差异的FileSearchOptsWorkspaceSearchOpts(均在 sdk/typescript/src/api/client.gen.ts),分别服务于单文件搜索与工作区聚合搜索,使用时可对照各自的类型定义。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询