# Nerve Coding Conventions ## 语言与范式 ### 函数式优先 用 `function` + `type`,不用 `class` + `interface`。 ```typescript // ✅ Good type WorkflowLaunch = { senseName: string workflowName: string ts: number } function recordWorkflowLaunch(senseName: string, workflowName: string): WorkflowLaunch { return { senseName, workflowName, ts: Date.now() } } // ❌ Bad interface IWorkflowLaunch { senseName: string workflowName: string ts: number } class WorkflowLaunch implements IWorkflowLaunch { constructor( public senseName: string, public workflowName: string, public ts: number, ) {} } ``` ### 具体规则 | 规则 | 说明 | |------|------| | `type` over `interface` | 所有类型定义用 `type`,不用 `interface` | | `function` over `class` | 用纯函数 + 闭包,不用 class | | 无 `this` | 函数不依赖 `this` 上下文 | | 无继承 | 不用 `extends`、`implements`、`abstract` | | 组合优先 | 用函数组合代替继承层次 | | 不可变优先 | 用 `Readonly`、`as const`,避免 mutation | | 禁用 optional properties | 不用 `?:`,用 `T \| null` 显式标记可空;多个互斥字段用 discriminated union | ### 禁用 Optional Properties 不使用 `?:`,所有可空字段显式标注 `T | null`。 ```typescript // ✅ Good — 明确表达"可以为空" type SenseConfig = { group: string; throttle: string | null; timeout: string | null; } // ❌ Bad — optional 隐藏了"缺失"和"空值"的区别 type SenseConfig = { group: string; throttle?: string; timeout?: string; } ``` 当多个字段互斥时,用 discriminated union 代替一堆 optional: ```typescript // ✅ Good — 编译器保证两种 overflow 形态互斥且字段完整 type WorkflowConfig = | { concurrency: number; overflow: "drop" } | { concurrency: number; overflow: "queue"; maxQueue: number } // ❌ Bad — 字段一堆 optional,运行时才知道到底填了哪种并发策略 type WorkflowConfig = { concurrency?: number; overflow?: string; maxQueue?: number; } ``` ### 例外 以下场景允许 class: - 第三方库要求(如 Drizzle 的 `sqliteTable` 返回值) - Error 子类(`class NerveError extends Error`) ## 模块与导出 ```typescript // ✅ Named exports only export function startEngine(config: EngineConfig): Engine { ... } export type EngineConfig = { ... } // ❌ No default exports export default function startEngine() { ... } ``` - 一律 named export,不用 default export - 一个模块做一件事,文件名即职责 ## 命名 | 类型 | 风格 | 示例 | |------|------|------| | 文件 | kebab-case | `sense-scheduler.ts` | | 类型 | PascalCase | `SenseScheduler` | | 函数/变量 | camelCase | `createSenseScheduler` | | 常量 | UPPER_SNAKE | `MAX_RETRY_COUNT` | | 泛型参数 | 单字母或描述性 | `T`, `TValue` | ## 错误处理 ```typescript // ✅ 用 Result 类型表达可预期的失败 type Result = { ok: true; value: T } | { ok: false; error: E } function parseSenseConfig(raw: unknown): Result { // ... } // ✅ throw 只用于不可恢复的 bug function unreachable(x: never): never { throw new Error(`Unreachable: ${x}`) } ``` - 可预期的失败用 `Result` 类型返回 - `throw` 只用于 bug(程序员错误),不用于业务逻辑 - 不用 try-catch 做流程控制 ## 异步 ```typescript // ✅ async/await,不用 .then() 链 async function runCompute(sense: SenseModule): Promise { const value = await sense.compute(db, peers) if (value == null) return null return createSignal(sense.id, value) } ``` ## 工具链 | 工具 | 用途 | |------|------| | **pnpm** | 包管理 | | **TypeScript** | 类型检查(strict mode) | | **Biome** | lint + format(替代 ESLint + Prettier) | | **tsup** | 打包 | ### 常用命令 ```bash pnpm run check # biome check(lint + format 检查) pnpm run format # biome format --write(自动修复格式) pnpm run build # 全量构建 ``` ## Monorepo 结构 ``` nerve/ packages/ core/ # @nerve/core — 共享类型和工具函数 cli/ # @nerve/cli — CLI 入口 daemon/ # @nerve/daemon — 引擎运行时 docs/ # RFC、convention 等文档 biome.json # 根级 Biome 配置 tsconfig.json # 根级 TypeScript 配置(composite project references) ``` - `core` 是共享层,`cli` 和 `daemon` 都依赖它 - `cli` 和 `daemon` 之间不互相依赖 - 未来云端版本作为新 package 加入 ## Commit Convention ``` (): type: feat | fix | refactor | docs | chore | test scope: core | cli | daemon | rfc-001 | ... ``` --- *小橘 🍊(NEKO Team)*