


开发一个让多种编程语言共用同一套API的框架
在开发从一份代码为多种语言生成包的框架时使用。规定进程间的JSON通信、可导出的类型、代码生成,以及检查各语言行为是否一致的测试。
要使用这个AI规则
## 让每种语言保持相同的行为和向后兼容
跨语言框架必须针对在每种受支持语言中都易于理解且行为等价的设计进行优化,而不是追求实现语言所具备的每一种惯用写法。
### 核心不变量
- 保持程序集格式、运行时协议和公共 API 的向后兼容性。
- 要求所有受支持的目标语言具备等价的可观察行为。
- 生成遵循各目标语言常规命名、打包和类型约定的代码。
- 只接受能够在每种目标语言中忠实表示的源语言特性。
- 相比目标语言特有的性能捷径,优先保证正确性和互操作性。
### 包边界
- 将协议内核、宿主运行时、模式定义、代码生成器、反射工具、兼容性检查和测试夹具彼此分离。
- 将构建实用工具和合规报告置于运行时包之外。
- 将每种语言的运行时和可选集成都作为独立负责的包。
- 将共享夹具放在所有编译器、生成器和运行时测试都能使用同一组行为用例的位置。
- 通过明确的版本化依赖连接在不同代码仓库中维护的组件。
## 在内核进程中运行代码,并通过JSON与各宿主语言通信
当宿主语言无法直接执行实现语言时,采用双端运行时模型。宿主进程通过标准输入和标准输出上的 JSON 消息与内核进程通信,而所有实现语言代码都只在内核中执行。
### 进程边界
- 为每个请求提供明确的操作判别字段。
- 使用不同的协议操作分别处理程序集加载、对象生命周期、方法调用、属性访问、异步工作、统计信息和回调。
- 仅当宿主运行时无法保留核心进程所需的文件描述符时,才使用额外的包装进程。
- 将诊断输出保留在错误流中,以免其破坏协议流。
### 回调顺序
当实现语言代码到达由宿主语言重写的方法或属性时:
1. 内核发送回调请求,而不是原始响应。
2. 宿主执行重写逻辑,并返回包含结果或失败信息的完成消息。
3. 内核恢复原始操作并返回其实际响应。
### 协议演进
- 将请求名称、字段含义、响应顺序和回调次序视为兼容性契约。
- 协议发生变化时,同时更新每个宿主运行时。
- 在更改消息结构或生命周期规则之前添加兼容性测试。
## 决定跨语言传值时是复制还是按引用传递
为每一类可移植值定义线上表示,并明确呈现所有权语义。按值复制跨越边界的值不得与仍由内核拥有的对象混淆。
### 线上表示
- 使用布尔值、数字和字符串各自的 JSON 表示按值发送它们。
- 按值发送列表和映射;需要将其与其他对象区分时,使用带有明确标签的封装。
- 使用完全限定的成员标识符对枚举进行编码。
- 使用带标签且无歧义的时间戳表示对日期进行编码。
- 使用完全限定的类型和字段数据对纯数据结构进行编码。
- 使用稳定的对象标识符按引用对类实例进行编码。
### 边界规则
- 在不同语言之间保持 UTF-8 字符串、浮点行为、可空性和集合复制语义。
- 一旦使用方依赖带标签的线上键,就保持这些键稳定。
- 当协议负责远程生命周期管理时,显式释放对象引用。
- 通过每个宿主运行时测试往返转换,而不是只测试实现语言一侧。
## 只导出每种语言都能表示的类型
对从模块主入口导出的声明施加可移植性限制,同时允许内部实现代码使用更广泛的语言特性。
### 可移植 API 表面
- 仅在每种目标语言都有可靠表示时,才支持基本类型、列表、映射、枚举、日期、类、接口、数据结构、Promise 和不透明值。
- 通过明确的命名规则或模式规则区分行为接口与纯数据结构。
- 要求纯数据结构仅包含只读属性且不包含方法。
- 仅允许在每种目标语言都能一致公开的位置使用 Promise,例如方法返回类型。
- 当静态类型目标无法恢复更精确的类型时,将不透明值视为隐式可空。
- 类按引用传递,值式结构按副本传递。
### 限制
- 拒绝不受支持的导出构造,例如元组、无值类型、任意精度整数、符号和方法重载。
- 要求重写方法保持完全兼容的签名;不得依赖协变返回类型或逆变参数。
- 当联合类型在静态类型目标中会退化为无类型对象时,应避免使用它。
- 不允许行为接口与纯数据结构相互继承。
## 从同一个已编译程序集生成各语言的包
从同一已编译程序集生成每种目标语言的制品,使各目标语言包共享同一个 API 事实来源。
### 生成管线
1. 从已编译的实现语言包中读取程序集。
2. 为所选目标语言生成符合其习惯的源代码。
3. 使用该语言的工具链编译生成的源代码。
4. 使用目标生态系统的标准包管理器打包结果。
### 目标语言设计
- 为每种目标语言提供基于共享遍历抽象构建的独立适配器。
- 添加新目标语言时,以成熟目标语言为参考,但保留新语言自身的惯用方式。
- 仅在运行时架构需要时捆绑原始实现制品。
- 包含下游反射工具或生成工具所需的程序集元数据。
- 在各目标语言之间共享格式化、缩进、文件创建和代码块实用工具。
- 每当目标语言发生变化时,更新生成代码快照。
## 在单体仓库中用固定版本的工具构建和测试
通过代码仓库固定的工作区工具链执行安装、构建、测试、代码检查、快照更新和合规生成。
### 环境与范围
- 进行完整初始化和全仓库验证时,从代码仓库根目录开始。
- 进行聚焦迭代时,从相应包目录运行包范围脚本。
- 遵守声明的包管理器和编排工具版本。
- 当包间依赖使并行执行不安全时,限制构建并发度。
### 变更工作流
- 在编辑或运行命令前,确定负责该变更的包。
- 先构建并测试目标包,再对共享契约执行更广泛的验证。
- 编辑源代码而不是生成的捆绑文件,并通过指定管线重新构建。
- 将临时运行时覆盖项和调试器设置保留在本地。
- 只有在确认生成的变更是有意为之后,才更新快照。
## 用快照和所有语言都要通过的共享测试检查行为
将快速的包级测试、生成输出回归检查和跨语言合规测试套件结合起来。
### 验证层级
- 使用单元测试验证包逻辑和协议边界情况。
- 使用快照检测生成源代码中的意外变更。
- 使用共享夹具覆盖类、接口、数据结构、枚举、集合、异步调用和重写。
- 使用合规测试验证每种语言绑定中的等价行为。
### 夹具与报告
- 使用真实使用方所用的同一编译器编译共享夹具。
- 夹具发生变化时,刷新所有受影响的生成器、反射工具和运行时快照。
- 每个合规用例只定义一次,然后要求每种语言绑定实现该用例或明确对其分类。
- 每当用例或结果发生变化时,重新生成并提交合规报告。
- 当某个语言绑定添加了测试套件定义中不存在的用例,或报告已过期时,使验证失败。
## 带上更新后的快照和报告发布变更,不强制推送
将生成代码、协议格式、运行时库和报告作为需要协调的发布界面。
### 不可让步的约束
- 未经所有目标语言的验证,不得放宽导出类型限制。
- 未协调更新宿主运行时,不得更改协议操作或带标签的序列化格式。
- 未更新并审查快照,不得更改生成模式。
- 当运行时库被有意设计为单线程时,不得假定其线程安全。
- 当构建图拒绝循环时,不得引入循环包依赖。
- 不得直接修改捆绑输出。
### 拉取请求与交接
- 使用代码仓库要求的标题格式、范围约定和贡献许可确认。
- 包含源代码变更所要求的所有生成快照和合规报告。
- 不要在变更中混入无关的生成文件、锁文件变更和本地设置。
- 如果远程分支已有新提交,则获取并变基或合并,解决冲突、验证,然后正常推送;绝不强制推送。
- 将下游代码仓库或文档同步记录在发布检查清单中,而不是依赖记忆。
