ARTICLE DETAIL

资讯详情

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

dagger TypeScript SDK 的 JSONValue 类:JSON 编码解码与字段路径操作全解

dagger TypeScript SDK 的 JSONValue 类:JSON 编码解码与字段路径操作全解 dagger TypeScript SDK 的 JSONValue 类JSON 编码解码与字段路径操作全解【免费下载链接】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 模块中当模块函数需要接收、返回或传递任意 JSON 结构如配置对象、API 响应时官方 API 提供的JSONValue类是核心载体。本文基于 dagger 仓库中 v0.20 TypeScript API 参考文档 JSONValue.md结合 TypeScript SDK 生成源码、服务端 schema 实现 与 集成测试完整讲解JSONValue的构造方式、全部 13 个方法、参数默认值与底层执行机制帮助你在模块代码中正确完成 JSON 值的创建、解码、字段路径查询与修改。1. JSONValue 是什么JSONValue是dagger.io/dagger包中生成的客户端类继承自BaseClient用于表示一个“任意 JSON 编码的值”。它对应 dagger 引擎 schema 中的JSONValue对象类型。从源码结构看服务端的真实类型定义非常轻量——core/jsonvalue.go 中它只是一个 JSON 字节的状态容器并实现了dagql.PersistedObject接口因此可以作为 DAG 节点被持久化、跨会话/跨进程引用// JSONValue is a simple state carrier for JSON-encoded bytes type JSONValue struct { Data []byte }在 TypeScript 侧client.gen.ts 中的JSONValue类持有五个私有字段_id、_asBoolean、_asInteger、_asString、_contents分别缓存对应方法的结果避免重复发起引擎查询。文档同时给出了配套类型JSONValueIDJSONValue的唯一标识PromiseID的解析目标JSON品牌化的 JSON 字符串类型string { __JSON: never }保证传入的内容是 JSON 文本JSONValueContentsOptscontents()的选项对象含pretty是否美化输出与indent缩进前缀。构造函数仅供内部使用参考文档明确指出new JSONValue(ctx?, _id?, _asBoolean?, _asInteger?, _asString?, _contents?)的构造函数“仅用于内部请勿直接实例化”。这是 dagger 生成客户端的统一约定——所有类对象都应通过查询构造器如client.json()或其他方法链式返回得到构造函数主要用于内部按 ID 重建对象例如asArray()解析结果后按元素 ID 重建子对象见 client.gen.ts。2. 如何创建一个 JSONValue2.1 顶层查询构造器json()服务端在 core/schema/jsonvalue.go 中安装了顶层字段json用于初始化一个空的JSONValue内容为 JSONnulldagql.Fields[*core.Query]{ dagql.Func(json, s.newJSONValue). Doc(Initialize a JSON value), }.Install(srv)因此 TypeScript 中的入口是client.json()。集成测试 core/integration/jsonvalue_test.go 展示了从零构建一个对象的标准写法import { dag } from dagger.io/dagger async function main() { // 从空 JSONValue 开始逐步添加字段 const obj dag.json().withField([name], dag.json().newString(Bob)) const withEmail obj.withField([profile, email], dag.json().newString(bobexample.com)) const name await withEmail.field([name]).asString() console.log(name) // Bob }2.2 标量编码newBoolean/newInteger/newString这三个方法把标量值“编码为 JSON”并返回新的JSONValue同步返回查询在 await 结果时才执行方法参数返回服务端实现newBoolean(value: boolean)新的布尔值JSONValuejson.Marshal(bool)见 newBooleannewInteger(value: number)新的整数值JSONValuejson.Marshal(int)见 newIntegernewString(value: string)新的字符串值JSONValuejson.Marshal(string)会自动转义换行、引号等特殊字符测试用例覆盖了边界输入整数支持负数与零TestInteger字符串支持空串与含\n、\t、的特殊字符TestString均能无损往返。2.3 从 JSON 文本创建withContents(contents: JSON)当内容来自现成的 JSON 文本数组、嵌套对象等时用withContents一次性解码const arr dag.json().withContents([1, hello, true, null])注意服务端 withContents 会先校验内容是否合法 JSON非法输入会直接报错invalid JSON: ...这是一个早失败fail-fast设计。3. 解码与读取as 系列方法与contents()3.1 类型解码方法方法返回说明asArray()PromiseJSONValue[]将 JSON 数组解码为JSONValue元素数组每个元素可继续链式调用asBoolean()Promiseboolean解码布尔值asInteger()Promisenumber解码整数asString()Promisestring解码字符串这些方法在服务端都是对Data字节做json.Unmarshal的“解码”操作类型不匹配时会抛出明确错误例如 asBoolean 在值不是布尔时返回value is not a booleanasArray 在非数组时返回value is not an array。asArray()的典型用法是逐项解码混合类型数组来自 TestArray 的模式const arr dag.json().withContents([1, hello, true, null]) const items await arr.asArray() const first await items[0].asInteger() // 1 const second await items[1].asString() // hello const third await items[2].asBoolean() // true从源码结构看asArray()内部对每个元素先取id再按JSONValue类型 ID 重建客户端对象client.gen.ts所以返回的元素是完整的JSONValue可以继续field()、withField()等所有操作。3.2contents(opts?): PromiseJSONcontents()返回该值编码后的 JSON 文本接受可选的JSONValueContentsOptspretty?: boolean—— 是否美化输出indent?: string—— 缩进前缀。从 contents 实现 可以确认默认值pretty默认false返回原始压缩字节indent默认两个空格 。开启pretty后服务端会走json.MarshalIndent重新格式化const bytes await obj.contents() // 紧凑输出 const pretty await obj.contents({ pretty: true }) // 换行 两空格缩进 const pretty2 await obj.contents({ pretty: true, indent: \t })TestBytes 验证了美化输出确实包含换行符与缩进空格。3.3id(): PromiseJSONValueID返回该JSONValue在引擎中的唯一标识。ID 可用于在函数间以JSONValueID参数传递大对象而不序列化内容本身——这与仓库中 ids.go 的 ID 机制一致也是withField的value参数在服务端以JSONValueID接收的原因见下文 4.3 节。4. 字段路径操作field/fields/withFieldJSONValue最有价值的部分是按“字段名数组”表达的嵌套路径操作路径统一编码为string[]。4.1fields(): Promisestring[]列出顶层对象的键名列表来自 fields 实现const obj dag.json().withContents({name: Alice, age: 25, active: true}) const keys await obj.fields() // [name, age, active]顺序不保证注意实现要求根值是对象非对象会报value is not an object且字段顺序来自 Go map 遍历结果不保序。4.2field(path: string[]): JSONValue按路径查找字段并返回其值注意同步返回JSONValue实际取值在其as*方法上 await。field 实现 逐段下钻任何一段要求当前节点必须是对象、且键必须存在否则报cant lookup field ... in non-object value或no such field: ...。TestNestedPaths 给出了多级嵌套访问的完整范例const obj dag.json().withContents( {user: {name: John, age: 30, profile: {email: johnexample.com, active: true}}} ) const name await obj.field([user, name]).asString() // John const age await obj.field([user, age]).asInteger() // 30 const email await obj.field([user, profile, email]).asString() const ok await obj.field([user, profile, active]).asBoolean()一个容易踩的边界空路径field([])后取值会报错TestEmptyPathError写路径逻辑时应保证path.length 0。4.3withField(path: string[], value: JSONValue): JSONValue在给定路径处设置新值返回新的JSONValue符合 dagger 不可变对象的一贯设计。withField 实现 有几个值得注意的行为value以 ID 传递服务端参数类型为JSONValueID即传入的JSONValue会在 DAG 中持久化后按 ID 加载适合传递任意复杂子树自动创建中间对象路径中间的键若不存在或非对象会被替换/创建为对象再下钻因此withField([profile, email], ...)可以从空对象直接建出profile.email根值非对象时宽容处理若当前值是null等非对象会以新对象为根重建。TestWithField 与 TestBytes 组合验证了“从空对象逐级拼装并读回”的完整闭环。5.with(arg)不断链的复用辅助// 文档原文Call the provided function with current JSONValue. // This is useful for reusability and readability by not breaking the calling chain. value.with(jv jv.withField([extra], dag.json().newInteger(1)))with()接收一个(param: JSONValue) JSONValue的函数并立即以当前对象调用client.gen.ts适合把可复用的转换逻辑封装进工具函数而不打断调用链。6. 方法总表分类方法签名说明构造构造函数new JSONValue(ctx?, _id?, _asBoolean?, _asInteger?, _asString?, _contents?)仅内部使用编码newBoolean/newInteger/newString(value) JSONValue标量编码为 JSON编码withContents(contents: JSON) JSONValue从 JSON 文本解码为新值非法 JSON 早失败修改withField(path: string[], value: JSONValue) JSONValue按路径设值自动创建中间对象解码asArray/asBoolean/asInteger/asString() Promise...类型解码类型不符时报错读取contents(opts?: { pretty?, indent? }) PromiseJSON导出 JSON 文本pretty默认 falseindent默认 读取field(path: string[]) JSONValue按路径取值路径不存在即报错读取fields() Promisestring[]顶层键名列表仅对象元信息id() PromiseJSONValueID引擎内唯一标识辅助with((jv: JSONValue) JSONValue) JSONValue函数式断链辅助7. 跨模块边界使用 JSONValueJSONValue的一个核心设计目标是“穿越模块 API 边界”。集成测试文件头注释明确说明其覆盖范围core/integration/jsonvalue_test.goThese tests cover JSON values crossing the module API boundary. They verify scalar, object, and array values passed between callers and module functions.结合 core/jsonvalue.go 中实现的EncodePersistedObject/DecodePersistedObject可以推断JSONValue在模块间传递时以 ID 引用 持久化负载的方式流转调用方拿到的是同一份 JSON 的 DAG 节点而非重新序列化一份拷贝。因此把配置对象作为JSONValue参数在模块函数间传递是类型安全且可缓存的。8. 小结JSONValue用一组极简但闭环的方法withContents/new*编码、as*/contents解码、field/fields/withField路径操作覆盖了在 dagger 工作流中处理任意 JSON 数据的常见需求。使用时记住三点不要直接new JSONValue(...)用client.json()起步所有with*/new*/field返回的都是惰性新对象只有await的解码方法才真正触达引擎类型不匹配对对象调asArray、对数组调fields、不存在的field路径都会在服务端报明确错误属于早失败设计便于在 CI 中快速定位问题。延伸阅读JSONValue 参考文档原文、TypeScript SDK 包、JSON 集成测试。【免费下载链接】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),仅供参考
返回列表