@namewta/speculo 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/package.json +1 -1
- package/template/canonical/canonical-specdev-wayfinder.md +146 -41
- package/template/skills/typescript-engineering-standards/README.md +36 -0
- package/template/skills/typescript-engineering-standards/SKILL.md +158 -0
- package/template/skills/typescript-engineering-standards/examples/comment-patterns.md +47 -0
- package/template/skills/typescript-engineering-standards/examples/naming-patterns.md +42 -0
- package/template/skills/typescript-engineering-standards/examples/project-layouts.md +75 -0
- package/template/skills/typescript-engineering-standards/examples/review-output-example.md +25 -0
- package/template/skills/typescript-engineering-standards/examples/type-modeling-patterns.md +66 -0
- package/template/skills/typescript-engineering-standards/manifest.txt +33 -0
- package/template/skills/typescript-engineering-standards/references/00-standard-levels-and-precedence.md +51 -0
- package/template/skills/typescript-engineering-standards/references/01-project-architecture-and-directory-layout.md +105 -0
- package/template/skills/typescript-engineering-standards/references/02-file-directory-and-symbol-naming.md +117 -0
- package/template/skills/typescript-engineering-standards/references/03-modules-imports-exports-and-dependencies.md +111 -0
- package/template/skills/typescript-engineering-standards/references/04-typescript-type-system.md +150 -0
- package/template/skills/typescript-engineering-standards/references/05-functions-async-errors-and-resources.md +142 -0
- package/template/skills/typescript-engineering-standards/references/06-comments-jsdoc-and-documentation.md +104 -0
- package/template/skills/typescript-engineering-standards/references/07-testing-strategy.md +84 -0
- package/template/skills/typescript-engineering-standards/references/08-react-and-frontend.md +91 -0
- package/template/skills/typescript-engineering-standards/references/09-node-cli-and-cross-platform.md +92 -0
- package/template/skills/typescript-engineering-standards/references/10-formatting-lint-and-complexity.md +107 -0
- package/template/skills/typescript-engineering-standards/references/11-configuration-dependencies-and-ci.md +86 -0
- package/template/skills/typescript-engineering-standards/references/12-security-performance-and-i18n.md +65 -0
- package/template/skills/typescript-engineering-standards/references/13-git-review-and-delivery.md +79 -0
- package/template/skills/typescript-engineering-standards/references/14-adoption-exceptions-and-migration.md +84 -0
- package/template/skills/typescript-engineering-standards/references/15-orca-derived-observations.md +54 -0
- package/template/skills/typescript-engineering-standards/references/README.md +45 -0
- package/template/skills/typescript-engineering-standards/templates/.editorconfig +12 -0
- package/template/skills/typescript-engineering-standards/templates/AGENTS.typescript.md +21 -0
- package/template/skills/typescript-engineering-standards/templates/code-review-checklist.md +37 -0
- package/template/skills/typescript-engineering-standards/templates/package-scripts.json +11 -0
- package/template/skills/typescript-engineering-standards/templates/prettier.json +6 -0
- package/template/skills/typescript-engineering-standards/templates/pull-request-template.md +37 -0
- package/template/skills/typescript-engineering-standards/templates/tsconfig.base.json +17 -0
- package/template/skills/typescript-engineering-standards/templates/tsconfig.project-references.json +8 -0
- package/template/workflows/specdev/A-archive-and-consolidate/A-archive-and-consolidate.md +89 -25
- package/template/workflows/specdev/A-archive-and-consolidate/consolidation-interview.md +56 -0
- package/template/workflows/specdev/INDEX.md +1 -1
- package/template/workflows/specdev/W-wayfinder/W-wayfinder.md +85 -27
- package/template/workflows/specdev/W-wayfinder/investigation-ticket-template.md +15 -4
- package/template/workflows/specdev/W-wayfinder/wayfinder-map-template.md +48 -12
package/template/skills/typescript-engineering-standards/references/04-typescript-type-system.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# TypeScript 类型系统规范
|
|
2
|
+
|
|
3
|
+
## 严格模式
|
|
4
|
+
|
|
5
|
+
新项目必须启用 `strict`。建议逐步启用:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"compilerOptions": {
|
|
10
|
+
"strict": true,
|
|
11
|
+
"noUncheckedIndexedAccess": true,
|
|
12
|
+
"exactOptionalPropertyTypes": true,
|
|
13
|
+
"noImplicitOverride": true,
|
|
14
|
+
"noImplicitReturns": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"useUnknownInCatchVariables": true,
|
|
17
|
+
"verbatimModuleSyntax": true,
|
|
18
|
+
"isolatedModules": true,
|
|
19
|
+
"forceConsistentCasingInFileNames": true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
具体选项需与编译器版本、模块系统和构建工具兼容。
|
|
25
|
+
|
|
26
|
+
## 禁止传播 `any`
|
|
27
|
+
|
|
28
|
+
外部或未知值使用 `unknown`,在边界收窄:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
function parsePayload(input: unknown): ParsedPayload {
|
|
32
|
+
return payloadSchema.parse(input)
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`any` 只允许存在于极小的兼容层,例如第三方类型错误或遗留迁移,并必须:
|
|
37
|
+
|
|
38
|
+
- 限定最小作用域。
|
|
39
|
+
- 写明原因与退出条件。
|
|
40
|
+
- 经过运行时验证后再向内部传递。
|
|
41
|
+
- 不进入公共 API。
|
|
42
|
+
|
|
43
|
+
## 外部输入必须验证
|
|
44
|
+
|
|
45
|
+
以下数据默认不可信:
|
|
46
|
+
|
|
47
|
+
- HTTP、RPC、WebSocket、IPC 消息。
|
|
48
|
+
- CLI 参数和环境变量。
|
|
49
|
+
- JSON、数据库反序列化、本地存储。
|
|
50
|
+
- 第三方 SDK 返回值。
|
|
51
|
+
- 浏览器消息和插件输入。
|
|
52
|
+
|
|
53
|
+
类型断言不是验证:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
// 错误
|
|
57
|
+
const config = JSON.parse(raw) as AppConfig
|
|
58
|
+
|
|
59
|
+
// 正确
|
|
60
|
+
const config = appConfigSchema.parse(JSON.parse(raw))
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 可辨识联合
|
|
64
|
+
|
|
65
|
+
使用单一判别字段表达互斥状态:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
type ConnectionState =
|
|
69
|
+
| { kind: 'idle' }
|
|
70
|
+
| { kind: 'connecting'; startedAtMs: number }
|
|
71
|
+
| { kind: 'connected'; connectionId: string }
|
|
72
|
+
| { kind: 'failed'; error: Error }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
避免多个可能互相矛盾的布尔字段。对状态分支执行穷尽检查;需要 `default` 时使用 `never` 断言。
|
|
76
|
+
|
|
77
|
+
## `type` 与 `interface`
|
|
78
|
+
|
|
79
|
+
默认策略可选择其一并保持一致。推荐默认使用 `type`,以下场景使用 `interface`:
|
|
80
|
+
|
|
81
|
+
- 需要声明合并。
|
|
82
|
+
- 公共库希望消费者扩展契约。
|
|
83
|
+
- 面向对象体系明确使用 `implements`。
|
|
84
|
+
- 框架生态已有强约定。
|
|
85
|
+
|
|
86
|
+
不要在同一领域无理由混用。
|
|
87
|
+
|
|
88
|
+
## 显式类型和推断
|
|
89
|
+
|
|
90
|
+
必须显式标注:
|
|
91
|
+
|
|
92
|
+
- 导出函数返回类型。
|
|
93
|
+
- 跨模块公共 API。
|
|
94
|
+
- 插件、回调和扩展点。
|
|
95
|
+
- 递归函数。
|
|
96
|
+
- 权限、金额、状态转换等高风险函数。
|
|
97
|
+
|
|
98
|
+
局部明显变量和短小私有函数可依赖推断。
|
|
99
|
+
|
|
100
|
+
## 类型断言
|
|
101
|
+
|
|
102
|
+
优先顺序:
|
|
103
|
+
|
|
104
|
+
1. 控制流收窄。
|
|
105
|
+
2. 类型守卫。
|
|
106
|
+
3. 运行时 Schema 验证。
|
|
107
|
+
4. `satisfies`。
|
|
108
|
+
5. 最后才使用 `as`。
|
|
109
|
+
|
|
110
|
+
禁止无理由双重断言:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
value as unknown as UserSession
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`@ts-ignore` 默认禁止。必须压制已知编译错误时,优先使用带原因的 `@ts-expect-error`,使错误消失后检查能够失败。
|
|
117
|
+
|
|
118
|
+
## 空值语义
|
|
119
|
+
|
|
120
|
+
明确区分:
|
|
121
|
+
|
|
122
|
+
- `property?: T`:属性可能不存在。
|
|
123
|
+
- `property: T | null`:属性存在,但值可以为空。
|
|
124
|
+
- `T | undefined`:查找可能没有结果。
|
|
125
|
+
- `Result<T, E>` 或异常:操作可能失败。
|
|
126
|
+
|
|
127
|
+
除非外部协议明确区分,不要写 `property?: T | null | undefined`。
|
|
128
|
+
|
|
129
|
+
## `.d.ts`
|
|
130
|
+
|
|
131
|
+
`.d.ts` 仅用于:
|
|
132
|
+
|
|
133
|
+
- 运行时已有但 TypeScript 不可见的全局声明。
|
|
134
|
+
- 无类型第三方模块声明。
|
|
135
|
+
- 框架或库声明扩展。
|
|
136
|
+
- 发布库生成的公共声明。
|
|
137
|
+
|
|
138
|
+
普通业务类型放在 `.ts` 中,通过正常模块导入。
|
|
139
|
+
|
|
140
|
+
## 枚举
|
|
141
|
+
|
|
142
|
+
默认优先字符串联合或 `as const` 对象。`enum` 主要用于外部协议、位标记、既有 API 或团队明确统一的运行时枚举需求。
|
|
143
|
+
|
|
144
|
+
## 不可变性
|
|
145
|
+
|
|
146
|
+
- 输入参数尽量使用只读结构。
|
|
147
|
+
- 对外返回 `ReadonlyArray<T>` 或只读对象。
|
|
148
|
+
- 不修改调用方传入对象。
|
|
149
|
+
- 需要排序或变更时先复制。
|
|
150
|
+
- 常量对象使用 `as const` 或 `satisfies`。
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# 函数、异步、错误与资源生命周期
|
|
2
|
+
|
|
3
|
+
## 函数职责
|
|
4
|
+
|
|
5
|
+
函数应只处理一个可命名职责和一个抽象层级。软性目标:
|
|
6
|
+
|
|
7
|
+
- 普通函数尽量不超过约 40 行。
|
|
8
|
+
- 编排函数尽量不超过约 60 行。
|
|
9
|
+
- 嵌套通常不超过三层。
|
|
10
|
+
- 参数超过三个时考虑参数对象。
|
|
11
|
+
|
|
12
|
+
这些数字用于触发审查,不是机械拆分标准。
|
|
13
|
+
|
|
14
|
+
## 提前返回
|
|
15
|
+
|
|
16
|
+
使用 Guard Clause 减少嵌套:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
function processSession(session: Session | undefined): Result {
|
|
20
|
+
if (!session) {
|
|
21
|
+
return emptyResult
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!session.isActive || !session.userId) {
|
|
25
|
+
return emptyResult
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return createResult(session)
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 参数对象
|
|
33
|
+
|
|
34
|
+
长参数列表或布尔参数应改为具名选项:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
type CreateSessionOptions = {
|
|
38
|
+
userId: string
|
|
39
|
+
timeoutMs: number
|
|
40
|
+
persistence: 'memory' | 'disk'
|
|
41
|
+
logger: Logger
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
避免 `createSession(id, true, false)`。
|
|
46
|
+
|
|
47
|
+
## 纯逻辑和副作用分离
|
|
48
|
+
|
|
49
|
+
建议分离:
|
|
50
|
+
|
|
51
|
+
- 解析。
|
|
52
|
+
- 验证。
|
|
53
|
+
- 领域决策。
|
|
54
|
+
- 数据持久化。
|
|
55
|
+
- 流程编排。
|
|
56
|
+
|
|
57
|
+
纯逻辑不读取隐藏全局状态、不修改输入、不直接访问网络、磁盘、时钟或随机源。将这些依赖作为参数或端口注入。
|
|
58
|
+
|
|
59
|
+
## Promise 必须有归宿
|
|
60
|
+
|
|
61
|
+
所有 Promise 必须被 `await`、`return`、显式收集,或用 `void` 明确表示有意脱离当前流程,并自行处理错误:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
void refreshCache().catch((error: unknown) => {
|
|
65
|
+
logger.error('Failed to refresh cache', { error })
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 并发
|
|
70
|
+
|
|
71
|
+
只有相互独立的任务才使用 `Promise.all`。有顺序、共享副作用、速率限制或资源约束时,使用顺序执行、队列或并发限制器。
|
|
72
|
+
|
|
73
|
+
不要无界并发处理大型输入集合。
|
|
74
|
+
|
|
75
|
+
## 取消与超时
|
|
76
|
+
|
|
77
|
+
网络、子进程、文件监听、Worker 和长任务应考虑:
|
|
78
|
+
|
|
79
|
+
- `AbortSignal`。
|
|
80
|
+
- 明确超时。
|
|
81
|
+
- 清理路径。
|
|
82
|
+
- 可识别的取消错误。
|
|
83
|
+
- 超时后底层资源是否真正停止。
|
|
84
|
+
|
|
85
|
+
## 重试
|
|
86
|
+
|
|
87
|
+
重试策略必须定义:
|
|
88
|
+
|
|
89
|
+
- 最大次数。
|
|
90
|
+
- 退避和抖动。
|
|
91
|
+
- 可重试错误范围。
|
|
92
|
+
- 幂等性。
|
|
93
|
+
- 最终失败的记录与反馈。
|
|
94
|
+
|
|
95
|
+
不能对所有错误无限重试。
|
|
96
|
+
|
|
97
|
+
## 错误处理
|
|
98
|
+
|
|
99
|
+
不得吞掉异常。允许忽略时必须说明这是最佳努力操作,并保留必要诊断信息。
|
|
100
|
+
|
|
101
|
+
错误应包含上下文并保留 `cause`:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
throw new Error(`Failed to load workspace config: ${configPath}`, {
|
|
105
|
+
cause: error
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
需要调用方分支处理的错误使用:
|
|
110
|
+
|
|
111
|
+
- 具名错误类。
|
|
112
|
+
- 带 `code` 的结构化错误。
|
|
113
|
+
- `Result<T, E>`。
|
|
114
|
+
- 可辨识联合。
|
|
115
|
+
|
|
116
|
+
不要通过匹配错误消息字符串控制流程。
|
|
117
|
+
|
|
118
|
+
## `catch` 值
|
|
119
|
+
|
|
120
|
+
将 `catch` 值视为 `unknown`,先通过 `instanceof`、错误守卫或标准化函数收窄。
|
|
121
|
+
|
|
122
|
+
## 资源清理
|
|
123
|
+
|
|
124
|
+
以下资源必须有明确生命周期:
|
|
125
|
+
|
|
126
|
+
- 事件监听器。
|
|
127
|
+
- Timer 和 Interval。
|
|
128
|
+
- 文件句柄。
|
|
129
|
+
- Socket、数据库连接。
|
|
130
|
+
- Worker 和子进程。
|
|
131
|
+
- `AbortController`。
|
|
132
|
+
- React Effect 订阅。
|
|
133
|
+
|
|
134
|
+
推荐返回清理函数或实现统一 `dispose()`:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
type Disposable = {
|
|
138
|
+
dispose(): void
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
创建资源的模块通常也应负责定义或暴露其清理方式。
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# 注释、JSDoc 与文档
|
|
2
|
+
|
|
3
|
+
## 注释解释原因
|
|
4
|
+
|
|
5
|
+
注释用于解释代码本身无法清楚表达的:
|
|
6
|
+
|
|
7
|
+
- 为什么必须采用此顺序。
|
|
8
|
+
- 为什么不能删除看似多余的逻辑。
|
|
9
|
+
- 平台、协议、性能或安全约束。
|
|
10
|
+
- 第三方缺陷和规避方案。
|
|
11
|
+
- 竞态条件和资源生命周期。
|
|
12
|
+
- 非直观产品规则。
|
|
13
|
+
|
|
14
|
+
不应逐行翻译代码。
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// 不推荐:Increment retry count.
|
|
18
|
+
retryCount += 1
|
|
19
|
+
|
|
20
|
+
// 推荐:Provider replication can briefly return 409 after a successful write.
|
|
21
|
+
retryCount += 1
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 注释风格
|
|
25
|
+
|
|
26
|
+
- 优先一行或一个短段落。
|
|
27
|
+
- 靠近被解释的逻辑。
|
|
28
|
+
- 使用完整、可验证的原因。
|
|
29
|
+
- 修改实现时同步更新。
|
|
30
|
+
- 能用命名和拆分表达时,不靠注释补救。
|
|
31
|
+
|
|
32
|
+
## 应写注释的场景
|
|
33
|
+
|
|
34
|
+
- 跨平台差异。
|
|
35
|
+
- 第三方类型或运行时缺陷。
|
|
36
|
+
- 兼容旧协议的临时分支。
|
|
37
|
+
- 性能关键路径的非直观优化。
|
|
38
|
+
- 安全检查顺序。
|
|
39
|
+
- 并发和竞态约束。
|
|
40
|
+
- 清理顺序。
|
|
41
|
+
- 特殊算法或领域公式。
|
|
42
|
+
|
|
43
|
+
## 不应写的注释
|
|
44
|
+
|
|
45
|
+
- 复述变量名或控制流。
|
|
46
|
+
- 注释掉的旧代码。
|
|
47
|
+
- 无跟踪信息的“以后优化”。
|
|
48
|
+
- 与实现重复的大篇教程。
|
|
49
|
+
- 无法验证的猜测。
|
|
50
|
+
|
|
51
|
+
历史实现由版本控制保存,不应长期留在源码中。
|
|
52
|
+
|
|
53
|
+
## JSDoc 使用范围
|
|
54
|
+
|
|
55
|
+
JSDoc 主要用于:
|
|
56
|
+
|
|
57
|
+
- 公共库 API。
|
|
58
|
+
- 插件和扩展点。
|
|
59
|
+
- 跨团队或跨进程契约。
|
|
60
|
+
- 参数具有单位、边界或特殊格式。
|
|
61
|
+
- 函数有重要副作用、取消、异常或线程安全语义。
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
/**
|
|
65
|
+
* Resolves a workspace path without following symbolic links.
|
|
66
|
+
*
|
|
67
|
+
* @throws {WorkspacePathError} When the path escapes the configured root.
|
|
68
|
+
*/
|
|
69
|
+
export function resolveWorkspacePath(
|
|
70
|
+
rootPath: string,
|
|
71
|
+
candidatePath: string
|
|
72
|
+
): string {
|
|
73
|
+
// ...
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
内部显而易见的函数不需要机械补全 JSDoc。
|
|
78
|
+
|
|
79
|
+
## TODO
|
|
80
|
+
|
|
81
|
+
TODO 必须包含负责人约定或可追踪编号,并说明删除条件:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// TODO(PROJ-1423): Remove after all clients send protocol v3.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
禁止:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// TODO: fix later
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 设计文档
|
|
94
|
+
|
|
95
|
+
以下内容更适合放入 `docs/` 或 ADR,而非源码注释:
|
|
96
|
+
|
|
97
|
+
- 多方案权衡。
|
|
98
|
+
- 跨服务架构。
|
|
99
|
+
- 数据迁移计划。
|
|
100
|
+
- 兼容性策略。
|
|
101
|
+
- 长期安全模型。
|
|
102
|
+
- 复杂协议说明。
|
|
103
|
+
|
|
104
|
+
源码注释可以引用相应 ADR 或问题编号,但应保留理解当前代码所需的最小上下文。
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# 测试策略
|
|
2
|
+
|
|
3
|
+
## 测试分层
|
|
4
|
+
|
|
5
|
+
| 类型 | 目标 | 默认位置 |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| 单元测试 | 函数、策略、解析器、状态转换 | 与源码同目录 |
|
|
8
|
+
| 集成测试 | 多个真实模块协作 | `tests/integration/` |
|
|
9
|
+
| 契约测试 | API、IPC、插件、适配器契约 | 源码旁或 `tests/contracts/` |
|
|
10
|
+
| E2E | 用户关键路径 | `tests/e2e/` |
|
|
11
|
+
| 基准测试 | 性能关键路径 | `*.bench.ts` |
|
|
12
|
+
|
|
13
|
+
## 测试命名
|
|
14
|
+
|
|
15
|
+
测试名描述可观察行为,而不是实现方法:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
describe('quoteShellArgument', () => {
|
|
19
|
+
it('preserves an empty argument as an explicit empty string', () => {
|
|
20
|
+
// ...
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
避免 `it('works')`、`describe('utils')`。
|
|
26
|
+
|
|
27
|
+
## 覆盖范围
|
|
28
|
+
|
|
29
|
+
关键模块应考虑:
|
|
30
|
+
|
|
31
|
+
- 正常路径。
|
|
32
|
+
- 边界值和空输入。
|
|
33
|
+
- 无效输入。
|
|
34
|
+
- 错误传播。
|
|
35
|
+
- 取消和超时。
|
|
36
|
+
- 并发或重复调用。
|
|
37
|
+
- 资源清理。
|
|
38
|
+
- 已修复缺陷的回归场景。
|
|
39
|
+
|
|
40
|
+
覆盖率数字不能替代风险导向的场景设计。
|
|
41
|
+
|
|
42
|
+
## 缺陷修复流程
|
|
43
|
+
|
|
44
|
+
1. 添加可稳定复现问题的失败测试。
|
|
45
|
+
2. 确认测试在修复前失败。
|
|
46
|
+
3. 实施最小修复。
|
|
47
|
+
4. 确认回归测试和相关测试通过。
|
|
48
|
+
5. 必要时增加跨平台或集成测试。
|
|
49
|
+
|
|
50
|
+
## 确定性
|
|
51
|
+
|
|
52
|
+
测试不应依赖:
|
|
53
|
+
|
|
54
|
+
- 真实当前时间。
|
|
55
|
+
- 外部不稳定网络。
|
|
56
|
+
- 测试执行顺序。
|
|
57
|
+
- 共享可变全局状态。
|
|
58
|
+
- 本机特定路径或环境配置。
|
|
59
|
+
- 无种子的随机数据。
|
|
60
|
+
|
|
61
|
+
通过注入时钟、随机源、文件系统和网络端口,或使用临时目录与隔离夹具保持确定性。
|
|
62
|
+
|
|
63
|
+
## Mock 原则
|
|
64
|
+
|
|
65
|
+
- 优先测试真实纯函数。
|
|
66
|
+
- Mock 系统边界,不 Mock 被测模块内部每个调用。
|
|
67
|
+
- 测试行为与输出,不锁死实现步骤。
|
|
68
|
+
- 不因 Mock 方便而跳过关键集成测试。
|
|
69
|
+
- 使用小而可读的夹具。
|
|
70
|
+
|
|
71
|
+
## 快照
|
|
72
|
+
|
|
73
|
+
快照适合结构稳定、人工审查有价值的输出。避免巨型快照、频繁无脑更新和对动态数据的快照。
|
|
74
|
+
|
|
75
|
+
## 测试代码质量
|
|
76
|
+
|
|
77
|
+
测试也是生产资产:
|
|
78
|
+
|
|
79
|
+
- 命名清晰。
|
|
80
|
+
- 无隐藏共享状态。
|
|
81
|
+
- 失败信息可诊断。
|
|
82
|
+
- 夹具具有领域含义。
|
|
83
|
+
- 清理临时资源。
|
|
84
|
+
- 不复制大量生产实现来计算期望值。
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# React 与前端规范
|
|
2
|
+
|
|
3
|
+
## 组件职责
|
|
4
|
+
|
|
5
|
+
组件输入由 Props 明确表达,渲染尽量纯粹。复杂功能按需拆分:
|
|
6
|
+
|
|
7
|
+
- 数据获取与缓存。
|
|
8
|
+
- 业务状态编排。
|
|
9
|
+
- 领域交互。
|
|
10
|
+
- 视觉展示。
|
|
11
|
+
|
|
12
|
+
组件名称使用具体领域语义:
|
|
13
|
+
|
|
14
|
+
- `WorkspaceReconnectDialog`
|
|
15
|
+
- `TerminalPermissionBanner`
|
|
16
|
+
- `PaymentMethodPanel`
|
|
17
|
+
|
|
18
|
+
避免 `DataComponent`、`CommonModal`、`GenericPanel`。
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
type WorkspaceCardProps = {
|
|
24
|
+
workspace: WorkspaceSummary
|
|
25
|
+
isSelected: boolean
|
|
26
|
+
onSelect(workspaceId: string): void
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
要求:
|
|
31
|
+
|
|
32
|
+
- 使用 `XxxProps`。
|
|
33
|
+
- 布尔 Props 使用 `is`、`has`、`can`、`should`。
|
|
34
|
+
- 事件 Props 使用 `onXxx`。
|
|
35
|
+
- 避免大型万能对象和多个隐式控制模式的布尔值。
|
|
36
|
+
- 复杂互斥状态使用联合类型。
|
|
37
|
+
- 是否使用 `React.FC` 按仓库统一规则,不混用。
|
|
38
|
+
|
|
39
|
+
## Hook
|
|
40
|
+
|
|
41
|
+
- 自定义 Hook 以 `use` 开头。
|
|
42
|
+
- 一个 Hook 处理一个可命名职责。
|
|
43
|
+
- Effect 依赖完整,不通过关闭规则规避。
|
|
44
|
+
- Effect 创建资源时返回清理函数。
|
|
45
|
+
- 返回多个独立值时优先具名对象;稳定二元关系可用元组。
|
|
46
|
+
- 避免把普通纯函数包装成 Hook。
|
|
47
|
+
|
|
48
|
+
## 状态管理
|
|
49
|
+
|
|
50
|
+
- 状态尽量靠近使用位置。
|
|
51
|
+
- 只有多个远距离调用方共享时才提升。
|
|
52
|
+
- Store 按领域切片,不创建单一巨型 Store。
|
|
53
|
+
- Selector 尽量窄,避免组件订阅整个状态树。
|
|
54
|
+
- 派生数据优先计算,不重复存储。
|
|
55
|
+
- 服务端状态与本地 UI 状态分开管理。
|
|
56
|
+
|
|
57
|
+
## Effect
|
|
58
|
+
|
|
59
|
+
Effect 用于与外部系统同步,不用于替代普通计算。检查:
|
|
60
|
+
|
|
61
|
+
- 是否可在渲染时直接派生。
|
|
62
|
+
- 是否需要取消旧请求。
|
|
63
|
+
- 是否存在竞态和过期响应。
|
|
64
|
+
- 是否清理监听器、Timer 和订阅。
|
|
65
|
+
- 是否因对象引用变化导致无意义重复执行。
|
|
66
|
+
|
|
67
|
+
## 性能
|
|
68
|
+
|
|
69
|
+
- 不因为“可能更快”滥用 `memo`、`useMemo`、`useCallback`。
|
|
70
|
+
- 优化针对已识别瓶颈。
|
|
71
|
+
- 长列表使用虚拟化。
|
|
72
|
+
- 高频事件使用调度、批处理、节流或防抖。
|
|
73
|
+
- 避免在热渲染路径创建昂贵对象。
|
|
74
|
+
- 关键优化应有测试、测量或简短原因说明。
|
|
75
|
+
|
|
76
|
+
## 可访问性
|
|
77
|
+
|
|
78
|
+
- 优先语义化 HTML。
|
|
79
|
+
- 交互元素支持键盘。
|
|
80
|
+
- 图标按钮有可访问名称。
|
|
81
|
+
- 表单控件有 Label 和错误关联。
|
|
82
|
+
- 焦点管理可预测。
|
|
83
|
+
- 不用颜色作为唯一状态表达。
|
|
84
|
+
- 弹窗、菜单和提示遵守相应 ARIA 交互模式。
|
|
85
|
+
|
|
86
|
+
## 浏览器边界
|
|
87
|
+
|
|
88
|
+
- 验证 URL、消息、Storage 和第三方脚本输入。
|
|
89
|
+
- 避免不安全原始 HTML。
|
|
90
|
+
- 不把秘密放入前端 Bundle。
|
|
91
|
+
- 浏览器代码不导入 Node 专属模块,除非平台明确提供安全桥接。
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Node.js、CLI 与跨平台规范
|
|
2
|
+
|
|
3
|
+
## Node 内置模块
|
|
4
|
+
|
|
5
|
+
使用 `node:` 前缀:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { readFile } from 'node:fs/promises'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 路径
|
|
13
|
+
|
|
14
|
+
使用 `node:path` 组合和归一化路径,不手工拼接分隔符:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
const configPath = path.join(rootPath, 'config', 'app.json')
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
涉及安全或相等判断时考虑:
|
|
21
|
+
|
|
22
|
+
- Windows 盘符和分隔符。
|
|
23
|
+
- UNC 路径。
|
|
24
|
+
- 大小写敏感差异。
|
|
25
|
+
- 符号链接。
|
|
26
|
+
- 相对路径和路径遍历。
|
|
27
|
+
- 规范化前后的边界检查顺序。
|
|
28
|
+
|
|
29
|
+
## CLI 分层
|
|
30
|
+
|
|
31
|
+
推荐拆分:
|
|
32
|
+
|
|
33
|
+
- `parse-cli-arguments.ts`
|
|
34
|
+
- `validate-cli-options.ts`
|
|
35
|
+
- `run-export-command.ts`
|
|
36
|
+
- `render-cli-error.ts`
|
|
37
|
+
|
|
38
|
+
要求:
|
|
39
|
+
|
|
40
|
+
- 参数解析与业务执行分离。
|
|
41
|
+
- 正常机器输出写 `stdout`,错误写 `stderr`。
|
|
42
|
+
- 明确定义退出码。
|
|
43
|
+
- 支持 `--help` 和 `--version`。
|
|
44
|
+
- 底层领域代码不直接调用 `process.exit()`。
|
|
45
|
+
- 信号处理和资源清理集中管理。
|
|
46
|
+
|
|
47
|
+
## 环境变量
|
|
48
|
+
|
|
49
|
+
在启动边界一次解析、验证和标准化:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
type AppEnvironment = {
|
|
53
|
+
port: number
|
|
54
|
+
logLevel: LogLevel
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function loadEnvironment(
|
|
58
|
+
source: NodeJS.ProcessEnv
|
|
59
|
+
): AppEnvironment {
|
|
60
|
+
// ...
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
业务代码不应在各处直接读取 `process.env`。
|
|
65
|
+
|
|
66
|
+
## 子进程
|
|
67
|
+
|
|
68
|
+
- 优先使用参数数组,不拼接 Shell 字符串。
|
|
69
|
+
- 必须拼接时按目标 Shell 正确转义。
|
|
70
|
+
- 处理超时、取消、退出码、信号和输出上限。
|
|
71
|
+
- 避免将不可信输入直接作为命令或参数。
|
|
72
|
+
- 明确清理孤儿进程。
|
|
73
|
+
|
|
74
|
+
## 文件和流
|
|
75
|
+
|
|
76
|
+
- 大文件优先流式处理。
|
|
77
|
+
- 关闭文件句柄和流。
|
|
78
|
+
- 处理背压。
|
|
79
|
+
- 临时文件使用隔离目录并在失败路径清理。
|
|
80
|
+
- 写关键文件时考虑原子替换和崩溃恢复。
|
|
81
|
+
|
|
82
|
+
## 跨平台
|
|
83
|
+
|
|
84
|
+
跨平台逻辑应集中在适配器中。测试至少覆盖:
|
|
85
|
+
|
|
86
|
+
- 路径和换行符。
|
|
87
|
+
- Shell 参数引用。
|
|
88
|
+
- 文件权限和可执行位。
|
|
89
|
+
- 信号差异。
|
|
90
|
+
- 大小写和文件锁行为。
|
|
91
|
+
|
|
92
|
+
不要把平台判断散落在整个业务代码中。
|