---
# Please note: Do not modify the header of this document. If modified, CodeBuddy (Internal Edition) will apply the default logic settings.
type: always
---

# Tencent Component Toolkit 开发规则

## 项目概述

tencent-component-toolkit 是腾讯云服务的 TypeScript SDK 工具包，提供对云函数（SCF）、API 网关、对象存储（COS）、私有网络（VPC）等多种腾讯云服务的统一封装和操作接口。

## 技术栈

- **语言**: TypeScript 4.3+
- **运行环境**: Node.js >= 10.18
- **核心依赖**: @tencent-sdk/capi, axios, lodash
- **测试框架**: Jest 26.6+
- **代码规范**: ESLint + Prettier

---

## 一、代码风格与结构

### 1.1 文件组织结构

```
src/
├── modules/              # 各云服务模块
│   ├── scf/             # 云函数模块
│   │   ├── index.ts     # 主类（导出默认类）
│   │   ├── interface.ts # 类型定义
│   │   ├── apis.ts      # API 常量和方法
│   │   ├── config.ts    # 配置常量
│   │   ├── utils.ts     # 工具函数
│   │   └── entities/    # 实体类
│   │       ├── scf.ts   # 主实体
│   │       ├── alias.ts # 别名实体
│   │       └── ...
│   ├── apigw/           # API 网关模块
│   ├── triggers/        # 触发器模块
│   └── ...
├── utils/               # 公共工具函数
│   ├── error.ts         # 错误类定义
│   └── index.ts         # 工具函数集合
└── index.ts             # 主入口（统一导出）
```

### 1.2 命名约定

#### 类名

- 使用 PascalCase
- 实体类以功能命名：`ScfEntity`, `AliasEntity`, `VersionEntity`
- 主模块类简短明了：`Scf`, `Apigw`, `Cos`
- 工具类以 Utils 结尾：`TagsUtils`, `ApigwUtils`

#### 函数和方法

- 使用 camelCase
- 动作动词开头：`deploy`, `remove`, `get`, `create`, `update`, `delete`
- 查询类：`getFunction`, `getTriggerList`, `getInitialStatus`
- 操作类：`deployTrigger`, `updateCode`, `createAlias`

#### 接口和类型

- 接口使用 PascalCase：`ScfDeployInputs`, `TriggerType`
- 类型别名使用 PascalCase
- 输入接口以 Inputs/Params 结尾：`ScfDeployInputs`, `TriggerInputsParams`
- 输出接口以 Outputs/Response 结尾：`ScfDeployOutputs`, `TriggerResponse`

#### 常量

- 全大写 + 下划线：`CONFIGS`, `APIS`, `TRIGGERS`
- 常量对象使用单独文件：`config.ts`, `apis.ts`

#### 私有属性

- 以下划线开头：`_credentials`, `_region`

### 1.3 导出规范

- 模块主类使用 `export default` 导出
- 类型、常量、工具函数使用 `export` 命名导出
- 在 `src/index.ts` 中统一导出所有模块

```typescript
// 正确
export { default as Scf } from './modules/scf';
export { TriggerManager } from './modules/triggers/manager';

// 模块内部
export default class Scf {}
export type { ScfDeployInputs } from './interface';
```

---

## 二、TypeScript 使用规范

### 2.1 类型定义

- **优先使用 interface** 定义对象类型和形状
- **使用 type** 定义联合类型、交叉类型、映射类型
- 为所有公共 API 提供明确的类型定义
- 使用泛型提供类型安全和灵活性

```typescript
// 使用 interface 定义对象
interface ScfDeployInputs {
  name: string;
  namespace?: string;
  region?: RegionType;
  code?: CodeInfo;
  handler?: string;
}

// 使用 type 定义联合类型
type RegionType = 'ap-guangzhou' | 'ap-shanghai' | 'ap-beijing';
type FunctionStatus = 'Active' | 'Creating' | 'Updating' | 'Failed';

// 使用泛型
async request<T = any>({ Action, ...data }: { Action: string; [key: string]: any }): Promise<T>
```

### 2.2 TypeScript 编译配置

- **目标**: ES2017
- **模块**: CommonJS
- **严格模式**: `strict: false`（但保持 `noImplicitAny: true`）
- **生成声明文件**: `declaration: true`
- **生成 Source Map**: `sourceMap: true`
- **输出目录**: `lib/`

### 2.3 类型安全实践

- 避免使用 `any`，必要时使用 `unknown` 或具体类型
- 使用非空断言操作符 `!` 时要确保值确实非空
- 使用可选链 `?.` 和空值合并 `??` 处理可能为空的值
- 为异步函数返回类型添加 `Promise<T>`

```typescript
// 好
const result = await this.request<{ Triggers: TriggerType[] }>({ Action: 'ListTriggers' });
const triggers = result.Triggers ?? [];

// 避免（虽然配置允许，但不应滥用）
const data: any = await this.request({ Action: 'GetInfo' });
```

---

## 三、代码模式和最佳实践

### 3.1 类和对象设计

- 使用 ES6 class 定义服务和实体
- 使用构造函数初始化依赖（credentials, region, capi）
- 使用依赖注入模式，将 credentials 和 region 作为参数传入
- 实体类负责具体的业务逻辑操作

```typescript
class Scf {
  credentials: CapiCredentials;
  region: RegionType;
  capi: Capi;
  scf: ScfEntity;
  alias: AliasEntity;

  constructor(credentials = {}, region: RegionType = 'ap-guangzhou') {
    this.credentials = credentials;
    this.region = region;
    this.capi = new Capi({ Region: region, SecretId: credentials.SecretId, ... });
    this.scf = new ScfEntity(this.capi, region);
    this.alias = new AliasEntity(this.capi);
  }
}
```

### 3.2 异步操作

- **必须使用 async/await** 处理异步操作
- 避免回调地狱
- 错误使用 try-catch 捕获
- 对于长时间操作，考虑使用状态轮询

```typescript
async deploy(inputs: ScfDeployInputs) {
  try {
    const funcInfo = await this.scf.get({ namespace, functionName });
    if (!funcInfo) {
      await this.scf.create(inputs);
    } else {
      await this.scf.updateCode(inputs, funcInfo);
    }
    await this.scf.isOperational({ namespace, functionName });
  } catch (error) {
    throw new ApiTypeError('DEPLOY_FAILED', error.message);
  }
}
```

### 3.3 错误处理

- 使用自定义错误类 `ApiTypeError` 和 `ApiError`
- 错误类包含错误类型、消息、堆栈、请求 ID
- 抛出错误时提供清晰的错误类型和消息
- 使用早期返回减少嵌套

```typescript
import { ApiTypeError } from '../../utils/error';

if (!inputs.aliasName) {
  throw new ApiTypeError('PARAMETER_SCF', 'aliasName is required');
}

// 操作前检查状态
if (func.Status === 'Creating' || func.Status === 'Updating') {
  throw new ApiTypeError('STATUS_INVALID', `Function status is ${func.Status}`);
}
```

### 3.4 数据操作

- 使用解构赋值提取对象属性
- 使用扩展运算符合并对象
- 使用 `deepClone` 进行深拷贝，避免引用问题
- 使用 `strip` 工具函数清理和格式化数据

```typescript
// 解构赋值
const { name, namespace = 'default', region = 'ap-guangzhou' } = inputs;

// 对象合并
const params = { ...defaultConfig, ...inputs };

// 深拷贝
const deleteList: TriggerType[] = deepClone(oldList);

// 数据清理
const weight = strip(1 - inputs.traffic);
```

### 3.5 条件判断

- 使用可选链 `?.` 访问可能为空的属性
- 使用空值合并 `??` 提供默认值
- 避免深度嵌套，使用早期返回
- 简单条件可以使用三元运算符

```typescript
// 可选链
const aliasName = funcInfo?.Alias?.Name ?? '$DEFAULT';

// 早期返回
if (!funcInfo) {
  await this.scf.create(inputs);
  return;
}
await this.scf.updateCode(inputs, funcInfo);

// 简单条件
const needCreate = !aliasInfo?.Name;
```

### 3.6 循环和迭代

- 使用 `for` 循环处理需要索引的场景
- 使用 `for...of` 遍历数组
- 使用 `map`、`filter`、`reduce` 进行函数式操作
- 避免在循环中创建不必要的对象

```typescript
// 需要索引
for (let i = 0; i < deleteList.length; i++) {
  const trigger = deleteList[i];
  await this.deleteTrigger(trigger);
}

// 函数式操作
const deployedList = deployList.filter((item) => item !== null);
const outputs = triggerList.map((item) => ({ ...item, NeedCreate: true }));
```

---

## 四、API 调用规范

### 4.1 API 封装

- 使用 `@tencent-sdk/capi` 进行 HTTP 请求
- 定义 API Action 常量（如 `APIS` 对象）
- 封装统一的 `request` 方法
- 处理通用错误和重试逻辑

```typescript
// apis.ts
import { SCF } from '@tencent-sdk/capi';

export const APIS = {
  GetFunction: async (capi, params) => await SCF.GetFunction(capi, params),
  ListTriggers: async (capi, params) => await SCF.ListTriggers(capi, params),
  // ...
};

// 主类中
async request({ Action, ...data }: { Action: ActionType; [key: string]: any }) {
  return await APIS[Action](this.capi, data);
}
```

### 4.2 区域配置

- 支持多区域部署
- 默认区域：`ap-guangzhou`
- 定义 `RegionType` 类型规范区域值
- 每个实例独立指定 region

### 4.3 凭证管理

- 使用 `CapiCredentials` 类型
- 包含 `SecretId`、`SecretKey`、`Token`
- 不要在代码中硬编码凭证
- 通过构造函数传入

```typescript
interface CapiCredentials {
  SecretId: string;
  SecretKey: string;
  Token?: string;
}
```

---

## 五、测试规范

### 5.1 测试文件组织

- 测试文件放在 `__tests__/` 目录
- 按模块组织：`__tests__/scf/`, `__tests__/apigw/`
- 测试文件命名：`*.test.ts` 或 `*.spec.ts`
- 使用 `MODULE` 环境变量运行特定模块测试

### 5.2 Jest 配置

- 测试环境：`node`
- 测试超时：`600000ms`（10 分钟）
- 忽略部分测试文件（如 CDN 测试、特殊功能测试）
- 支持通过环境变量控制测试范围

```bash
# 运行所有测试
npm test

# 运行特定模块
MODULE=scf npm test
MODULE=triggers npm test

# 本地调试
npm run test:local
```

### 5.3 测试编写建议

- 为关键功能编写单元测试
- 测试边界情况和错误处理
- Mock 外部 API 调用
- 使用 fixtures 准备测试数据

---

## 六、模块化设计规范

### 6.1 模块结构

每个模块应包含以下文件：

- `index.ts` - 主类，提供主要 API
- `interface.ts` - 所有类型定义
- `apis.ts` - API Action 常量和封装
- `config.ts` - 配置常量（可选）
- `utils.ts` - 工具函数（可选）
- `entities/` - 实体类目录（复杂模块）

### 6.2 模块依赖

- 模块间通过接口交互
- 避免循环依赖
- 共享类型定义放在 `interface.ts`
- 公共工具放在 `utils/` 目录

### 6.3 实体类设计

- 实体类负责具体的 CRUD 操作
- 通过构造函数接收 capi 实例
- 每个实体专注于特定资源
- 返回类型明确的响应

```typescript
// 示例：AliasEntity
class AliasEntity {
  capi: Capi;

  constructor(capi: Capi) {
    this.capi = capi;
  }

  async get({ namespace, functionName, region, aliasName }: AliasGetInputs) {
    return await APIS.GetAlias(this.capi, { FunctionName: functionName, ... });
  }

  async create(inputs: AliasCreateInputs) { ... }
  async update(inputs: AliasUpdateInputs) { ... }
}
```

---

## 七、ESLint 规则

### 7.1 配置要点

- Parser: `@typescript-eslint/parser`
- Extend: `eslint:recommended`, `plugin:@typescript-eslint/recommended`, `plugin:prettier/recommended`
- Env: `node`, `es6`, `jest`

### 7.2 关键规则

```javascript
{
  '@typescript-eslint/no-explicit-any': 'off',      // 允许 any（但应避免）
  '@typescript-eslint/no-unused-vars': 'warn',     // 未使用变量警告
  '@typescript-eslint/explicit-function-return-type': 'off',  // 不要求显式返回类型
  '@typescript-eslint/no-non-null-assertion': 'off',  // 允许非空断言
  'no-console': 'off',                             // 允许 console
  'no-empty': ['warn', { allowEmptyCatch: true }], // 允许空 catch
  'prettier/prettier': 'error'                     // Prettier 冲突报错
}
```

### 7.3 代码质量

- 保持代码简洁，避免过度嵌套
- 使用早期返回减少嵌套层级
- 避免重复代码，提取公共逻辑
- 添加必要的注释说明复杂逻辑

---

## 八、Prettier 配置

### 8.1 格式化规则

```javascript
{
  arrowParens: 'always',      // 箭头函数参数始终使用括号
  printWidth: 100,            // 每行最大 100 字符
  semi: true,                 // 使用分号
  singleQuote: true,          // 使用单引号
  tabWidth: 2,                // 2 空格缩进
  trailingComma: 'all'        // 尾逗号
}
```

### 8.2 使用方式

```bash
# 检查格式
npm run prettier

# 自动修复
npm run prettier:fix

# 结合 lint 一起使用
npm run format
```

---

## 九、Git 工作流

### 9.1 Git Hooks

- **pre-commit**: 运行安全检查 (`ygsec`) 和 `lint-staged`
- **commit-msg**: 使用 `commitlint` 验证提交信息
- **pre-push**: 运行安全检查、lint 修复和 prettier 修复

### 9.2 提交信息规范

- 使用 `@commitlint/config-conventional` 配置
- 遵循 Conventional Commits 规范
- 格式：`type(scope): subject`

```bash
# 示例
feat(scf): add support for provisioned concurrency
fix(apigw): resolve custom domain deployment issue
docs: update README with new features
```

### 9.3 Lint-staged 配置

```json
{
  "**/*.{js,ts,tsx}": ["npm run lint:fix"],
  "**/*.{css,html,js,json,md,yaml,yml}": ["npm run prettier:fix"]
}
```

---

## 十、版本发布

### 10.1 Semantic Release

- 使用 `semantic-release` 自动发布
- 自动生成 CHANGELOG
- 支持提交分析和发布说明生成
- 使用 git 标签管理版本

### 10.2 发布流程

```bash
# 自动发布（CI 中）
npm run release

# 本地测试发布
npm run release-local
```

---

## 十一、性能优化

### 11.1 代码优化

- 避免不必要的重复 API 请求
- 使用缓存减少 API 调用
- 批量操作优于循环单个操作
- 异步操作并行化（使用 `Promise.all`）

```typescript
// 好的做法
const [funcInfo, triggerList] = await Promise.all([
  this.scf.get({ namespace, functionName }),
  this.getTriggerList(functionName, namespace),
]);

// 避免
const funcInfo = await this.scf.get(...);
const triggerList = await this.getTriggerList(...);
```

### 11.2 构建优化

- 使用 `tsc` 编译 TypeScript
- 生成 `.d.ts` 类型声明文件
- 生成 source map 用于调试
- 输出到 `lib/` 目录

---

## 十二、安全规范

### 12.1 凭证管理

- 使用 `CapiCredentials` 类型管理凭证
- 支持 `SecretId`、`SecretKey`、`Token`
- **严禁**在代码中硬编码凭证
- 通过环境变量或配置文件传入

### 12.2 安全检查

- 使用 `@ygkit/secure` 进行安全检查
- 在 pre-commit 和 pre-push 钩子中运行
- 检测敏感信息泄露（如密钥、令牌）

### 12.3 数据安全

- 不要在日志中输出敏感信息
- 使用 `strip` 等工具清理输出数据
- 验证用户输入

---

## 十三、常见场景处理模式

### 13.1 资源状态检查

操作前检查资源状态，确保处于可操作状态

```typescript
await this.scf.isOperational({ namespace, functionName });
```

### 13.2 状态轮询

对于异步操作，使用轮询机制检查完成状态

```typescript
// 轮询最多 30 次
for (let i = 0; i < 30; i++) {
  const result = await this.getStatus();
  if (result.status === 'Done') return result;
  if (result.status === 'Failed') throw result.reason;
  await sleep(1000);
}
```

### 13.3 触发器管理

- 支持创建、更新、删除触发器
- 通过唯一 key 识别触发器
- 处理触发器唯一性约束
- 使用 `TriggerManager` 统一管理

### 13.4 版本和别名

- 支持版本发布（`$LATEST`、数字版本）
- 支持别名创建和流量分配
- 使用 `VersionEntity` 和 `AliasEntity`

### 13.5 标签管理

- 使用 `TagsUtils` 统一管理资源标签
- 格式化标签输入和输出
- 批量操作标签

---

## 十四、禁止事项

1. ❌ **不要在代码中硬编码凭证或敏感信息**
2. ❌ **不要使用隐式 any**（虽然配置允许，但应保持类型安全）
3. ❌ **不要忽略错误处理**，所有异步操作都应有 try-catch
4. ❌ **不要循环依赖模块**
5. ❌ **不要使用 console.error 记录敏感信息**
6. ❌ **不要提交 node_modules**
7. ❌ **不要修改 lib 目录**（构建产物）
8. ❌ **不要跳过测试提交代码**
9. ❌ **不要在循环中执行同步阻塞操作**
10. ❌ **不要在公共 API 中返回 any 类型**

---

## 十五、最佳实践清单

### 开发前

- [ ] 了解模块的功能和职责
- [ ] 查看相关接口定义和类型
- [ ] 确认依赖关系

### 开发中

- [ ] 为公共 API 添加类型定义
- [ ] 使用 async/await 处理异步操作
- [ ] 添加适当的错误处理
- [ ] 使用早期返回减少嵌套
- [ ] 添加必要的注释

### 开发后

- [ ] 运行 `npm run format` 格式化代码
- [ ] 运行 `npm run lint` 检查代码规范
- [ ] 编写或更新测试用例
- [ ] 更新相关文档
- [ ] 运行测试确保功能正常

### 提交前

- [ ] 运行 `npm run format` 确保代码格式
- [ ] 运行 `npm run lint` 确保无 lint 错误
- [ ] 运行测试确保功能正常
- [ ] 检查提交信息是否符合规范
- [ ] 确认没有敏感信息泄露

---

## 十六、工具脚本

```bash
# 构建
npm run build

# 测试
npm test                          # 运行所有测试
npm run test:scf                  # 运行 SCF 模块测试
npm run test:local                # 本地调试模式

# 代码检查和格式化
npm run lint                      # ESLint 检查
npm run lint:fix                  # ESLint 自动修复
npm run prettier                  # Prettier 检查
npm run prettier:fix              # Prettier 自动修复
npm run format                    # 结合 lint 和 prettier

# 发布
npm run release                   # 自动发布
npm run release-local             # 本地测试发布

# 依赖管理
npm run check-dependencies        # 检查依赖更新
```

---

## 十七、项目特定约定

### 17.1 函数操作流程

1. 检查函数初始状态（`getInitialStatus`）
2. 根据状态决定创建或更新
3. 检查函数可操作性（`isOperational`）
4. 处理版本和别名
5. 设置预置并发和独占配额
6. 部署触发器
7. 设置标签

### 17.2 触发器更新优化逻辑

- 支持更新的触发器类型：`http`, `ckafka`, `mqtt`, `apache_kafka`
- 如果触发器在 DB 中存在且类型支持更新，则更新；否则创建
- 删除逻辑：对于支持更新的触发器，跳过删除旧触发器

### 17.3 默认值

- 默认命名空间：`default`
- 默认区域：`ap-guangzhou`
- 默认限定符：`$LATEST`

### 17.4 特殊处理

- 函数状态为 `CreateFailed` 时，先删除再重新创建
- 异步函数（type=async）需要更新重试配置
- HTTP 直通函数需要特殊处理
- 镜像函数需要特殊处理

---

## 十八、维护和演进

### 18.1 依赖管理

- 定期运行 `npm run check-dependencies` 检查依赖更新
- 核心依赖保持稳定版本
- 开发依赖可以及时更新
- 注意破坏性变更

### 18.2 代码重构

- 保持向后兼容
- 使用 TypeScript 类型检查保护
- 逐步重构，避免大规模改动
- 重构后运行完整测试

### 18.3 文档维护

- 更新 README 添加新功能
- 维护 CHANGELOG 记录重要变更
- 为复杂功能添加使用示例
- 保持接口文档与代码同步

---

## 十九、故障排查

### 19.1 常见错误

- **状态错误**: 函数处于 `Creating`、`Updating` 状态无法操作
- **权限错误**: 凭证没有相应权限
- **资源不存在**: 函数或触发器已被删除
- **参数错误**: 必填参数缺失或格式不正确

### 19.2 调试技巧

- 使用 `DEBUG=true npm run test:local` 本地调试
- 查看 API 请求 ID (`reqId`) 追踪问题
- 检查函数状态和配置
- 使用 `console.log` 记录关键操作

---

## 二十、总结

本项目的核心原则：

1. **类型安全**: 使用 TypeScript 提供类型保护
2. **模块化**: 清晰的模块划分和职责分离
3. **可维护性**: 统一的代码风格和结构
4. **可测试性**: 完善的测试覆盖
5. **安全性**: 严格的凭证管理和安全检查
6. **性能**: 优化 API 调用和异步操作

遵循以上规范，可以确保代码质量、可维护性和团队协作效率。
