@bovinphang/frontend-craft 2.5.0 → 2.7.0

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.
Files changed (156) hide show
  1. package/.claude-plugin/marketplace.json +7 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +77 -1
  4. package/CHANGELOG.zh-CN.md +77 -1
  5. package/CONTRIBUTING.md +15 -10
  6. package/CONTRIBUTING.zh-CN.md +15 -10
  7. package/README.md +69 -43
  8. package/README.openclaw.md +11 -9
  9. package/README.openclaw.zh-CN.md +11 -9
  10. package/README.zh-CN.md +69 -43
  11. package/agents/fec-typescript-reviewer.md +1 -1
  12. package/commands/fec-doc-sync.md +7 -6
  13. package/dist/bin/frontend-craft.js +30 -27
  14. package/docs/example-prompts.md +82 -69
  15. package/docs/ja-JP/README.md +110 -84
  16. package/docs/ko-KR/README.md +100 -74
  17. package/docs/project-structure.md +8 -4
  18. package/docs/runtimes/antigravity.md +1 -1
  19. package/docs/runtimes/augment.md +1 -1
  20. package/docs/runtimes/claude.md +16 -10
  21. package/docs/runtimes/claude.zh-CN.md +16 -10
  22. package/docs/runtimes/cline.md +1 -1
  23. package/docs/runtimes/codebuddy.md +1 -1
  24. package/docs/runtimes/codex.md +1 -1
  25. package/docs/runtimes/copilot.md +1 -1
  26. package/docs/runtimes/cursor.md +1 -1
  27. package/docs/runtimes/gemini.md +1 -1
  28. package/docs/runtimes/kilo.md +1 -1
  29. package/docs/runtimes/openclaw.md +1 -1
  30. package/docs/runtimes/opencode.md +1 -1
  31. package/docs/runtimes/qoder.md +1 -1
  32. package/docs/runtimes/trae.md +1 -1
  33. package/docs/runtimes/windsurf.md +1 -1
  34. package/docs/zh-CN/example-prompts.md +82 -69
  35. package/docs/zh-CN/project-structure.md +8 -4
  36. package/docs/zh-TW/README.md +88 -62
  37. package/openclaw.plugin.json +1 -1
  38. package/package.json +3 -3
  39. package/skills/eval_queries.json +179 -56
  40. package/skills/fec-accessibility-check/SKILL.md +1 -1
  41. package/skills/fec-alchemy/SKILL.md +74 -0
  42. package/skills/fec-alchemy/assets/absorption-plan-template.md +47 -0
  43. package/skills/fec-alchemy/assets/intake-template.md +55 -0
  44. package/skills/fec-alchemy/assets/review-checklist.md +31 -0
  45. package/skills/fec-alchemy/references/methodology.md +94 -0
  46. package/skills/fec-alchemy/references/originality-and-licensing.md +57 -0
  47. package/skills/fec-backend-requirements-handoff/SKILL.md +45 -0
  48. package/skills/fec-browser-storage/SKILL.md +1 -1
  49. package/skills/fec-canvas-threejs/SKILL.md +1 -1
  50. package/skills/fec-code-review/SKILL.md +11 -3
  51. package/skills/fec-data-fetching/SKILL.md +15 -15
  52. package/skills/fec-data-fetching/references/query-patterns.md +27 -1
  53. package/skills/fec-debug-framework/SKILL.md +14 -19
  54. package/skills/fec-debug-framework/references/report-template.md +58 -0
  55. package/skills/fec-doc-sync/SKILL.md +19 -17
  56. package/skills/fec-drawio-studio/SKILL.md +69 -0
  57. package/skills/fec-drawio-studio/data/THIRD_PARTY_NOTICES.md +10 -0
  58. package/skills/fec-drawio-studio/data/brand-icons.json +878 -0
  59. package/skills/fec-drawio-studio/data/shape-index.json.gz +0 -0
  60. package/skills/fec-drawio-studio/references/data-residency.md +27 -0
  61. package/skills/fec-drawio-studio/references/diagram-patterns.md +41 -0
  62. package/skills/fec-drawio-studio/references/layout-and-export.md +57 -0
  63. package/skills/fec-drawio-studio/references/troubleshooting.md +29 -0
  64. package/skills/fec-drawio-studio/references/xml-and-mermaid.md +54 -0
  65. package/skills/fec-drawio-studio/scripts/brand-symbols.mjs +99 -0
  66. package/skills/fec-drawio-studio/scripts/diagram-lint.mjs +143 -0
  67. package/skills/fec-drawio-studio/scripts/diagram-url.mjs +102 -0
  68. package/skills/fec-drawio-studio/scripts/layout-graph.mjs +107 -0
  69. package/skills/fec-drawio-studio/scripts/png-embed-fix.mjs +26 -0
  70. package/skills/fec-drawio-studio/scripts/scan-go-packages.mjs +36 -0
  71. package/skills/fec-drawio-studio/scripts/scan-js-modules.mjs +52 -0
  72. package/skills/fec-drawio-studio/scripts/scan-python-classes.mjs +30 -0
  73. package/skills/fec-drawio-studio/scripts/scan-python-modules.mjs +55 -0
  74. package/skills/fec-drawio-studio/scripts/scan-rust-modules.mjs +35 -0
  75. package/skills/fec-drawio-studio/scripts/scan-ts-modules.mjs +7 -0
  76. package/skills/fec-drawio-studio/scripts/shape-query.mjs +81 -0
  77. package/skills/fec-drawio-studio/scripts/studio-core.mjs +139 -0
  78. package/skills/fec-drawio-studio/styles/built-in/corporate.json +49 -0
  79. package/skills/fec-drawio-studio/styles/built-in/default.json +49 -0
  80. package/skills/fec-drawio-studio/styles/built-in/handdrawn.json +49 -0
  81. package/skills/fec-drawio-studio/styles/schema.json +112 -0
  82. package/skills/fec-e2e-testing/SKILL.md +5 -3
  83. package/skills/fec-e2e-testing/references/e2e-ci-reporting.md +62 -0
  84. package/skills/fec-e2e-testing/references/e2e-special-scenarios.md +52 -0
  85. package/skills/fec-e2e-testing/references/e2e-visual-regression.md +60 -0
  86. package/skills/fec-form-handling/SKILL.md +11 -11
  87. package/skills/fec-form-handling/references/advanced-form-patterns.md +34 -5
  88. package/skills/fec-image-generation/SKILL.md +56 -0
  89. package/skills/fec-image-generation/references/artifact-routing.md +80 -0
  90. package/skills/fec-image-generation/references/diagram-workflows.md +43 -0
  91. package/skills/fec-image-generation/references/png-qa-autofix.md +30 -0
  92. package/skills/fec-image-generation/scripts/png-qa.mjs +431 -0
  93. package/skills/fec-implement-from-design/SKILL.md +9 -2
  94. package/skills/fec-legacy-to-modern-migration/SKILL.md +29 -163
  95. package/skills/fec-legacy-to-modern-migration/references/migration-execution-checklist.md +110 -0
  96. package/skills/fec-legacy-to-modern-migration/references/migration-strategy-and-mapping.md +48 -0
  97. package/skills/fec-legacy-web-standard/SKILL.md +1 -1
  98. package/skills/fec-list-virtualization/SKILL.md +3 -3
  99. package/skills/fec-list-virtualization/references/virtualization-patterns.md +32 -4
  100. package/skills/fec-motion-interaction/SKILL.md +7 -0
  101. package/skills/fec-nextjs-project-standard/SKILL.md +7 -1
  102. package/skills/fec-performance-optimization/SKILL.md +9 -1
  103. package/skills/fec-performance-optimization/references/framework-performance-patterns.md +38 -0
  104. package/skills/fec-performance-optimization/references/report-template.md +59 -0
  105. package/skills/fec-pwa-implementation/SKILL.md +3 -4
  106. package/skills/fec-react-project-standard/SKILL.md +12 -4
  107. package/skills/fec-react-project-standard/references/react-performance-patterns.md +35 -0
  108. package/skills/fec-react-project-standard/references/react-project-structure.md +197 -0
  109. package/skills/fec-react-project-standard/references/react-quality-patterns.md +131 -0
  110. package/skills/fec-react-project-standard/references/react-runtime-patterns.md +293 -0
  111. package/skills/fec-refactor-clean/SKILL.md +4 -1
  112. package/skills/fec-refactor-clean/references/report-template.md +42 -0
  113. package/skills/fec-responsive-layout/references/responsive-layout-patterns.md +11 -0
  114. package/skills/fec-security-review/SKILL.md +3 -3
  115. package/skills/fec-source-driven-development/SKILL.md +26 -0
  116. package/skills/fec-state-management/SKILL.md +1 -1
  117. package/skills/fec-storybook-component-doc/SKILL.md +2 -2
  118. package/skills/fec-tailwind-design-system/references/tailwind-system-patterns.md +5 -1
  119. package/skills/fec-typescript-project-standard/SKILL.md +54 -0
  120. package/skills/{fec-typescript-type-safety → fec-typescript-project-standard}/references/type-safety-patterns.md +1 -1
  121. package/skills/{fec-typescript-type-safety/SKILL.md → fec-typescript-project-standard/references/type-safety.md} +1 -10
  122. package/skills/fec-ui-design/SKILL.md +26 -8
  123. package/skills/fec-ui-design/data/style-archetypes.json +40 -0
  124. package/skills/fec-ui-design/data/ux-quality-rules.json +35 -0
  125. package/skills/fec-ui-design/references/design-intelligence.md +66 -6
  126. package/skills/fec-ui-design/references/pre-delivery-checklist.md +6 -0
  127. package/skills/fec-ui-design/scripts/design-system.mjs +119 -1
  128. package/skills/fec-validation-fix/SKILL.md +5 -2
  129. package/skills/fec-validation-fix/references/report-template.md +43 -0
  130. package/skills/fec-vue3-project-standard/SKILL.md +12 -3
  131. package/skills/fec-vue3-project-standard/references/vue3-composables-routing.md +163 -0
  132. package/skills/fec-vue3-project-standard/references/vue3-performance-patterns.md +13 -0
  133. package/skills/fec-vue3-project-standard/references/vue3-project-structure.md +177 -0
  134. package/skills/fec-vue3-project-standard/references/vue3-state-api-quality.md +216 -0
  135. package/skills/fec-web-video-presentation/SKILL.md +61 -0
  136. package/skills/fec-web-video-presentation/data/starter-themes.json +59 -0
  137. package/skills/fec-web-video-presentation/references/chapter-craft.md +37 -0
  138. package/skills/fec-web-video-presentation/references/content-plan.md +38 -0
  139. package/skills/fec-web-video-presentation/references/recording-and-audio.md +33 -0
  140. package/skills/fec-web-video-presentation/references/theme-system.md +36 -0
  141. package/skills/fec-web-video-presentation/scripts/create-video-presentation.mjs +430 -0
  142. package/skills/fec-web-workers/SKILL.md +3 -4
  143. package/skills/metadata.json +381 -168
  144. package/skills/relations.json +136 -25
  145. package/templates/shared/rules/fec-ci-cd.md +20 -108
  146. package/templates/shared/rules/fec-design-system.md +47 -223
  147. package/templates/shared/rules/fec-error-handling.md +35 -179
  148. package/templates/shared/rules/fec-i18n.md +43 -91
  149. package/templates/shared/rules/fec-refactoring.md +4 -0
  150. package/templates/shared/rules/fec-rendering-patterns.md +28 -171
  151. package/templates/shared/rules/fec-responsive-design.md +34 -211
  152. package/templates/shared/rules/fec-state-management.md +41 -144
  153. package/templates/shared/rules/fec-typescript.md +47 -290
  154. package/skills/fec-e2e-testing/references/e2e-advanced.md +0 -176
  155. package/skills/fec-react-project-standard/references/react-project-details.md +0 -642
  156. package/skills/fec-vue3-project-standard/references/vue3-project-details.md +0 -547
@@ -1,6 +1,6 @@
1
1
  # TypeScript / JavaScript 规则
2
2
 
3
- 编写、修改或评审 `.ts`、`.tsx`、`.js`、`.jsx` 时应用本文件。注释风格另见 `fec-code-comments.md`;E2E 与校验流程另见 `fec-testing.md`。
3
+ 编写、修改或评审 `.ts`、`.tsx`、`.js`、`.jsx` 时应用本文件。本文只保留项目常驻硬约束;复杂类型建模、`tsconfig` 分层、声明产物、DTO / view model 边界、类型测试与发布入口设计,交给 `fec-typescript-project-standard` skill 或专项评审处理。注释风格另见 `fec-code-comments.md`;E2E 与校验流程另见 `fec-testing.md`。
4
4
 
5
5
  ## 类型与接口
6
6
 
@@ -9,347 +9,104 @@
9
9
  ### 对外导出的 API
10
10
 
11
11
  - 对**导出**的函数、共享工具函数、公开类方法,写明参数与返回值类型。
12
- - **局部**变量在类型显而易见时交给 TypeScript 推断。
13
- - 重复出现的内联对象形状抽成具名 `interface` 或 `type`。
14
-
15
- ```typescript
16
- // 错误:导出函数缺少显式类型
17
- export function formatUser(user) {
18
- return `${user.firstName} ${user.lastName}`;
19
- }
20
-
21
- // 正确:对外 API 显式标注
22
- interface User {
23
- firstName: string;
24
- lastName: string;
25
- }
26
-
27
- export function formatUser(user: User): string {
28
- return `${user.firstName} ${user.lastName}`;
29
- }
30
- ```
12
+ - **局部**变量在类型显而易见时交给 TypeScript 推断,不为显而易见的中间变量重复标注。
13
+ - 重复出现的内联对象形状抽成具名 `interface` 或 `type`,避免同一契约散落在多个签名中。
14
+ - 外部数据、API DTO、路由参数、表单值与组件 props 的边界要显式命名;复杂建模分流到 `fec-typescript-project-standard`。
31
15
 
32
16
  ### `interface` 与 `type`
33
17
 
34
18
  - 可能被扩展或 `implements` 的**对象形状**优先用 `interface`。
35
19
  - **联合、交叉、元组、映射类型、工具类型组合**用 `type`。
36
- - 优先**字符串字面量联合**;仅在互操作或团队统一要求时使用 `enum`。
37
-
38
- ```typescript
39
- interface User {
40
- id: string;
41
- email: string;
42
- }
43
-
44
- type UserRole = "admin" | "member";
45
- type UserWithRole = User & { role: UserRole };
46
- ```
20
+ - 状态、类型、角色等有限业务取值优先用字符串字面量联合;仅在互操作或团队统一要求时使用 `enum`。
47
21
 
48
22
  ### 函数参数:复杂类型宜具名
49
23
 
50
- - 参数上的**复杂联合**、**内联对象类型**、**较复杂的回调签名**等,应**优先**提取为具名 `type` / `interface`,再在函数签名中引用,便于阅读、复测与重构。
51
- - **仅当**类型**简单**、**短小**、一眼可读,且**明显无复用**价值时,允许在参数位置内联(如单独的 `string`、`number`、`boolean` 等)。
52
-
53
- ```typescript
54
- // 不推荐:联合与可选散落在参数上,语义不突出
55
- function getUserInfo(id: string | number | undefined) {}
56
-
57
- // 推荐:具名类型表达「用户标识」语义,可选更自然
58
- type UserId = string | number;
59
- function getUserInfo(id?: UserId) {}
60
- ```
61
-
62
- ```typescript
63
- // 不推荐:内联联合对象冗长,难复用、难单测描述
64
- function send(data: string | { content: string; type: "text" | "html" }) {}
65
-
66
- // 推荐:消息载荷单一真源
67
- type MessagePayload =
68
- | string
69
- | {
70
- content: string;
71
- type: "text" | "html";
72
- };
73
-
74
- function send(data: MessagePayload) {}
75
- ```
24
+ - 参数上的**复杂联合**、**内联对象类型**、**较复杂的回调签名**等,应优先提取为具名 `type` / `interface`,再在函数签名中引用。
25
+ - 仅当类型简单、短小、一眼可读,且明显无复用价值时,允许在参数位置内联。
26
+ - 回调参数与返回值必须表达清楚;不要用 `Function`、宽泛对象或隐式 `any` 承接业务契约。
76
27
 
77
28
  ### 避免 `any`
78
29
 
79
- - 业务代码中避免 `any`。
80
- - 外部或不可信数据用 `unknown`,再安全收窄。
81
- - 类型随调用方变化时用泛型。
82
-
83
- ```typescript
84
- // 错误:any 取消类型检查
85
- function getErrorMessage(error: any) {
86
- return error.message;
87
- }
88
-
89
- // 正确:unknown 强制收窄
90
- function getErrorMessage(error: unknown): string {
91
- if (error instanceof Error) {
92
- return error.message;
93
- }
94
- return "Unexpected error";
95
- }
96
- ```
30
+ - 业务代码中避免 `any`;已有遗留 `any` 不随手扩散。
31
+ - 外部或不可信数据用 `unknown`,通过 `typeof`、`in`、`instanceof`、schema parse 或自定义 predicate 安全收窄。
32
+ - 类型随调用方变化时用泛型,但不要为简单场景引入难以理解的泛型层。
33
+ - `as` 类型断言只用于明确的边界互操作或已验证收窄后的补充表达,不用于压制类型错误。
97
34
 
98
35
  ### React 组件 Props
99
36
 
100
- - 用具名 `interface` 或 `type` 定义 props。
101
- - 回调 props 写清参数与返回值。
102
- - 无特殊理由不使用 `React.FC`(避免隐式 `children` 等差异)。
103
-
104
- ```typescript
105
- interface User {
106
- id: string;
107
- email: string;
108
- }
109
-
110
- interface UserCardProps {
111
- user: User;
112
- onSelect: (id: string) => void;
113
- }
114
-
115
- function UserCard({ user, onSelect }: UserCardProps) {
116
- return <button onClick={() => onSelect(user.id)}>{user.email}</button>;
117
- }
118
- ```
37
+ - 用具名 `interface` 或 `type` 定义 props,复杂公共 props 分流到类型模块。
38
+ - 回调 props 写清参数与返回值;事件 payload 不用裸对象长期内联。
39
+ - 无特殊理由不使用 `React.FC`,避免隐式 `children` 等差异。
40
+ - TSX 泛型、复杂组件 props 或外部 DTO 映射问题,交给 React 规则与 `fec-typescript-project-standard` 共同收敛。
119
41
 
120
42
  ## 单文件规模与模块拆分
121
43
 
122
- - `.ts` / `.tsx` / `.js` / `.jsx` 单文件建议控制在 **约 300 行以内**。该阈值是可维护性与评审效率的经验上限,不是机械的硬限制。
123
- - 当文件明显超过该规模且承担多重职责时,应优先按职责拆分:如数据访问、业务规则、视图渲染、适配层、常量与映射。
124
- - 超阈值优先提取:纯函数、子组件、自定义 Hook、`*.types.ts` 类型模块、常量表,不要仅为压行数做无意义切分。
44
+ - `.ts` / `.tsx` / `.js` / `.jsx` 单文件建议控制在**约 300 行以内**。该阈值是可维护性与评审效率的经验上限,不是机械硬限制。
45
+ - 当文件明显超过该规模且承担多重职责时,应优先按职责拆分:数据访问、业务规则、视图渲染、适配层、常量与映射、类型定义。
46
+ - 超阈值优先提取纯函数、子组件、自定义 Hook、`*.types.ts` 类型模块、常量表;不要仅为压行数做无意义切分。
125
47
  - 可接受例外:生成代码、极薄的 re-export 聚合文件、经团队评审确认的高内聚模块;例外建议在文件头简短注明原因。
126
48
 
127
49
  ### 仍为 JavaScript 的文件
128
50
 
129
- - 在 `.js` / `.jsx` 中,若短期无法迁 TS,可用 **JSDoc** 补类型,并与运行时行为一致。
130
-
131
- ```javascript
132
- /**
133
- * @param {{ firstName: string, lastName: string }} user
134
- * @returns {string}
135
- */
136
- export function formatUser(user) {
137
- return `${user.firstName} ${user.lastName}`;
138
- }
139
- ```
51
+ - 在 `.js` / `.jsx` 中,若短期无法迁 TS,可用 JSDoc 补类型,并与运行时行为一致。
52
+ - 不为迁移方便引入新的隐式全局、宽松对象或未验证外部输入。
140
53
 
141
54
  ## 禁止 Magic Number / Magic String
142
55
 
143
- - **业务代码中禁止**使用**无语义**的硬编码数字或字符串(如 `1`、`2`、`3`、`"1"`、`"2"`、`"3"`)直接表示**状态、类型、标识或业务含义**(含 `if`/`switch`/赋值与 API 字段映射等)。
144
- - **固定且有限的取值范围**须在单一真源处定义,并在全仓引用名称,避免裸值散落:
145
- - **`enum`**(与后端或协议对齐、或团队明确约定时使用;注意字符串 enum、const enum 与打包/tree-shaking 策略);
146
- - **`as const` 常量对象**(常与 `typeof` / `keyof` 推导联合类型,适合前端主路径);
147
- - **字面量联合类型**(`type Status = "a" | "b"`)并与上面对象或 map 配套,保证调用处可收窄、可重构。
148
- - **不属本条**的典型例外(仍应保持可读):纯算法下标、 obvious 的 `0`/`1` 长度判断、与业务无关的 UI 刻度若已有设计 Token 则改走 `fec-design-system.md`。
149
-
150
- ```typescript
151
- // 不佳:业务语义依赖裸数字 / 裸字符串
152
- function label(status: number) {
153
- if (status === 1) return "待支付";
154
- if (status === 2) return "已支付";
155
- return "未知";
156
- }
157
- if (user.role === "3") {
158
- /* ... */
159
- }
160
-
161
- // 更佳:字面量联合 + as const 常量对象(或团队约定的 enum)
162
- type OrderStatus = "pending" | "paid" | "cancelled";
163
- const ORDER_STATUS = {
164
- Pending: "pending",
165
- Paid: "paid",
166
- Cancelled: "cancelled",
167
- } as const satisfies Record<string, OrderStatus>;
168
-
169
- function label(status: OrderStatus) {
170
- if (status === ORDER_STATUS.Pending) return "待支付";
171
- if (status === ORDER_STATUS.Paid) return "已支付";
172
- return "已取消";
173
- }
174
- ```
56
+ - **业务代码中禁止**使用**无语义**的硬编码数字或字符串直接表示状态、类型、标识或业务含义,包括 `if` / `switch` / 赋值 / API 字段映射。
57
+ - 固定且有限的取值范围须在单一真源处定义,并在全仓引用名称,避免裸值散落。
58
+ - 前端主路径优先使用 `as const` 常量对象配合字面量联合;与后端协议或团队约定强绑定时可使用 `enum`。
59
+ - 不属本条的典型例外仍应保持可读:纯算法下标、明显的 `0` / `1` 长度判断、与业务无关的 UI 刻度;视觉值若已有设计 Token,应改走 `fec-design-system.md`。
175
60
 
176
61
  ## 不可变更新
177
62
 
178
- 优先用展开运算符合并新对象,避免直接改写入参。
179
-
180
- ```typescript
181
- interface User {
182
- id: string;
183
- name: string;
184
- }
185
-
186
- // 错误:修改原对象
187
- function updateUser(user: User, name: string): User {
188
- user.name = name;
189
- return user;
190
- }
191
-
192
- // 正确:返回新对象
193
- function updateUser(user: Readonly<User>, name: string): User {
194
- return { ...user, name };
195
- }
196
- ```
63
+ - 优先返回新对象或新数组,避免直接改写入参、props、store 快照或缓存对象。
64
+ - 对不应被修改的数据优先建模为 `readonly` / `Readonly<T>`。
65
+ - 大型嵌套更新应使用项目既有状态方案或清晰的 reducer / helper,不在组件中堆叠临时可变逻辑。
197
66
 
198
67
  ## 异步与错误处理
199
68
 
200
- 使用 `async/await` 与 `try/catch`,在 `catch` 中将错误视为 `unknown` 再收窄。
201
-
202
- ```typescript
203
- interface User {
204
- id: string;
205
- email: string;
206
- }
207
-
208
- declare function riskyOperation(userId: string): Promise<User>;
209
-
210
- function getErrorMessage(error: unknown): string {
211
- if (error instanceof Error) {
212
- return error.message;
213
- }
214
- return "Unexpected error";
215
- }
216
-
217
- const logger = {
218
- error: (message: string, error: unknown) => {
219
- // 替换为项目内的日志实现(如 pino、winston 等)
220
- },
221
- };
222
-
223
- async function loadUser(userId: string): Promise<User> {
224
- try {
225
- return await riskyOperation(userId);
226
- } catch (error: unknown) {
227
- logger.error("Operation failed", error);
228
- throw new Error(getErrorMessage(error));
229
- }
230
- }
231
- ```
69
+ - 使用 `async` / `await` 与明确的错误边界;不要吞掉 promise rejection。
70
+ - `catch` 中将错误视为 `unknown` 再收窄,统一映射为用户可见错误、日志错误或调用方可处理的领域错误。
71
+ - API、认证、上传、支付等跨边界错误遵循 `fec-api-layer.md`、`fec-error-handling.md` 和安全规则,不在业务组件中散落裸处理。
232
72
 
233
73
  ## 输入校验
234
74
 
235
- 对外部输入(表单、API、URL 参数等)宜用 **Zod**(或项目选用的同类库)做模式校验,并用 `z.infer` 推导类型。
236
-
237
- ```typescript
238
- import { z } from "zod";
239
-
240
- const userSchema = z.object({
241
- email: z.string().email(),
242
- age: z.number().int().min(0).max(150),
243
- });
244
-
245
- type UserInput = z.infer<typeof userSchema>;
246
-
247
- const validated: UserInput = userSchema.parse(input);
248
- ```
75
+ - 外部输入(表单、API、URL 参数、localStorage、postMessage、第三方 SDK 回调等)必须在边界处校验或收窄。
76
+ - 可使用 Zod、Valibot、Yup 或项目选用的同类 schema 工具;不要把具体库作为无条件新依赖引入。
77
+ - schema 推导类型可作为输入类型单一真源;复杂 DTO、领域模型与 UI view model 的分层交给 `fec-typescript-project-standard`。
249
78
 
250
79
  ## 类型资产分层与命名
251
80
 
252
- - 模块或特性专属类型使用 `*.types.ts`,并与实现文件同目录或同 feature 目录放置,例如 `user.types.ts`、`billing.types.ts`。
81
+ - 模块或特性专属类型使用 `*.types.ts`,并与实现文件同目录或同 feature 目录放置。
253
82
  - 全局与环境相关声明放在 `global.d.ts`、`env.d.ts` 或 `types/*.d.ts`,仅用于真全局或 ambient 声明,不将可模块化类型放入全局。
254
83
  - 仅用于类型的导入导出优先使用 `import type` 与 `export type`,减少值空间歧义并提升编译语义清晰度。
255
- - 与 API DTO 同源的类型,放在对应 feature 或 API 子目录的 `*.types.ts`,避免在页面或组件实现内散落大型匿名类型。
256
-
257
- ```typescript
258
- // user.types.ts
259
- export interface UserProfile {
260
- id: string;
261
- email: string;
262
- status: "active" | "disabled";
263
- }
264
-
265
- // user.service.ts
266
- import type { UserProfile } from "./user.types";
267
- export type { UserProfile };
268
- ```
84
+ - 与 API DTO 同源的类型,放在对应 feature 或 API 子目录,避免在页面或组件实现内散落大型匿名类型。
85
+ - `index.ts` 聚合导出应保持浅层且按 feature 边界组织,避免深层 barrel 引发循环依赖与不必要耦合。
269
86
 
270
87
  ## 工程化与惯用法补充
271
88
 
272
- - 使用**判别式联合**配合 `never` 穷尽检查,确保分支新增成员时编译期可发现遗漏。
273
- - 需要同时满足「字面量保留」与「结构校验」时优先使用 `satisfies`,再考虑类型断言。
274
- - 优先使用类型收窄(`typeof` / `in` / 自定义 predicate)而非 `as` 强转;`as` 应用于边界互操作而非消错。
275
- - 对不应被修改的数据优先建模为 `readonly` / `Readonly<T>`,与不可变更新规则协同。
89
+ - 需要同时满足字面量保留与结构校验时优先使用 `satisfies`,再考虑类型断言。
90
+ - 使用判别式联合表达清晰状态;关键分支需要穷尽性时用 `never` 检查。
276
91
  - 新业务代码默认采用 ES Module;`namespace` 与三斜线指令仅用于声明合并或遗留互操作场景。
277
- - `index.ts` 聚合导出应保持浅层且按 feature 边界组织,避免深层 barrel 引发循环依赖与不必要的耦合。
278
- - 扩展第三方类型时使用独立声明文件(如 `types/vendor-foo.d.ts`)并通过 `declare module "pkg"` 局部扩展,避免污染全局实现文件。
279
- - `tsconfig` 应保持 `strict` 族能力;若为兼容遗留场景需要放宽严格项,必须在评审中明确说明范围、风险与回收计划。
280
- - 可在消费项目使用 lint(如 `max-lines`)辅助识别超长文件,但规则设计应服务可维护性,而非追求机械达标。
92
+ - 扩展第三方类型时使用独立声明文件并通过局部 `declare module` 扩展,避免污染全局实现文件。
93
+ - `tsconfig`、package exports、声明文件、路径别名和 public API 类型属于 TypeScript 项目规范深水区,不在本规则内展开。
281
94
 
282
95
  ## 日志与 `console.log`
283
96
 
284
97
  - 生产路径避免遗留 `console.log`;使用项目统一的日志方案。
285
- - 可在保存后格式化、`tsc` 检查或提交前脚本中对 `console.log` 做提示或拦截(按团队工具链配置)。
286
-
287
- ## 常见模式
288
-
289
- ### 统一 API 响应形状(示例)
290
-
291
- ```typescript
292
- interface ApiResponse<T> {
293
- success: boolean;
294
- data?: T;
295
- error?: string;
296
- meta?: {
297
- total: number;
298
- page: number;
299
- limit: number;
300
- };
301
- }
302
- ```
303
-
304
- ### 自定义 Hook(示例)
305
-
306
- ```typescript
307
- export function useDebounce<T>(value: T, delay: number): T {
308
- const [debouncedValue, setDebouncedValue] = useState<T>(value);
309
-
310
- useEffect(() => {
311
- const handler = setTimeout(() => setDebouncedValue(value), delay);
312
- return () => clearTimeout(handler);
313
- }, [value, delay]);
314
-
315
- return debouncedValue;
316
- }
317
- ```
318
-
319
- ### 仓储接口(示例)
320
-
321
- ```typescript
322
- interface Repository<T> {
323
- findAll(filters?: Filters): Promise<T[]>;
324
- findById(id: string): Promise<T | null>;
325
- create(data: CreateDto): Promise<T>;
326
- update(id: string, data: UpdateDto): Promise<T>;
327
- delete(id: string): Promise<void>;
328
- }
329
- ```
98
+ - 调试日志提交前应删除,或按团队工具链通过 lint / hook / CI 提示。
330
99
 
331
100
  ## 密钥与敏感配置
332
101
 
333
- - **禁止**在源码中硬编码密钥、Token、私钥。
334
- - **必须**通过环境变量或构建期注入(如 `process.env.*`、`import.meta.env.*`,以项目脚手架为准),并在缺失时显式失败或降级策略清晰。
335
-
336
- ```typescript
337
- // 错误:硬编码密钥
338
- const apiKey = "sk-proj-xxxxx";
339
-
340
- // 正确:环境变量(Node 示例;Vite 等请用 import.meta.env 及 VITE_ 前缀约定)
341
- const apiKey = process.env.OPENAI_API_KEY;
342
- if (!apiKey) {
343
- throw new Error("OPENAI_API_KEY not configured");
344
- }
345
- ```
346
-
347
- 涉及认证、支付、上传等场景时,结合项目安全规范做专项评审。
102
+ - **禁止**在源码中硬编码密钥、Token、私钥或真实凭证示例。
103
+ - 必须通过环境变量或构建期注入读取配置,并在缺失时显式失败或提供清晰降级策略。
104
+ - 涉及认证、支付、上传、第三方脚本或敏感数据处理时,结合项目安全规范做专项评审。
348
105
 
349
106
  ## 与测试规则的关系
350
107
 
351
- 关键用户路径的端到端覆盖方式(Playwright、Cypress、Page Object 等)以 `fec-testing.md` 为准;本文件不重复展开 E2E 细则。
108
+ 类型改动影响 public API、DTO、外部输入收窄或关键业务分支时,应补充 typecheck、类型测试、组件测试或消费方 fixture。关键用户路径的端到端覆盖方式(Playwright、Cypress、Page Object 等)以 `fec-testing.md` 为准;本文件不重复展开 E2E 细则。
352
109
 
353
110
  ## 与 `typescript-reviewer` 子代理
354
111
 
355
- 对 **`.ts` / `.tsx` / `.js` / `.jsx`** 进行专项评审(先跑 typecheck/eslint、PR 合并就绪检查、分级结论)时,可委托插件内置的 **`typescript-reviewer`** 子代理;其报告默认写入 `reports/typescript-review-YYYY-MM-DD-HHmmss.md`,规则底线仍以本文件与项目 `CLAUDE.md` 为准。
112
+ 对 **`.ts` / `.tsx` / `.js` / `.jsx`** 进行专项评审(先跑 typecheck / eslint、PR 合并就绪检查、分级结论)时,可委托插件内置的 **`typescript-reviewer`** 子代理;其报告默认写入 `reports/typescript-review-YYYY-MM-DD-HHmmss.md`,规则底线仍以本文件与项目 `CLAUDE.md` 为准。
@@ -1,176 +0,0 @@
1
- # E2E 高级测试细节
2
-
3
- ## CI 集成(示例)
4
-
5
- ```yaml
6
- # .github/workflows/e2e.yml
7
- name: E2E Tests
8
- on: [push, pull_request]
9
-
10
- jobs:
11
- test:
12
- runs-on: ubuntu-latest
13
- steps:
14
- - uses: actions/checkout@v4
15
- - uses: actions/setup-node@v4
16
- with:
17
- node-version: 20
18
- - run: npm ci
19
- - run: npx playwright install --with-deps
20
- - run: npx playwright test
21
- env:
22
- CI: true
23
- BASE_URL: ${{ vars.STAGING_URL }}
24
- - uses: actions/upload-artifact@v4
25
- if: always()
26
- with:
27
- name: playwright-report
28
- path: playwright-report/
29
- retention-days: 30
30
- ```
31
-
32
- Cypress:固定 `CYPRESS_baseUrl` 或配置文件中的 `baseUrl`,失败截图/视频同样建议上传 artifact。
33
-
34
- ## E2E 报告模板(Markdown)
35
-
36
- 输出或归档测试报告时可采用下列结构,便于复盘:
37
-
38
- ```markdown
39
- # E2E 测试报告
40
-
41
- **日期:** YYYY-MM-DD HH:mm
42
- **耗时:** X 分 Y 秒
43
- **结果:** 通过 / 失败
44
-
45
- ## 摘要
46
-
47
- - 总计 X | 通过 Y | 失败 Z | 不稳定/跳过 说明
48
-
49
- ## 失败用例
50
-
51
- ### 用例名
52
-
53
- - **文件:** `tests/e2e/xxx.spec.ts:行号`
54
- - **错误:** 简述断言或超时信息
55
- - **截图/Trace:** 路径或 artifact 名称
56
- - **建议修复:** 可执行结论
57
-
58
- ## 产物
59
-
60
- - HTML 报告:`playwright-report/index.html`
61
- - Trace / 视频 / 截图:CI artifact 或本地 `test-results/`
62
- ```
63
-
64
- ## 特殊场景(按需)
65
-
66
- ### Web3 / 钱包注入(Playwright)
67
-
68
- 在 **`page.goto` 之前**通过 `context.addInitScript` 注入 mock,避免依赖真实插件:
69
-
70
- ```typescript
71
- test("连接钱包", async ({ page, context }) => {
72
- await context.addInitScript(() => {
73
- (window as unknown as { ethereum?: unknown }).ethereum = {
74
- isMetaMask: true,
75
- request: async ({ method }: { method: string }) => {
76
- if (method === "eth_requestAccounts")
77
- return ["0x1234567890123456789012345678901234567890"];
78
- if (method === "eth_chainId") return "0x1";
79
- return null;
80
- },
81
- };
82
- });
83
-
84
- await page.goto("/");
85
- await page.getByTestId("connect-wallet").click();
86
- await expect(page.getByTestId("wallet-address")).toContainText("0x1234");
87
- });
88
- ```
89
-
90
- 链 ID、账户列表与业务契约保持一致即可。
91
-
92
- ### 金融或高风险操作
93
-
94
- - **禁止**在真实生产环境执行真实资金操作;使用 **staging、mock 或 `test.skip`**。
95
- - 断言**预览金额、成功态**与**关键接口 200** 后再结束用例,超时给足(如链上确认场景)。
96
-
97
- ```typescript
98
- test("下单预览与成功态", async ({ page }) => {
99
- test.skip(process.env.NODE_ENV === "production", "生产环境跳过真实交易");
100
-
101
- await page.goto("/markets/demo");
102
- await page.getByTestId("position-yes").click();
103
- await page.getByTestId("trade-amount").fill("1.0");
104
-
105
- const preview = page.getByTestId("trade-preview");
106
- await expect(preview).toContainText("1.0");
107
-
108
- await page.getByTestId("confirm-trade").click();
109
- await page.waitForResponse(
110
- (resp) => resp.url().includes("/api/trade") && resp.status() === 200,
111
- { timeout: 30_000 },
112
- );
113
- await expect(page.getByTestId("trade-success")).toBeVisible();
114
- });
115
- ```
116
-
117
- ## 视觉回归测试
118
-
119
- 通过截图快照对比检测非预期的 UI 变化。适用于 CSS 重构、设计 Token 更新、组件改版等场景。
120
-
121
- ### 基础用法
122
-
123
- ```typescript
124
- import { test, expect } from "@playwright/test";
125
-
126
- test("首页布局与基线一致", async ({ page }) => {
127
- await page.goto("/");
128
- await page.waitForLoadState("networkidle");
129
-
130
- // 全页截图对比 — 首次运行自动生成基线
131
- await expect(page).toHaveScreenshot("homepage-full.png", {
132
- fullPage: true,
133
- maxDiffPixels: 100, // 允许的轻微像素差异(抗锯齿等)
134
- });
135
- });
136
-
137
- test("按钮组件视觉一致", async ({ page }) => {
138
- await page.goto("/components/buttons");
139
- const submitButton = page.getByTestId("submit-button");
140
- await expect(submitButton).toHaveScreenshot("submit-button.png");
141
- });
142
- ```
143
-
144
- ### 屏蔽动态内容
145
-
146
- 时间、随机 ID、第三方广告等动态元素会导致误报,使用 `mask` 屏蔽:
147
-
148
- ```typescript
149
- await expect(page).toHaveScreenshot("dashboard.png", {
150
- mask: [
151
- page.locator(".live-clock"),
152
- page.locator(".random-id"),
153
- page.locator(".ad-banner"),
154
- ],
155
- });
156
- ```
157
-
158
- ### 禁用动画
159
-
160
- CSS 动画会导致截图不一致,注入样式禁用动画后再截图:
161
-
162
- ```typescript
163
- await page.addStyleTag({
164
- content:
165
- "*, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; }",
166
- });
167
- await expect(page).toHaveScreenshot("animated-page.png");
168
- ```
169
-
170
- ### 基线管理
171
-
172
- - **首次运行**: `npx playwright test` 失败但自动生成基线到 `tests/` 目录
173
- - **更新基线**: UI 有意变更时 `npx playwright test --update-snapshots`
174
- - **CI 一致性**: 基线必须在与 CI 相同的 OS(Linux/Ubuntu)上生成,字体渲染在 macOS 与 Linux 间存在差异
175
- - **多浏览器**: 每个 project 独立生成基线(Chromium/Firefox/WebKit 渲染结果不同)
176
- - **基线文件**: 纳入 `.gitignore` 或 Git LFS 管理,避免仓库膨胀