feat: release Dever 0.1.4 with enforceable project guidance
This commit is contained in:
1 parent
201bdee372
commit
89629c2197
86 files changed
+2798
-338
No files matched your search
@@ -1,26 +1,28 @@
|
||||
# 核心语法
|
||||
|
||||
以下片段说明语法。将它们放进正确角色文件并补完整调用链后检查,不能当作免配置 HTTP 项目。
|
||||
每个片段都链接到随 skill 提供、经过检查的完整源码。先看它所属的角色和调用链,再复用到项目;不要把片段单独当作完整 HTTP 项目。
|
||||
|
||||
## 类型和函数
|
||||
|
||||
```dever
|
||||
type Greeting {
|
||||
message: Text
|
||||
}
|
||||
源码:[模板 App](../assets/template/module/hello/greeting/app.dever)
|
||||
|
||||
greet(name: Text) (response: Greeting) {
|
||||
response = Greeting { message = "Hello, " + text.trim(name) }
|
||||
```dever
|
||||
greet(name: Text) (message: Text) {
|
||||
message = "Hello, " + name
|
||||
}
|
||||
```
|
||||
|
||||
函数是 `name(输入) (命名输出) { 线性语句 }`,没有 function/return。调用按位置传参。零输入或零输出也写 `()`。单输出直接得到值;多输出调用返回只能按输出名访问的结果。App 的输入、输出和向外传播错误均为公开合同,不暴露 Domain/Adapter 私有类型。
|
||||
函数写成 `name(输入) (命名输出) { 语句 }`,不写 function/return,调用按位置传参。没有输入或输出时也要保留 `()`。一个输出直接得到值;多个输出按名字访问。
|
||||
|
||||
App 的参数、返回值和向外传播的错误都属于公开接口,不能暴露 Domain/Adapter 私有类型。
|
||||
|
||||
函数命名表达业务行为,调用路径不附加主题文件名。相关函数、类型和同名分句可以同处一个内聚文件;拆分与复用的判断见 [文件与函数组织](development.md#文件与函数组织),不按函数长度自动增加 helper。
|
||||
|
||||
常用类型:`Bool`、`Int`(检查溢出)、`Float`、精确 `Decimal`、`Text`、`Bytes`、`Uuid`、`Id`、`DateTime`、`Date`、`Time`、`Duration`、`Secret`、`Json`。可空用 `T?`,集合用 `List<T>`、`Map<K,V>`。Model ID 是每个 Model 独有的名义类型,不等于任意 Int。不得把不同表的 ID 混用。
|
||||
|
||||
record 用字段初始化;choice 用分支构造:
|
||||
record 用字段初始化;choice 用分支构造。以下 State、label、display 和 grade 位于同一份语法测试,测试入口覆盖每个分句;实际业务无需创建这些演示函数。
|
||||
|
||||
源码:[分句测试](../assets/examples/collections/test/content/article/clauses.dever)
|
||||
|
||||
```dever
|
||||
type State {
|
||||
@@ -28,7 +30,11 @@ type State {
|
||||
Published
|
||||
Rejected(reason: Text)
|
||||
}
|
||||
```
|
||||
|
||||
源码:[分句测试](../assets/examples/collections/test/content/article/clauses.dever)
|
||||
|
||||
```dever
|
||||
label(state: State.Published) (text: Text) {
|
||||
text = "published"
|
||||
}
|
||||
@@ -44,7 +50,11 @@ label(state: other) (text: Text) {
|
||||
|
||||
## 分支与边界
|
||||
|
||||
没有 if、else、switch、match、条件表达式或递归。同名、同参数数量的分句必须连续,相同输出合同,互斥且穷尽;没有先匹配谁的顺序优先级。`other` 是同一参数位置所有明确模式的补集。
|
||||
用同名函数的不同分句表达条件,不写 if/else/switch/match、条件表达式或递归。这些分句要连续,参数数量和输出声明一致。
|
||||
|
||||
每种输入必须恰好匹配一个分句:不能漏掉,也不能重叠;写在前面不会优先匹配。`other` 表示该参数位置没有被其他明确模式覆盖的值。
|
||||
|
||||
源码:[分句测试](../assets/examples/collections/test/content/article/clauses.dever)
|
||||
|
||||
```dever
|
||||
display(value: Text) (text: Text) {
|
||||
@@ -68,16 +78,67 @@ grade(score: Int >= 60) (text: Text) {
|
||||
|
||||
字面量分句适合明确的状态和规则,不意味着可以按某个用户 ID、租户名字或样例数据写业务特例。运行时配置与可信身份的归属见 [配置与硬编码](development.md#配置与硬编码)。
|
||||
|
||||
集合遍历使用语言的 `map/filter/reduce/each` 等核心操作及静态 handler,不能加入 for/while。handler 的签名和可达调用链由编译器检查,不是运行期闭包或动态插件。具体签名查当前版本 `library/` 与核心语言指南,不杜撰 lambda 语法。
|
||||
## 集合与处理函数
|
||||
|
||||
Dever 用 `each` 同时表达映射和遍历,没有独立的 `map`:处理函数有一个输出时生成 List,没有输出时逐项执行动作。`filter` 按 Bool 输出筛选,`reduce` 按初始值逐项累积。它们是语言核心操作,不需要导入集合库。
|
||||
|
||||
下面的 App 选出已发布且标题非空的文章,整理标题并统计总字数。输入、结果类型与完整调用链都在 [集合项目](../assets/examples/collections/) 内。
|
||||
|
||||
源码:[文章 App](../assets/examples/collections/module/content/article/app.dever)
|
||||
|
||||
```dever
|
||||
type Article {
|
||||
title: Text
|
||||
published: Bool
|
||||
}
|
||||
|
||||
type Summary {
|
||||
titles: List<Text>
|
||||
title_length: Int
|
||||
}
|
||||
|
||||
summarize(articles: List<Article>) (summary: Summary) {
|
||||
published = filter(domain.is_published, articles)
|
||||
titles = each(domain.published_title, published)
|
||||
summary = Summary {
|
||||
titles = titles
|
||||
title_length = reduce(domain.add_title_length, titles, 0)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
处理函数直接使用有业务含义的命名函数。参数顺序、类型和输出由编译器检查,不使用 lambda 或运行期闭包:
|
||||
|
||||
源码:[文章 Domain](../assets/examples/collections/module/content/article/domain.dever)
|
||||
|
||||
```dever
|
||||
is_published(article: app.Article) (selected: Bool) pure {
|
||||
selected = article.published and text.trim(article.title) != ""
|
||||
}
|
||||
|
||||
published_title(article: app.Article) (title: Text) pure {
|
||||
title = text.trim(article.title)
|
||||
}
|
||||
|
||||
add_title_length(title: Text, total: Int) (next: Int) pure {
|
||||
next = total + length(title)
|
||||
}
|
||||
```
|
||||
|
||||
`filter` 的处理函数接收一个元素,输出 Bool;`each` 的单输出成为新 List 的元素;`reduce` 按“元素、当前累计值”传参,输出下一个累计值。顺序保持不变,空集合的 reduce 返回初始值。本例初始值为 0。
|
||||
|
||||
集合项目的 [summary 测试](../assets/examples/collections/test/content/article/summary.dever) 用 `each(assert_clean_title, actual.titles)` 逐条断言。这个处理函数没有输出,所以该调用没有返回 List。测试还验证筛选顺序、清理结果、总字数和空集合。
|
||||
|
||||
## 失败和能力
|
||||
|
||||
业务错误通过 choice 的 `error` 分支声明,`fail` 传播,`result(call)` 显式捕获;普通调用直接得到成功值。不能用字符串/任意 JSON 代替类型化失败,不能捕获后悄悄吞掉错误。错误映射到 HTTP 的方式见 application.md。
|
||||
|
||||
纯 Domain 函数可声明 `pure`,编译器检查其调用链;要从 Model REST 字段来源调用的业务转换必须是合规的同领域 pure Domain。外部文件/网络 I/O 经 Port/Adapter,不把系统调用塞入普通 App 或 Domain。
|
||||
Domain 的纯计算函数可以声明 `pure`,它调用的方法也要满足纯计算要求。Model 的 REST 字段转换只能调用合规的同领域 pure Domain。文件、网络等外部操作经 Port/Adapter,不直接放进普通 App 或 Domain。
|
||||
|
||||
Dever 推断挂起,无需 async/await。直接调用按顺序完成;`run` 显式启动结构化子任务,`wait/stop` 消费 Task,任务不能逃逸所属作用域。Group/Channel/Stream 具有静态资源约束;不能跨挂起、线程或请求随意保存句柄。`result` 不改变调度,也不绕开 effect 检查。
|
||||
不需要写 async/await,普通调用依次完成。要并发执行时用 `run` 启动子任务,再用 `wait/stop` 收尾;不能把任务留到当前作用域之外。
|
||||
|
||||
`Secret` 不可打印、比较或转为普通 Text。密码使用现有 crypto 能力;不要自制哈希。声明类型、分句和 effect 报错时修正真实边界,不添加无意义中转函数、泛用返回包装或吞错分句来绕过检查。
|
||||
Group/Channel/Stream 的使用范围由编译器检查,不能跨等待、线程或请求随意保存句柄。`result` 只负责捕获结果,不改变调度,也不让原本禁止的操作变成合法。
|
||||
|
||||
`Secret` 不可打印、比较或转为普通 Text。密码使用现有 crypto 能力,不自制哈希。类型、分句或调用能力报错时修正真实问题,不增加中转函数、通用包装或吞错分句来绕过检查。
|
||||
|
||||
更多完整语法以官方核心仓库同版本 `LANGUAGE.md` 为准;新建项目先使用本 skill 的已验证模板。
|
||||
Reference in new issue
Block a user