1
0
Files
DiAL/openspec/specs/backend-code-quality/spec.md
lanyuanxiaoyao e983e5d75d refactor: 重命名 command checker 为 cmd checker 并适配跨平台测试
将 type/configKey 从 "command" 统一为 "cmd",源码目录 runner/command/ → runner/cmd/,
spec 目录 command-checker/ → cmd-checker/,测试全部改用 bun -e 替代 Unix 系统命令,
归档 cmd-checker-enhancement 变更并同步 delta spec 到主 spec。
2026-05-14 09:23:10 +08:00

103 lines
4.9 KiB
Markdown
Raw 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.
## Purpose
定义后端代码中 es-toolkit 和 Bun 内置 API 的使用规范:类型判断、空值检测、深度比较、错误判断、并发控制、集合分组和 Web API 标准方法,替代手写实现落实库使用优先级规则。
## Requirements
### Requirement: 使用 es-toolkit 进行类型判断
系统 SHALL 使用 es-toolkit 的 `isPlainObject` 替代手写的对象类型判断函数,用于 expect 校验中区分纯值(原始值)和操作符对象。
#### Scenario: 识别纯对象为操作符
- **WHEN** body 校验规则中 expected 配置为 `{ equals: "value" }`(纯对象操作符)
- **THEN** `isPlainObject(expected)` SHALL 返回 true系统按操作符语义处理
#### Scenario: 排除非纯对象作为操作符
- **WHEN** body 校验规则中 expected 为原始值如 `"value"` 或数字 `200`
- **THEN** `isPlainObject(expected)` SHALL 返回 false系统按 equals 默认操作符处理
### Requirement: 使用 es-toolkit 进行空值检测
系统 SHALL 使用 es-toolkit 的 `isNil` 替代手写的 `actual === null || actual === undefined` 检测,用于 expect 中 `empty` 操作符的空值判断。
#### Scenario: null 值判定为空
- **WHEN** 校验值为 null
- **THEN** `isNil(null)` SHALL 返回 true
#### Scenario: undefined 值判定为空
- **WHEN** 校验值为 undefined
- **THEN** `isNil(undefined)` SHALL 返回 true
#### Scenario: 非空值判定为非空
- **WHEN** 校验值为 0、"false"、空数组 `[]` 等非 nil 值
- **THEN** `isNil(value)` SHALL 返回 false
### Requirement: 使用 es-toolkit 进行空对象检测
系统 SHALL 使用 es-toolkit 的 `isEmptyObject` 替代手写的 `typeof actual === "object" && Object.keys(actual).length === 0` 检测,用于 expect 中 `empty` 操作符的空对象判断。
#### Scenario: 空对象判定为空
- **WHEN** 校验值为 `{}`
- **THEN** `isEmptyObject({})` SHALL 返回 true
#### Scenario: 非空对象判定为非空
- **WHEN** 校验值为 `{ key: "val" }`
- **THEN** `isEmptyObject({ key: "val" })` SHALL 返回 false
#### Scenario: null 不是空对象
- **WHEN** 校验值为 null
- **THEN** `isEmptyObject(null)` SHALL 返回 false空值由 isNil 前置处理)
### Requirement: 使用 es-toolkit 进行深度相等比较
系统 SHALL 使用 es-toolkit 的 `isEqual` 替代 `!==` 浅比较,用于 expect 中 `equals` 操作符的值比较,支持对象和数组的深度比较。
#### Scenario: 原始值浅比较
- **WHEN** expected 和 actual 均为原始值字符串、数字、布尔值、null
- **THEN** `isEqual(actual, expected)` 的行为 SHALL 与 `actual === expected` 一致
#### Scenario: 对象深度比较
- **WHEN** expected 和 actual 均为对象(如从 JSONPath 提取的结构化数据)
- **THEN** `isEqual(actual, expected)` SHALL 递归比较所有属性值,而非引用比较
### Requirement: 使用 es-toolkit 进行错误类型判断
系统 SHALL 使用 es-toolkit 的 `isError` 替代 `error instanceof Error`,用于 HTTP runner 和 cmd runner 中的错误类型判断。
#### Scenario: Error 实例识别
- **WHEN** 错误对象为 `new Error("msg")`
- **THEN** `isError(error)` SHALL 返回 true
#### Scenario: Error 子类识别
- **WHEN** 错误对象为继承 Error 的自定义类型
- **THEN** `isError(error)` SHALL 返回 true
#### Scenario: 非 Error 对象识别
- **WHEN** 错误对象为字符串或普通对象
- **THEN** `isError(error)` SHALL 返回 false
### Requirement: 使用 es-toolkit Semaphore 实现并发控制
系统 SHALL 使用 es-toolkit 的 `Semaphore` 类替代手写的信号量实现(计数器 + Promise 队列),用于 ProbeEngine 中的组内并发拨测控制。
#### Scenario: 获取并发槽位
- **WHEN** 当前并发数未达上限
- **THEN** `semaphore.acquire()` SHALL 立即返回,不阻塞
#### Scenario: 等待并发槽位
- **WHEN** 当前并发数已达上限 maxConcurrentChecks
- **THEN** `semaphore.acquire()` SHALL 阻塞等待,直到其他任务调用 `semaphore.release()`
#### Scenario: 释放并发槽位
- **WHEN** 调用 `semaphore.release()`
- **THEN** 系统 SHALL 唤醒一个等待中的 acquire() 调用
### Requirement: 使用 es-toolkit groupBy 实现 target 分组
系统 SHALL 使用 es-toolkit 的 `groupBy` 函数替代手写的 Map 循环分组,用于 ProbeEngine 中按 interval 分组拨测目标。
#### Scenario: 按 interval 分组
- **WHEN** 输入包含不同 intervalMs 值的多个 target
- **THEN** `groupBy(targets, t => t.intervalMs)` SHALL 返回 key 为 intervalMs 值的分组对象,值为对应 target 数组
### Requirement: 使用 Bun 内置 API 进行 Headers 转换
系统 SHALL 使用 `Object.fromEntries(headers)` 标准 Web API 替代手写的 `headersToRecord` 函数,用于将 Fetch API 的 Headers 对象转换为键值对。
#### Scenario: 转换响应头
- **WHEN** HTTP runner 获取到 response headers
- **THEN** `Object.fromEntries(response.headers)` SHALL 返回以 header 名称为 key、header 值为 value 的对象