Files

66 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 用 Python、JavaScript 或 Go 转换 Markdown
复制 [external-lib 项目](../assets/examples/external-lib/) 后,就能检查源码并运行 fake 测试。无需安装 Python/Node/Go 或下载依赖。
项目用现成 Markdown 库转换内容,App 只调用 Port。生成的 HTML 没有做安全清洗;展示不可信输入前,需要按产品要求清洗。外部语言只承接需要复用的能力,不转移普通业务逻辑。
先读 `module/document/markup/app.dever`、`port.dever`、`adapter.dever` 和两个测试。Port 的成功输出必须带名字 html,失败合同来自公开 App 的 RenderResult;同一份 Dever 声明供三种实现复用。
默认选择 pip。切换生态时只替换 `adapter.dever` 中的 external 声明、同一文件的 lib 值及 `config/setting.json` 的根 lib 数组;不要同时复制三个 Adapter 到同一角色,也不要改 Port/App/Test:
| 生态 | external 声明 | lib 声明 | setting.json 根 lib 中的值 | 已附实现 |
| --- | --- | --- | --- | --- |
| Python | `external pip "python/render.py"` | `lib "markdown@3.8.2"` | `pip:markdown@3.8.2` | `module/document/markup/python/render.py` |
| JavaScript | `external npm "javascript/render.mjs"` | `lib "marked@15.0.12"` | `npm:marked@15.0.12` | `module/document/markup/javascript/render.mjs` |
| Go | `external go "go/render.go"` | `lib "github.com/yuin/goldmark@v1.7.8"` | `go:github.com/yuin/goldmark@v1.7.8` | `module/document/markup/go/render.go` |
项目默认 Python 的完整声明如下,JS/Go 按表替换:
源码:[外部 Adapter](../assets/examples/external-lib/module/document/markup/adapter.dever)
```dever
external pip "python/render.py" {
lib "markdown@3.8.2"
}
```
版本是示例固定输入,不表示“最新版本”;显式依赖准备仍须验证来源、许可证和产品需求。库的 Markdown 方言与尾部换行不同,切换生态不保证输出逐字节等价,真实输出验收需针对所选库进行。普通 fake 用例只验证 App/Port 合同。
## 外部函数怎么写
Python 导出 `async def render(payload, setting)`;JS 导出 `async function render(payload, setting, signal)`;Go 导出 `func Render(context.Context, any, any) (any, error)`,使用 `package main`,但不手写 main。操作名 `render` 在 Go 映射为 `Render`,蛇形名按段转 PascalCase。
编译器从 Port 生成 `contract.json`,写入参数、返回值、业务错误和接口标识。运行器自动找到同名处理函数,不需要项目复制 SDK、维护注册表、计算 hash 或编写 stdin 协议。
Python 使用 `Worker.from_manifest`,JS 使用 `Worker.fromManifest`,Go 由生成的入口调用 `ServeManifest`。SDK 来自匹配版本的运行资源。
三种实现共用的是 Port 的输入、输出、错误和操作合同。schema 身份还包含所选生态与 Lib 声明,因此切换生态或依赖后会变化,不能复用旧 manifest 或要求三种 hash 相等。
本例输入是 `{"source":"# Report"}`,成功返回 `{"html":"..."}`。即使只有一个输出,也不能返回裸字符串。
没有 setting 声明时,setting 为 null/nil。需要配置再增加 Adapter setting 类型和对应配置绑定,不能读取环境变量。
业务拒绝使用 SDK 的 `BusinessError`:本例的 identity 是 `document.markup.RenderResult.Rejected`,payload 是 `{"message":"..."}`。未知异常属于运行失败,不自动变成业务拒绝,也不返回假成功。
stdout 专用于协议,日志写 stderr。Python 处理函数要响应取消,JS 使用 signal,Go 使用 context。需要网络、文件、子进程或 GPU 时,通过 `allow` 声明效果;实际权限继承容器用户,由部署侧管理,不再使用 Dever 内层沙箱或 Adapter 挂载授权。真实文件路径通过业务 setting 传入。只运行可信 Worker,本例纯文档转换不需要这些能力。
## 准备与测试
```sh
dever check <root>
dever test <root> --filter document.markup --timeout-ms 5000
```
`rendered` 与 `rejected` 各自替换 `port.render`,分别检查成功和业务拒绝。fake 只对当前用例有效,不会影响其他测试。编译器检查参数、返回值、允许的错误和调用能力。普通测试不加载真实库、不启动 Worker,也不要求依赖锁或生产配置。
需要真实运行时,按用户授权准备依赖:
```sh
dever lib add <root> pip:markdown@3.8.2
dever run <root> -- document.markup.render '{"source":"# Report"}'
```
JS/Go 改用表中的依赖声明。已有锁迁移机器时使用 `dever lib install <root>`。run/build 离线;缺资源就报错,不借用宿主解释器。切换依赖使用 Lib 命令并核对锁,不手工伪造 dever.lock。
静态示例与 fake 检查不证明第三方依赖已下载、真实库输出已验收或跨架构 Worker 已可运行。