@ lient- compose/ 编码源
产生岛的道具类型 从岛的每个堆 清单,所以作曲家和 每个应用程序都通过建筑而不是手来商定每个岛屿的道具.
npx @client-compose/codegen client-compose.codegen.json # write
npx @client-compose/codegen client-compose.codegen.json --check # CI: exit 1 if out of date
npx @client-compose/codegen compat client-compose.codegen.json --base origin/main
# CI: exit 1 on breaking changes
npx @client-compose/codegen strings client-compose.codegen.json # CI: check the strings catalog
转到输出格式化 gofmt 如果你的路径。 (在此重播中, 运行 node codegen/cli.ts …
直接使用源。 )
安装
有节点20+: npx @client-compose/codegen …,或添加 @client-compose/codegen 是一个非常依赖.
没有节点 (去项目):单独下载 client-compose-codegen
用于您平台的可执行文件
代码释放数字 : linux-x64, (中文(简体) ),
linux-arm64, (中文(简体) ), darwin-x64, (中文(简体) ), darwin-arm64 或者说 windows-x64,带有 SHA256SUMS 要校验的文件
这个 例如,通过GitHub CLI:
gh release download "@client-compose/[email protected]" -R client-compose/client-compose \
-p "client-compose-codegen-darwin-arm64" -p SHA256SUMS
shasum -a 256 --check --ignore-missing SHA256SUMS
chmod +x client-compose-codegen-darwin-arm64 && mv client-compose-codegen-darwin-arm64 /usr/local/bin/client-compose-codegen
二进制与 npm 包的参数相同 。 他们没有公证,所以在macOS一个副本
通过浏览器需要下载 xattr -d com.apple.quarantine <file> 在它运行之前
(负载 gh 或者说 curl 别.
配置
client-compose.codegen.json (路径相对于此文件; 仅配置您使用的目标):
{
"manifests": "islands",
"actions": "actions",
"targets": {
"go": { "out": "composer-go/islands_gen.go", "package": "main" },
"typescript": { "out": "web/islands.generated.ts", "protocolImport": "@client-compose/protocol" }
}
}
actions 可选:为每个目标生成的行动清单(第5段)。 A 类
配置可能只包含 actions。 。 。 .
对于实体(第2.1项),添加 "entities": "entities",一个实体列表。 见
实体。 。 。 .
对于几种显示共享类型(第2.2段),添加 "types": "types",类型目录
名单 见 共享类型。 。 。 .
对于字符串(第4.7段),添加 "appStrings": "app-strings.json" (应用字符串显示),
"screenStrings": "screen-strings.json" (每个屏幕自己的字符串,用于Go和TypeScript作曲),
"catalog": "strings" (目录) <locale>.json 如果不是作曲家服务的文件)
en, (中文(简体) ), "defaultLocale"。见 字符串。 。 。 .
在Go项目中,a //go:generate client-compose-codegen <config> (或 npx @client-compose/codegen <config>(行让) go generate 运行它
(见 examples/todo/composer-go/main.go) (中文(简体) ).
你得到的东西
对于 profile-header v2, 每个目标生成 a ProfileHeaderV2 了解自身类型
岛屿类型和版本,所以注册不能给岛屿取名错误:
| 堆栈 | 已生成 | 用作 |
|---|---|---|
| 走开 | struct + 键 IslandType() 编号 : IslandVersion() 方法 | cc.Define(func(ctx, r) (ProfileHeaderV2, error) { … }) |
| 类型脚本 | interface +描述符 const 名称相同 | registry.register(ProfileHeaderV2, (props) => …), (中文(简体) ), island(ProfileHeaderV2, resolve) |
供采取行动 follow-user v1( 第5.1节) :
| 堆栈 | 已生成 | 用作 |
|---|---|---|
| 走开 | FollowUserV1Input (与其行动、版本、输入计划和结果类型挂钩), FollowUserV1Result,并且每个声明错误都有一个错误类型,例如:. FollowUserV1Blocked | cc.DefineAction(func(ctx, call, in FollowUserV1Input) (FollowUserV1Result, cc.Effects, error) { … })返回时 FollowUserV1Blocked{} 作为错误 |
| 类型脚本 | FollowUserV1Input, (中文(简体) ), FollowUserV1Result,则 FollowUserV1Error 工会,以及 FollowUserV1 描述符 | action(FollowUserV1, perform) 在作曲家, callAction(…, FollowUserV1, input) 或者说 useAction(FollowUserV1) 在应用程序中 |
实体
一个实体命名一些岛屿, 所以一个动作可以说它有什么变化
(第2.1和5.3节)。 每一个都显示在 entities 目录和岛道具标记对象
显示一个与 entity数字 :
// entities/todo.json
{ "entity": "todo", "id": "id", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "done": { "type": "boolean" } } }
// in an island's props
"todos": { "type": "array", "items": { "type": "object", "entity": "todo", "required": ["id", "title"], "properties": { … } } }
代码源检查每个标记对象: 它有实体的ID, 需要, 以及每个实体的
它显示的属性有实体的设置。 它可能有自己的属性. compat
将标出或未标出对象视为断裂变化.
| 堆栈 | 已生成 | 用作 |
|---|---|---|
| 走开 | TodoEntity每一个财产,除了id,每一个可选的; IslandEntities() 在拥有实体的岛屿上 | cc.Set("3", TodoEntity{Done: &done}), (中文(简体) ), cc.Delete[TodoEntity]("3") |
| 类型脚本 | TodoEntity 及其描述者; entities 岛上的描述 | changed(TodoEntity, "3", { done: true }), (中文(简体) ), deleted(TodoEntity, "3"); 客户端使用描述符应用更改' entities |
共享类型
当若干岛屿、行动或实体拥有相同形状时(图像、个人徽章、a)
,定义一次并参考一次。 每一个都显示在 types 目录:对象,或
字符串语句,与其它语句相同。 类型可能指另一个类型,但不指
{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}我们自己来.
// types/image.json
{ "type": "image", "description": "A picture.", "schema": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri" }, "width": { "type": "integer" } } } }
// anywhere a schema can be: an island's props, an action's input, result or error details, an
// entity's properties, or another shared type
"cover": { "$ref": "image", "description": "Shown at the top." }
仅说明( E)description, (中文(简体) ), title, (中文(简体) ), $comment, (中文(简体) ), examples可以坐在旁边 $ref类型
生成一次,以其自己的名字(Image,有巢类类似 ImageFocus和每个
引用使用它,所以一个帮助者或组件可以在它出现的地方带走它. 到处都有计划
嵌入或比较(作曲者用来验证的动作输入方案,实体检查),
参考书目被写出,所以参考书目完全指现存类型的写作会是什么.
compat 判断每个岛屿改变为共同类型,并根据它们的规则采取行动:
给一个共享的enum添加一个值 是打破它使用的地方.
代码源生成 Go 和 TypeScript 。 斯威夫特和克特林的目标 与他们的客户 需要一个维护者回来.
字符串
每个应用节目的词出自作曲家(spec §4.7). 岛屿表宣布
由按键组成的字符串,每个参数都填入,以及 counted 对于一个言语依赖
count数字 :
"strings": {
"heading": { "description": "Over the list." },
"greeting": { "params": ["name"] },
"articleCount": { "params": ["count"], "counted": true }
}
App string express 声明属于无岛的词(一个占地者"Loading","Loading"),
a 验证信息),格式相同: { "strings": { … } }。每个目标生成一个类型
其成员是弦:为无正框者提供正文,为具有下列功能者提供功能:
| 堆栈 | 已生成 | 用作 |
|---|---|---|
| 类型脚本 | ArticleListV1Strings和描述器的 strings· ; AppStrings | props.t.articleCount({ count }) 在登记的组成部分中; useAppStrings(AppStrings).retry |
单词是目录,每个语言一个文件,例如. strings/pl.json数字 :
{
"app": { "retry": "Spróbuj ponownie" },
"islands": {
"article-list@1": {
"heading": "Najnowsze",
"greeting": "Cześć {name}",
"articleCount": { "#0": "Brak artykułów", "#one": "{count} artykuł", "#few": "{count} artykuły", "#*": "{count} artykułów" }
}
}
}
屏幕的自有弦是其作曲家使用自己的词,例如其元标题. 屏幕
字符串显示通过屏幕标识来宣告, { "screens": { "author": { "title": { "params": ["author"] } } } },目录里有 screens开始
AuthorScreenStringsFor(r).Title(name); 类型脚本, lc.strings(AuthorScreenStrings).title({ author })。 。 。 .
已计数字符串的变体键入 #<number>, (中文(简体) ), #<category> (CLDR's zero, (中文(简体) ), one, (中文(简体) ), two, (中文(简体) ),
few, (中文(简体) ), many, (中文(简体) ), other)或(或) #*,按此顺序选择. strings 检查目录与
显示:默认语言必须拥有每个字符串;缺少一个字符串的则得到警告
回到默认的。 未知的钥匙和岛屿,变体 #*,字符串上的变体
这不算,和 {slots} 而不是参数是错误.
支持的计划子集
化身使用JSON Schema的一个特意小分集. 外面的任何东西都会被拒绝 错误,所以一个表 永远不能指不同语言中不同的事物.
| 司马 | 走开 | 类型脚本 |
|---|---|---|
string | string | string |
string, (中文(简体) ), format: uri | string | string |
string, (中文(简体) ), enum: [...] | 名称 string 类型 + conss | 字符串结合 |
integer | int | number |
integer, (中文(简体) ), format: int64 | int64 | number |
number | float64 | number |
boolean | bool | boolean |
array 与 items | []T | T[] |
object 与 properties | 名称结构 | 命名接口 |
object 与 additionalProperties | map[string]T | Record<string, T> |
没有在 required | a. 指针,或为零; omitempty | prop?: |
共享类型( E){ "$ref": "image" })成为它自己命名的类型:见 共享类型。 。 。 .
还允许: description (成为医生的评论), title (命名为巢型), $comment, (中文(简体) ),
examples。不支持 : $ref 除了同一类人的名字之外, oneOf编号 :anyOf编号 :allOf类型工会, null, (中文(简体) ), pattern, (中文(简体) ),
minimum 和其他校验关键词,格式 uri, (中文(简体) ), int32 财务报告和审定财务报表 int64。 。 。 .
取名问. 巢穴类型以其属性来命名(author → Author),或之后
title 如果设置。 没有标题的矩阵项目获得一个 Item 后缀和地图值a Value 后缀.
Go 和 TypeScript 将它们平整(PostGridV1Post) (中文(简体) ). 共享类型以自身命名
(单位:千美元)image → Image)),其名称不可能是相形见绌的生成. 地产名称为骆驼卡塞德(去:PascalCased 有标准
初始化,例如:. avatarUrl → AvatarURL),保留了原JSON密钥.
清单的兼容性规则
Apps和作曲家独立部署,而旧的App版本长期被安装. 所以,一个岛屿版本的改变必须保持 两者 工作方向: 旧应用程序解码 新作曲家的有效载荷,以及新作曲家旧作曲(apps可先发作)的解码. 客户端跳过 道具不解码的岛屿(secret §4.4),所以一次突破性的改变悄悄地隐藏了该岛.
| 一岛版内的变化 | 允许? |
|---|---|
| 添加可选属性 | ✅ |
| 删除可选属性 | qq 旧应用程序已经处理它 缺席 |
变动 description 或者说 title,重新排列enum值 | 页:1 title 更改重命名生成的类型, 您的编译器将指出这些类型) |
| 添加所需的属性 | 新应用程序拒绝尚未发送的作曲家的有效载荷 |
| 删除所需的属性 | 旧的应用程序需要它 |
| 选择或要求财产 | ❌ |
更改类型, format,或整数大小 | ❌ |
| 添加或去除 enum 值 | qq应用无法解码他们不知道的值 |
| 删除岛屿版本 | {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}但是只支持这个版本的应用程序 {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}停止接收这个岛 |
在 a 中进行分解更改 新岛版 (新设) profile-header.v3.json和保持旧的
已经发布的应用程序版本 .
在一个岛屿版的字符串和应用程序字符串可以添加,它们的描述和 词变了 删除一个, 改变其参数, 或使其计数或不计数, 正在打破: 已释放 应用程序仍然显示, 与他们建造的参数.
行动遵循同样的规则(第5.1节)。 已发布应用程序继续发送旧输入和解码
结果和错误细节,所以 input, (中文(简体) ), result 每个错误 details 遵循上表.
由于客户端将未知代码视为通用代码,可添加或删除已声明的错误代码
失败。 给出已有错误 details或者把他们带走 是破碎的 删除动作
版本只警告: 应用程序仍然称它得到 unsupported_action_version。 。 。 .
在CI里检查
compat 与先前的状态相比
client-compose-codegen compat client-compose.codegen.json --base origin/main # a git ref
client-compose-codegen compat client-compose.codegen.json --base-dir ./old-islands
✖ profile-header v2 · props.badge: became required: new apps would reject payloads from a composer that omits it
1 breaking change(s) in client-compose.codegen.json compared with origin/main.
Put them in a new island version instead (profile-header v3), and keep the old version for apps already released.
在 GitHub 动作中,请查看 fetch-depth: 0 通过 --base "origin/$GITHUB_BASE_REF" 牵出
请求.
测试
codegen/test/fixtures/islands 覆盖每个支持
特性。 它所生成的输出通过Go和TypeScript的测试被编译并解码.