mta-mcp 1.0.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.
- package/README.md +818 -0
- package/agents/_TEMPLATE.md +153 -0
- package/agents/flutter.agent.md +222 -0
- package/agents/i18n.agent.md +78 -0
- package/agents/logicflow.agent.md +97 -0
- package/agents/vue3.agent.md +176 -0
- package/agents/wechat-miniprogram.agent.md +89 -0
- package/bin/mta.cjs +132 -0
- package/common/i18n.md +385 -0
- package/common/typescript-strict.md +186 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +6493 -0
- package/dist/index.js.map +1 -0
- package/package.json +81 -0
- package/standards/README.md +194 -0
- package/standards/core/code-generation.md +421 -0
- package/standards/core/code-style.md +308 -0
- package/standards/core/dart-base.md +572 -0
- package/standards/core/mandatory-rules.md +103 -0
- package/standards/core/typescript-base.md +179 -0
- package/standards/frameworks/flutter-ui-system.md +497 -0
- package/standards/frameworks/flutter.md +1268 -0
- package/standards/frameworks/pinia.md +172 -0
- package/standards/frameworks/vue3-composition.md +779 -0
- package/standards/frameworks/wechat-miniprogram.md +2177 -0
- package/standards/libraries/element-plus.md +1128 -0
- package/standards/libraries/i18n.md +360 -0
- package/standards/libraries/logicflow.md +1007 -0
- package/standards/patterns/api-layer.md +187 -0
- package/standards/patterns/component-design.md +200 -0
- package/standards/patterns/design-system-restoration.md +570 -0
- package/standards/patterns/vue-api-mock-layer.md +958 -0
- package/standards/patterns/vue-css-nesting.md +604 -0
- package/standards/troubleshooting-cases/flutter/textfield-vertical-centering.md +107 -0
- package/standards/workflows/design-restoration-guide.md +164 -0
- package/standards/workflows/large-project-split.md +359 -0
- package/standards/workflows/problem-diagnosis.md +280 -0
- package/standards/workflows/textfield-centering-guide.md +157 -0
- package/templates/README.md +144 -0
- package/templates/common/types/_CONFIG.md +12 -0
- package/templates/common/types/api.ts +39 -0
- package/templates/common/types/common.ts +70 -0
- package/templates/config-templates/agents-section.md +9 -0
- package/templates/config-templates/custom-section.md +6 -0
- package/templates/config-templates/header.md +29 -0
- package/templates/config-templates/workflow-minimal.md +44 -0
- package/templates/copilot-instructions-mcp-optimized.md +158 -0
- package/templates/vue/api-layer/_CONFIG.md +145 -0
- package/templates/vue/api-layer/index.ts +58 -0
- package/templates/vue/api-layer/mock/index.ts +122 -0
- package/templates/vue/api-layer/modules/_template.ts +109 -0
- package/templates/vue/api-layer/modules/index.ts +16 -0
- package/templates/vue/api-layer/request.ts +279 -0
- package/templates/vue/api-layer/types.ts +80 -0
- package/troubleshooting/README.md +368 -0
- package/troubleshooting/USAGE_GUIDE.md +289 -0
- package/troubleshooting/flutter/clip-/351/230/264/345/275/261/350/243/201/345/211/252.md +244 -0
- package/troubleshooting/flutter/component-/351/200/232/347/224/250/345/214/226/346/217/220/345/217/226.md +269 -0
- package/troubleshooting/flutter/input-/345/255/227/346/256/265/347/274/272/345/244/261.md +240 -0
- package/troubleshooting/flutter/input-/350/276/271/346/241/206/351/227/256/351/242/230.md +236 -0
- package/troubleshooting/flutter/layout-/345/260/272/345/257/270/344/270/215/345/214/271/351/205/215.md +214 -0
- package/troubleshooting/flutter/shadow-/351/200/217/345/207/272/351/227/256/351/242/230.md +172 -0
- package/troubleshooting/flutter/sketch-/345/210/227/350/241/250item/345/214/272/345/237/237.md +212 -0
- package/troubleshooting/flutter/sketch-/345/233/276/346/240/207/345/260/272/345/257/270.md +135 -0
- package/troubleshooting/flutter/sketch-/345/256/214/346/225/264/346/217/220/345/217/226.md +201 -0
- package/troubleshooting/flutter/sketch-/345/261/236/346/200/247/346/234/252/344/275/277/347/224/250.md +139 -0
- package/troubleshooting/flutter/sketch-/350/203/214/346/231/257/345/261/202/351/253/230/345/272/246.md +264 -0
- package/troubleshooting/flutter/svg-/346/234/252/345/261/205/344/270/255.md +120 -0
- package/troubleshooting/flutter/svg-/351/242/234/350/211/262/345/274/202/345/270/270.md +117 -0
- package/troubleshooting/flutter/tabbar-/345/212/250/347/224/273/345/220/214/346/255/245.md +107 -0
- package/troubleshooting/flutter/withopacity-/345/274/203/347/224/250.md +81 -0
- package/troubleshooting/vue3/cascader-/350/257/257/346/233/277/346/215/242.md +130 -0
- package/troubleshooting/vue3/drawer-input-/346/240/267/345/274/217.md +181 -0
- package/troubleshooting/vue3/table-/347/274/226/350/276/221/345/217/226/346/266/210.md +148 -0
- package/troubleshooting/vue3/table-/350/276/271/346/241/206/351/227/256/351/242/230.md +178 -0
package/common/i18n.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# 国际化 (i18n) 最佳实践
|
|
2
|
+
|
|
3
|
+
适用于需要多语言支持的前端项目
|
|
4
|
+
|
|
5
|
+
## 🎯 核心原则
|
|
6
|
+
|
|
7
|
+
1. **零硬编码**: 所有用户可见文本必须使用翻译函数
|
|
8
|
+
2. **键名规范**: 使用点分层级结构 (`common.save`, `user.profile.title`)
|
|
9
|
+
3. **参数化**: 动态内容使用参数插值,不拼接字符串
|
|
10
|
+
4. **回退机制**: 提供默认语言作为回退
|
|
11
|
+
|
|
12
|
+
## 🔧 标准配置 (Vue I18n)
|
|
13
|
+
|
|
14
|
+
### 目录结构
|
|
15
|
+
```
|
|
16
|
+
src/locales/
|
|
17
|
+
├── index.ts # i18n 初始化
|
|
18
|
+
├── zh-CN.ts # 简体中文
|
|
19
|
+
├── en-US.ts # 英文
|
|
20
|
+
└── ja-JP.ts # 日文
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 翻译文件示例
|
|
24
|
+
```typescript
|
|
25
|
+
// zh-CN.ts
|
|
26
|
+
export default {
|
|
27
|
+
common: {
|
|
28
|
+
save: '保存',
|
|
29
|
+
cancel: '取消',
|
|
30
|
+
confirm: '确认',
|
|
31
|
+
delete: '删除',
|
|
32
|
+
edit: '编辑',
|
|
33
|
+
search: '搜索'
|
|
34
|
+
},
|
|
35
|
+
user: {
|
|
36
|
+
profile: {
|
|
37
|
+
title: '用户资料',
|
|
38
|
+
name: '姓名',
|
|
39
|
+
email: '邮箱'
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
message: {
|
|
43
|
+
saveSuccess: '保存成功',
|
|
44
|
+
deleteConfirm: '确认删除 {name} 吗?',
|
|
45
|
+
itemsSelected: '已选择 {count} 项'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 🎨 单文件 i18n 配置(轻量方案)
|
|
51
|
+
|
|
52
|
+
**适用于不想引入 vue-i18n 插件的项目,使用自定义实现:**
|
|
53
|
+
|
|
54
|
+
### 1. 配置位置
|
|
55
|
+
- **翻译文件**: `src/locales/messages.ts` (键值对数组格式)
|
|
56
|
+
- **语言状态**: `src/stores/state/locale.ts` (Pinia Store)
|
|
57
|
+
- **全局注册**: `src/main.ts` (自定义 $t 方法)
|
|
58
|
+
|
|
59
|
+
### 2. 翻译文件格式
|
|
60
|
+
```typescript
|
|
61
|
+
// src/locales/messages.ts
|
|
62
|
+
// 索引 0 为英文,索引 1 为中文
|
|
63
|
+
|
|
64
|
+
const messages: Record<string, [string, string]> = {
|
|
65
|
+
// ========== 通用 ==========
|
|
66
|
+
是: ['Yes', '是'],
|
|
67
|
+
否: ['No', '否'],
|
|
68
|
+
确定: ['OK', '确定'],
|
|
69
|
+
取消: ['Cancel', '取消'],
|
|
70
|
+
确认: ['Confirm', '确认'],
|
|
71
|
+
保存: ['Save', '保存'],
|
|
72
|
+
提交: ['Submit', '提交'],
|
|
73
|
+
搜索: ['Search', '搜索'],
|
|
74
|
+
查询: ['Query', '查询'],
|
|
75
|
+
重置: ['Reset', '重置'],
|
|
76
|
+
导出: ['Export', '导出'],
|
|
77
|
+
新增: ['Add', '新增'],
|
|
78
|
+
编辑: ['Edit', '编辑'],
|
|
79
|
+
删除: ['Delete', '删除'],
|
|
80
|
+
详情: ['Detail', '详情'],
|
|
81
|
+
操作: ['Operation', '操作'],
|
|
82
|
+
状态: ['Status', '状态'],
|
|
83
|
+
备注: ['Remark', '备注'],
|
|
84
|
+
|
|
85
|
+
// ========== 业务模块 ==========
|
|
86
|
+
订单号: ['Order No', '订单号'],
|
|
87
|
+
金额: ['Amount', '金额'],
|
|
88
|
+
// ... 按模块分组
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default messages
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. 语言状态管理
|
|
95
|
+
```typescript
|
|
96
|
+
// src/stores/state/locale.ts
|
|
97
|
+
import { ref } from 'vue'
|
|
98
|
+
import { defineStore } from 'pinia'
|
|
99
|
+
|
|
100
|
+
export const useLocaleStore = defineStore('locale', () => {
|
|
101
|
+
// 默认中文,可从 localStorage 读取
|
|
102
|
+
const locale = ref<'zh-cn' | 'en'>(
|
|
103
|
+
(localStorage.getItem('locale') as 'zh-cn' | 'en') || 'zh-cn'
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
const setLocale = (lang: 'zh-cn' | 'en') => {
|
|
107
|
+
locale.value = lang
|
|
108
|
+
localStorage.setItem('locale', lang)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const toggleLocale = () => {
|
|
112
|
+
setLocale(locale.value === 'zh-cn' ? 'en' : 'zh-cn')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { locale, setLocale, toggleLocale }
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 4. main.ts 全局注册
|
|
120
|
+
```typescript
|
|
121
|
+
// src/main.ts
|
|
122
|
+
import { createApp } from 'vue'
|
|
123
|
+
import { createPinia } from 'pinia'
|
|
124
|
+
import App from './App.vue'
|
|
125
|
+
import messages from '@/locales/messages'
|
|
126
|
+
import { useLocaleStore } from '@/stores'
|
|
127
|
+
|
|
128
|
+
const app = createApp(App)
|
|
129
|
+
const pinia = createPinia()
|
|
130
|
+
|
|
131
|
+
// ⚠️ 必须先注册 pinia,再使用 store
|
|
132
|
+
app.use(pinia)
|
|
133
|
+
|
|
134
|
+
// 获取语言状态
|
|
135
|
+
const localeStore = useLocaleStore()
|
|
136
|
+
|
|
137
|
+
// 注册全局 $t 方法
|
|
138
|
+
app.config.globalProperties.$t = (key: string): string => {
|
|
139
|
+
const translation = messages[key]
|
|
140
|
+
if (!translation) {
|
|
141
|
+
console.warn(`[i18n] Missing translation: ${key}`)
|
|
142
|
+
return key
|
|
143
|
+
}
|
|
144
|
+
// 索引 0 为英文,索引 1 为中文
|
|
145
|
+
return translation[localeStore.locale === 'zh-cn' ? 1 : 0] || key
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
app.mount('#app')
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 5. 使用方式
|
|
152
|
+
|
|
153
|
+
**在模板中(直接使用):**
|
|
154
|
+
```vue
|
|
155
|
+
<template>
|
|
156
|
+
<el-button>{{ $t('保存') }}</el-button>
|
|
157
|
+
<el-table-column :label="$t('订单号')" prop="orderNo" />
|
|
158
|
+
<el-tag>{{ $t(row.status === 'success' ? '成功' : '失败') }}</el-tag>
|
|
159
|
+
</template>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**在 script 中(需要获取实例):**
|
|
163
|
+
```typescript
|
|
164
|
+
<script setup lang="ts">
|
|
165
|
+
import { getCurrentInstance } from 'vue'
|
|
166
|
+
|
|
167
|
+
// ⚠️ 必须通过 getCurrentInstance 获取
|
|
168
|
+
const { appContext } = getCurrentInstance()!
|
|
169
|
+
const $t = appContext.config.globalProperties.$t
|
|
170
|
+
|
|
171
|
+
// 使用
|
|
172
|
+
ElMessage.success($t('保存成功'))
|
|
173
|
+
ElMessageBox.confirm($t('确认删除吗?'), $t('提示'))
|
|
174
|
+
|
|
175
|
+
// 表单验证
|
|
176
|
+
const rules = {
|
|
177
|
+
name: [{ required: true, message: $t('请输入名称'), trigger: 'blur' }]
|
|
178
|
+
}
|
|
179
|
+
</script>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 6. 添加新翻译键
|
|
183
|
+
|
|
184
|
+
在 `src/locales/messages.ts` 中按分类添加:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
const messages: Record<string, [string, string]> = {
|
|
188
|
+
// ========== 已有内容 ==========
|
|
189
|
+
|
|
190
|
+
// ========== 新增:交易模块 ==========
|
|
191
|
+
汇款订单: ['Remittance Order', '汇款订单'],
|
|
192
|
+
收款订单: ['Collection Order', '收款订单'],
|
|
193
|
+
交易流水: ['Transaction Record', '交易流水'],
|
|
194
|
+
|
|
195
|
+
// ========== 新增:客户模块 ==========
|
|
196
|
+
客户名称: ['Customer Name', '客户名称'],
|
|
197
|
+
联系方式: ['Contact', '联系方式'],
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### ❌ 禁止事项
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// ❌ 不要引入 useI18n(项目未使用 vue-i18n)
|
|
205
|
+
import { useI18n } from 'vue-i18n'
|
|
206
|
+
|
|
207
|
+
// ❌ 不要硬编码文本
|
|
208
|
+
<el-button>保存</el-button>
|
|
209
|
+
|
|
210
|
+
// ❌ 不要字符串拼接
|
|
211
|
+
const msg = '删除' + name + '成功'
|
|
212
|
+
|
|
213
|
+
// ❌ 不要在翻译值中使用变量(当前实现不支持)
|
|
214
|
+
$t('已选择 {count} 项', { count: 5 }) // 不支持!
|
|
215
|
+
// ✅ 替代方案
|
|
216
|
+
`${$t('已选择')} ${count} ${$t('项')}`
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## ✅ 最佳实践
|
|
220
|
+
|
|
221
|
+
### Vue 组件中使用
|
|
222
|
+
```vue
|
|
223
|
+
<script setup lang="ts">
|
|
224
|
+
import { getCurrentInstance } from 'vue'
|
|
225
|
+
|
|
226
|
+
// 获取 $t 函数
|
|
227
|
+
const { appContext } = getCurrentInstance()!
|
|
228
|
+
const $t = appContext.config.globalProperties.$t
|
|
229
|
+
</script>
|
|
230
|
+
|
|
231
|
+
<template>
|
|
232
|
+
<!-- ✅ 好 -->
|
|
233
|
+
<el-button>{{ $t('common.save') }}</el-button>
|
|
234
|
+
<el-table-column :label="$t('user.profile.name')" />
|
|
235
|
+
|
|
236
|
+
<!-- 参数插值 -->
|
|
237
|
+
<p>{{ $t('message.deleteConfirm', { name: userName }) }}</p>
|
|
238
|
+
|
|
239
|
+
<!-- 复数处理 -->
|
|
240
|
+
<span>{{ $t('message.itemsSelected', { count: selectedCount }) }}</span>
|
|
241
|
+
|
|
242
|
+
<!-- ❌ 坏 -->
|
|
243
|
+
<el-button>保存</el-button>
|
|
244
|
+
<p>确认删除 {{ userName }} 吗?</p>
|
|
245
|
+
</template>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### TypeScript 中使用
|
|
249
|
+
```typescript
|
|
250
|
+
import { ElMessage } from 'element-plus'
|
|
251
|
+
|
|
252
|
+
// ✅ 好
|
|
253
|
+
ElMessage.success($t('message.saveSuccess'))
|
|
254
|
+
|
|
255
|
+
// 带参数
|
|
256
|
+
ElMessage.warning($t('message.deleteConfirm', { name: user.name }))
|
|
257
|
+
|
|
258
|
+
// ❌ 坏
|
|
259
|
+
ElMessage.success('保存成功')
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 动态文本映射
|
|
263
|
+
```typescript
|
|
264
|
+
// ✅ 好 - 使用映射对象
|
|
265
|
+
const statusMap = {
|
|
266
|
+
pending: $t('status.pending'),
|
|
267
|
+
success: $t('status.success'),
|
|
268
|
+
error: $t('status.error')
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const statusText = statusMap[status]
|
|
272
|
+
|
|
273
|
+
// 或在模板中
|
|
274
|
+
{{ { 0: $t('type.input'), 1: $t('type.output') }[row.type] }}
|
|
275
|
+
|
|
276
|
+
// ❌ 坏 - 硬编码
|
|
277
|
+
const statusMap = {
|
|
278
|
+
pending: '待处理',
|
|
279
|
+
success: '成功',
|
|
280
|
+
error: '失败'
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## ⚠️ 禁止模式
|
|
285
|
+
|
|
286
|
+
- ❌ 硬编码中文/英文文本
|
|
287
|
+
- ❌ 字符串拼接: `'删除' + name + '吗?'`
|
|
288
|
+
- ❌ 在代码中切换语言逻辑: `if (lang === 'zh') { ... }`
|
|
289
|
+
- ❌ 重复的翻译键
|
|
290
|
+
|
|
291
|
+
## 📋 代码审查清单
|
|
292
|
+
|
|
293
|
+
- [ ] 所有用户可见文本使用 `$t()`
|
|
294
|
+
- [ ] 翻译键使用点分层级结构
|
|
295
|
+
- [ ] 动态内容使用参数插值
|
|
296
|
+
- [ ] 所有语言文件有相同的键结构
|
|
297
|
+
- [ ] ElMessage/ElMessageBox 的文本已翻译
|
|
298
|
+
- [ ] 表单验证消息已翻译
|
|
299
|
+
|
|
300
|
+
## 🔧 常见场景
|
|
301
|
+
|
|
302
|
+
### 表单验证
|
|
303
|
+
```typescript
|
|
304
|
+
const rules = {
|
|
305
|
+
name: [
|
|
306
|
+
{
|
|
307
|
+
required: true,
|
|
308
|
+
message: $t('validation.required', { field: $t('user.profile.name') }),
|
|
309
|
+
trigger: 'blur'
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
min: 2,
|
|
313
|
+
max: 20,
|
|
314
|
+
message: $t('validation.length', { min: 2, max: 20 }),
|
|
315
|
+
trigger: 'blur'
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### 确认对话框
|
|
322
|
+
```typescript
|
|
323
|
+
const handleDelete = async (row: User) => {
|
|
324
|
+
try {
|
|
325
|
+
await ElMessageBox.confirm(
|
|
326
|
+
$t('message.deleteConfirm', { name: row.name }),
|
|
327
|
+
$t('common.warning'),
|
|
328
|
+
{
|
|
329
|
+
confirmButtonText: $t('common.confirm'),
|
|
330
|
+
cancelButtonText: $t('common.cancel'),
|
|
331
|
+
type: 'warning'
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
// 执行删除
|
|
335
|
+
} catch (err) {
|
|
336
|
+
// 用户取消
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### 时间格式化
|
|
342
|
+
```typescript
|
|
343
|
+
// 使用 i18n 的日期格式化
|
|
344
|
+
const formatDate = (date: Date) => {
|
|
345
|
+
return new Intl.DateTimeFormat(locale.value, {
|
|
346
|
+
year: 'numeric',
|
|
347
|
+
month: 'long',
|
|
348
|
+
day: 'numeric'
|
|
349
|
+
}).format(date)
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## 🌍 语言切换
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
import { useI18n } from 'vue-i18n'
|
|
357
|
+
|
|
358
|
+
const { locale } = useI18n()
|
|
359
|
+
|
|
360
|
+
// 切换语言
|
|
361
|
+
const changeLanguage = (lang: 'zh-CN' | 'en-US') => {
|
|
362
|
+
locale.value = lang
|
|
363
|
+
localStorage.setItem('language', lang)
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## ⚠️ 重要:配置文件管理
|
|
370
|
+
|
|
371
|
+
### Copilot 配置 .gitignore
|
|
372
|
+
|
|
373
|
+
**推荐做法:**将自动生成的 `.github/copilot-instructions.md` 添加到 `.gitignore`
|
|
374
|
+
|
|
375
|
+
```gitignore
|
|
376
|
+
# Copilot 配置(自动生成)
|
|
377
|
+
.github/copilot-instructions.md
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**适用项目:**
|
|
381
|
+
- 需要国际化的 Web 应用
|
|
382
|
+
- Vue.js、React、Angular 项目
|
|
383
|
+
- 多语言支持的前端项目
|
|
384
|
+
|
|
385
|
+
**详细指南**: 参考 [Copilot .gitignore 通用指南](../docs/guides/COPILOT_GITIGNORE_GUIDE.md)
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# TypeScript 严格模式指南
|
|
2
|
+
|
|
3
|
+
适用于所有需要高质量类型安全的 TypeScript 项目
|
|
4
|
+
|
|
5
|
+
## 🎯 核心原则
|
|
6
|
+
|
|
7
|
+
1. **零 any**: 绝不使用 `any` 类型,使用 `unknown` 或具体类型
|
|
8
|
+
2. **严格空检查**: 启用 `strictNullChecks`,明确处理 `null`/`undefined`
|
|
9
|
+
3. **完整类型定义**: 所有函数参数、返回值、变量都有明确类型
|
|
10
|
+
4. **类型推断优先**: 让 TypeScript 推断简单类型,复杂类型显式声明
|
|
11
|
+
|
|
12
|
+
## 📝 tsconfig.json 配置
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"compilerOptions": {
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noImplicitAny": true,
|
|
19
|
+
"strictNullChecks": true,
|
|
20
|
+
"strictFunctionTypes": true,
|
|
21
|
+
"strictBindCallApply": true,
|
|
22
|
+
"strictPropertyInitialization": true,
|
|
23
|
+
"noImplicitThis": true,
|
|
24
|
+
"alwaysStrict": true,
|
|
25
|
+
"noUnusedLocals": true,
|
|
26
|
+
"noUnusedParameters": true,
|
|
27
|
+
"noImplicitReturns": true,
|
|
28
|
+
"noFallthroughCasesInSwitch": true
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## ✅ 最佳实践
|
|
34
|
+
|
|
35
|
+
### 类型定义
|
|
36
|
+
```typescript
|
|
37
|
+
// ✅ 好
|
|
38
|
+
interface User {
|
|
39
|
+
id: number
|
|
40
|
+
name: string
|
|
41
|
+
email?: string // 可选属性
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getUser(id: number): Promise<User | null> {
|
|
45
|
+
// ...
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ❌ 坏
|
|
49
|
+
function getUser(id: any): any {
|
|
50
|
+
// ...
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 空值处理
|
|
55
|
+
```typescript
|
|
56
|
+
// ✅ 好
|
|
57
|
+
const user: User | null = await getUser(1)
|
|
58
|
+
if (user) {
|
|
59
|
+
console.log(user.name)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 或使用可选链
|
|
63
|
+
console.log(user?.name)
|
|
64
|
+
|
|
65
|
+
// ❌ 坏
|
|
66
|
+
const user = await getUser(1)
|
|
67
|
+
console.log(user.name) // 可能报错
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 联合类型
|
|
71
|
+
```typescript
|
|
72
|
+
// ✅ 好
|
|
73
|
+
type Status = 'pending' | 'success' | 'error'
|
|
74
|
+
|
|
75
|
+
function handleStatus(status: Status) {
|
|
76
|
+
switch (status) {
|
|
77
|
+
case 'pending': return 'Loading...'
|
|
78
|
+
case 'success': return 'Done!'
|
|
79
|
+
case 'error': return 'Failed!'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ❌ 坏
|
|
84
|
+
function handleStatus(status: string) {
|
|
85
|
+
// 失去类型约束
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 泛型使用
|
|
90
|
+
```typescript
|
|
91
|
+
// ✅ 好
|
|
92
|
+
function fetchData<T>(url: string): Promise<T> {
|
|
93
|
+
return fetch(url).then(res => res.json())
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface Product {
|
|
97
|
+
id: number
|
|
98
|
+
name: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const products = await fetchData<Product[]>('/api/products')
|
|
102
|
+
|
|
103
|
+
// ❌ 坏
|
|
104
|
+
function fetchData(url: string): Promise<any> {
|
|
105
|
+
return fetch(url).then(res => res.json())
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## ⚠️ 禁止模式
|
|
110
|
+
|
|
111
|
+
- ❌ `any` 类型
|
|
112
|
+
- ❌ 类型断言 `as any`
|
|
113
|
+
- ❌ `@ts-ignore` / `@ts-nocheck`
|
|
114
|
+
- ❌ 隐式 any (`noImplicitAny: false`)
|
|
115
|
+
- ❌ 非空断言 `!` (除非确定安全)
|
|
116
|
+
|
|
117
|
+
## 📋 代码审查清单
|
|
118
|
+
|
|
119
|
+
- [ ] 所有函数有明确的参数类型和返回值类型
|
|
120
|
+
- [ ] 没有使用 `any` 类型
|
|
121
|
+
- [ ] 正确处理可能为 `null`/`undefined` 的值
|
|
122
|
+
- [ ] 使用联合类型而非宽泛的 `string`/`number`
|
|
123
|
+
- [ ] 复杂对象有接口定义
|
|
124
|
+
- [ ] 泛型使用恰当
|
|
125
|
+
|
|
126
|
+
## 🔧 常见场景
|
|
127
|
+
|
|
128
|
+
### API 响应处理
|
|
129
|
+
```typescript
|
|
130
|
+
interface ApiResponse<T> {
|
|
131
|
+
success: boolean
|
|
132
|
+
data?: T
|
|
133
|
+
error?: string
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function callApi<T>(endpoint: string): Promise<ApiResponse<T>> {
|
|
137
|
+
try {
|
|
138
|
+
const response = await fetch(endpoint)
|
|
139
|
+
const data = await response.json()
|
|
140
|
+
return { success: true, data }
|
|
141
|
+
} catch (error) {
|
|
142
|
+
return {
|
|
143
|
+
success: false,
|
|
144
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 类型守卫
|
|
151
|
+
```typescript
|
|
152
|
+
function isUser(obj: unknown): obj is User {
|
|
153
|
+
return (
|
|
154
|
+
typeof obj === 'object' &&
|
|
155
|
+
obj !== null &&
|
|
156
|
+
'id' in obj &&
|
|
157
|
+
'name' in obj
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const data: unknown = await fetchData()
|
|
162
|
+
if (isUser(data)) {
|
|
163
|
+
console.log(data.name) // TypeScript 知道 data 是 User
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## ⚠️ 重要:配置文件管理
|
|
170
|
+
|
|
171
|
+
### Copilot 配置 .gitignore
|
|
172
|
+
|
|
173
|
+
**推荐做法:**将自动生成的 `.github/copilot-instructions.md` 添加到 `.gitignore`
|
|
174
|
+
|
|
175
|
+
```gitignore
|
|
176
|
+
# Copilot 配置(自动生成)
|
|
177
|
+
.github/copilot-instructions.md
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**适用项目:**
|
|
181
|
+
- TypeScript 应用(React、Vue、Angular)
|
|
182
|
+
- Node.js 后端服务
|
|
183
|
+
- TypeScript 工具库
|
|
184
|
+
- 所有使用 TypeScript 的项目
|
|
185
|
+
|
|
186
|
+
**详细指南**: 参考 [Copilot .gitignore 通用指南](../docs/guides/COPILOT_GITIGNORE_GUIDE.md)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 故障排除案例元数据
|
|
4
|
+
*/
|
|
5
|
+
interface TroubleshootingCase {
|
|
6
|
+
id: string;
|
|
7
|
+
framework: string;
|
|
8
|
+
title: string;
|
|
9
|
+
problemType: string;
|
|
10
|
+
tags: string[];
|
|
11
|
+
severity: string;
|
|
12
|
+
timeSaved: string;
|
|
13
|
+
filePath: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 查询结果
|
|
17
|
+
*/
|
|
18
|
+
interface TroubleshootingQueryResult {
|
|
19
|
+
cases: Array<{
|
|
20
|
+
id: string;
|
|
21
|
+
title: string;
|
|
22
|
+
framework: string;
|
|
23
|
+
problemType: string;
|
|
24
|
+
tags: string[];
|
|
25
|
+
matchScore: number;
|
|
26
|
+
timeSaved: string;
|
|
27
|
+
preview: string;
|
|
28
|
+
}>;
|
|
29
|
+
totalFound: number;
|
|
30
|
+
queryInfo: {
|
|
31
|
+
framework?: string;
|
|
32
|
+
keywords: string[];
|
|
33
|
+
errorMessage?: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 查询故障排除案例
|
|
38
|
+
*/
|
|
39
|
+
declare function queryTroubleshootingCases(params: {
|
|
40
|
+
framework?: string;
|
|
41
|
+
keywords?: string[];
|
|
42
|
+
errorMessage?: string;
|
|
43
|
+
codePattern?: string;
|
|
44
|
+
limit?: number;
|
|
45
|
+
}): Promise<TroubleshootingQueryResult>;
|
|
46
|
+
/**
|
|
47
|
+
* 获取案例完整内容
|
|
48
|
+
*/
|
|
49
|
+
declare function getTroubleshootingCaseContent(params: {
|
|
50
|
+
framework: string;
|
|
51
|
+
caseId: string;
|
|
52
|
+
}): Promise<{
|
|
53
|
+
content: string;
|
|
54
|
+
metadata: any;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* 列出所有可用案例
|
|
58
|
+
*/
|
|
59
|
+
declare function listTroubleshootingCases(framework?: string): Promise<{
|
|
60
|
+
cases: TroubleshootingCase[];
|
|
61
|
+
frameworks: string[];
|
|
62
|
+
}>;
|
|
63
|
+
|
|
64
|
+
export { getTroubleshootingCaseContent, listTroubleshootingCases, queryTroubleshootingCases };
|