# 命名规范

本文档定义了项目中所有代码的命名规范，确保代码风格统一，提高可读性和可维护性。

## 目录

- [文件和文件夹命名](#文件和文件夹命名)
- [变量和函数命名](#变量和函数命名)
- [类和构造函数命名](#类和构造函数命名)
- [常量命名](#常量命名)
- [接口路由命名](#接口路由命名)
- [TypeScript 特定规范](#typescript-特定规范)
- [注释命名规范](#注释命名规范)
- [命名示例](#命名示例)

## 文件和文件夹命名

**规则：使用下划线分隔（snake_case）**

### 文件命名

```
✅ 正确示例：
- order_controller.ts
- user_service.ts
- game_gateway.ts
- player_entity.ts
- create_room_dto.ts
- database_config.ts

❌ 错误示例：
- OrderController.ts
- userService.ts
- game-gateway.ts
- playerEntity.ts
```

### 文件夹命名

```
✅ 正确示例：
- src/api/
- src/service/
- src/model/dto/
- src/utils/
- src/config/
- test/unit_test/
- test/integration_test/

❌ 错误示例：
- src/API/
- src/Service/
- src/model-dto/
- src/Utils/
```

### 特殊说明

- 所有文件和文件夹名使用小写字母
- 多个单词之间使用下划线 `_` 连接
- 避免使用缩写，除非是广泛认可的缩写（如 dto、api）

## 变量和函数命名

**规则：使用小驼峰命名（camelCase）**

### 变量命名

```typescript
✅ 正确示例：
const userName = 'Alice';
let playerScore = 100;
const roomId = '12345';
const isGameStarted = false;
const maxPlayerCount = 4;

❌ 错误示例：
const UserName = 'Alice';
const player_score = 100;
const RoomId = '12345';
const is_game_started = false;
```

### 函数命名

```typescript
✅ 正确示例：
function getUserInfo() { }
async function queryUserInfo() { }
function calculateDamage() { }
function isPlayerAlive() { }
function handlePlayerMove() { }

❌ 错误示例：
function GetUserInfo() { }
function query_user_info() { }
function CalculateDamage() { }
function IsPlayerAlive() { }
```

### 命名建议

- 使用动词开头描述函数功能：
  - `get` - 获取数据（如 `getUserById`）
  - `set` - 设置数据（如 `setPlayerPosition`）
  - `create` - 创建实体（如 `createRoom`）
  - `update` - 更新数据（如 `updatePlayerScore`）
  - `delete` - 删除数据（如 `deleteRoom`）
  - `is/has` - 布尔判断（如 `isGameOver`、`hasPermission`）
  - `handle` - 事件处理（如 `handlePlayerAttack`）
  - `calculate` - 计算逻辑（如 `calculateDamage`）
  - `validate` - 验证逻辑（如 `validateInput`）

- 布尔变量使用 `is`、`has`、`can` 等前缀：
  ```typescript
  const isActive = true;
  const hasPermission = false;
  const canMove = true;
  ```

## 类和构造函数命名

**规则：使用大驼峰命名（PascalCase）**

### 类命名

```typescript
✅ 正确示例：
class UserModel { }
class OrderService { }
class GameController { }
class PlayerEntity { }
class RoomGateway { }
class DatabaseConnection { }

❌ 错误示例：
class userModel { }
class order_service { }
class gameController { }
class player_entity { }
```

### 接口命名

```typescript
✅ 正确示例：
interface User { }
interface GameConfig { }
interface PlayerData { }
interface RoomOptions { }

// 或使用 I 前缀（可选）
interface IUser { }
interface IGameConfig { }

❌ 错误示例：
interface user { }
interface game_config { }
interface playerData { }
```

### DTO 命名

```typescript
✅ 正确示例：
class CreateUserDto { }
class UpdatePlayerDto { }
class JoinRoomDto { }
class GameStateDto { }

❌ 错误示例：
class createUserDto { }
class update_player_dto { }
class joinRoomDTO { }
```

### 装饰器命名

```typescript
✅ 正确示例：
@Controller('users')
@Injectable()
@Module()
@Get()

// 自定义装饰器
function CustomDecorator() { }
```

## 常量命名

**规则：全大写 + 下划线分隔（SCREAMING_SNAKE_CASE）**

```typescript
✅ 正确示例：
const PORT = 3000;
const DB_HOST = 'localhost';
const MAX_PLAYERS = 10;
const API_VERSION = 'v1';
const DEFAULT_TIMEOUT = 5000;
const GAME_STATUS_WAITING = 'waiting';
const GAME_STATUS_PLAYING = 'playing';

❌ 错误示例：
const port = 3000;
const dbHost = 'localhost';
const maxPlayers = 10;
const ApiVersion = 'v1';
const default_timeout = 5000;
```

### 枚举命名

```typescript
✅ 正确示例：
enum GameStatus {
  WAITING = 'waiting',
  PLAYING = 'playing',
  FINISHED = 'finished',
}

enum PlayerRole {
  ADMIN = 'admin',
  PLAYER = 'player',
  SPECTATOR = 'spectator',
}

❌ 错误示例：
enum gameStatus {
  waiting = 'waiting',
  playing = 'playing',
}

enum PlayerRole {
  admin = 'admin',
  player = 'player',
}
```

## 接口路由命名

**规则：全小写 + 短横线分隔（kebab-case）**

```typescript
✅ 正确示例：
@Get('user/get-info')
@Post('order/create-order')
@Put('player/update-position')
@Delete('room/delete-room')
@Get('game/get-state')
@Post('room/join-room')

❌ 错误示例：
@Get('user/getInfo')
@Post('order/createOrder')
@Put('player/update_position')
@Delete('room/DeleteRoom')
@Get('game/GetState')
```

### 路由结构建议

```typescript
// 资源型路由
@Controller('api/players')
export class PlayerController {
  @Get()                    // GET /api/players
  @Get(':id')              // GET /api/players/:id
  @Post()                  // POST /api/players
  @Put(':id')              // PUT /api/players/:id
  @Delete(':id')           // DELETE /api/players/:id
}

// 动作型路由
@Controller('api/game')
export class GameController {
  @Post('start-game')      // POST /api/game/start-game
  @Post('end-game')        // POST /api/game/end-game
  @Get('get-state')        // GET /api/game/get-state
}

// 嵌套资源路由
@Controller('api/rooms')
export class RoomController {
  @Post(':id/join')        // POST /api/rooms/:id/join
  @Post(':id/leave')       // POST /api/rooms/:id/leave
  @Get(':id/players')      // GET /api/rooms/:id/players
}
```

## TypeScript 特定规范

### 类型别名

```typescript
✅ 正确示例：
type UserId = string;
type PlayerPosition = { x: number; y: number };
type GameCallback = (state: GameState) => void;

❌ 错误示例：
type userId = string;
type player_position = { x: number; y: number };
```

### 泛型参数

```typescript
✅ 正确示例：
function findById<T>(id: string): T { }
class Repository<T, K> { }
interface Response<T> { }

// 使用有意义的名称
function mapArray<TInput, TOutput>(arr: TInput[]): TOutput[] { }

❌ 错误示例：
function findById<t>(id: string): t { }
class Repository<type, key> { }
```

### 装饰器参数

```typescript
✅ 正确示例：
@Column({ name: 'user_name' })
@IsString({ message: 'Name must be a string' })
@ApiProperty({ description: 'User ID' })

❌ 错误示例：
@Column({ name: 'UserName' })
@IsString({ message: 'name_must_be_string' })
```

## 注释命名规范

### 注释标签命名

**规则：使用标准JSDoc标签**

```typescript
✅ 正确示例：
@param userId 用户ID
@returns 用户信息
@throws NotFoundException 用户不存在时
@author moyin
@version 1.0.0
@since 2025-01-07
@lastModified 2025-01-07

❌ 错误示例：
@参数 userId 用户ID
@返回 用户信息
@异常 NotFoundException 用户不存在时
@作者 moyin
```

### 修改记录命名

**规则：使用标准化的修改类型**

```typescript
✅ 正确示例：
- 2025-01-07: 代码规范优化 - 清理未使用的导入
- 2025-01-07: 功能新增 - 添加用户验证功能
- 2025-01-07: Bug修复 - 修复登录验证逻辑
- 2025-01-07: 性能优化 - 优化数据库查询
- 2025-01-07: 重构 - 重构用户服务架构

❌ 错误示例：
- 2025-01-07: 修改 - 改了一些代码
- 2025-01-07: 更新 - 更新了功能
- 2025-01-07: 优化 - 优化了性能
- 2025-01-07: 调整 - 调整了结构
```

**📏 长度限制：修改记录只保留最近5次修改，保持文件头注释简洁。**

### 注释内容命名

**规则：使用清晰描述性的中文**

```typescript
✅ 正确示例：
/** 用户唯一标识符 */
userId: string;

/** 用户邮箱地址，用于登录和通知 */
email: string;

/** 用户状态：active-激活, inactive-未激活, banned-已封禁 */
status: UserStatus;

/**
 * 验证用户登录凭据
 * 
 * 业务逻辑：
 * 1. 验证用户名或邮箱格式
 * 2. 查找用户记录
 * 3. 验证密码哈希值
 * 4. 检查用户状态
 */

❌ 错误示例：
/** id */
userId: string;

/** 邮箱 */
email: string;

/** 状态 */
status: UserStatus;

/**
 * 登录
 */
```

### 版本号命名规范

**规则：使用语义化版本号**

```typescript
✅ 正确示例：
@version 1.0.0    // 主版本.次版本.修订版本
@version 1.2.3    // 功能更新
@version 2.0.0    // 重大更新

修改时版本递增规则：
- 代码规范优化、Bug修复 → 修订版本 +1 (1.0.0 → 1.0.1)
- 功能新增、功能修改 → 次版本 +1 (1.0.1 → 1.1.0)
- 重构、架构变更 → 主版本 +1 (1.1.0 → 2.0.0)

❌ 错误示例：
@version v1        // 缺少详细版本号
@version 1         // 格式不规范
@version latest    // 不明确的版本标识
```

## 命名示例

### 完整的模块示例

```typescript
// 文件：src/api/player_controller.ts
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { PlayerService } from '../service/player_service';
import { CreatePlayerDto } from '../model/dto/create_player_dto';

const MAX_PLAYERS = 100;

@Controller('api/players')
export class PlayerController {
  constructor(private readonly playerService: PlayerService) {}

  @Get()
  async getAllPlayers() {
    return this.playerService.findAll();
  }

  @Get(':id')
  async getPlayerById(@Param('id') playerId: string) {
    return this.playerService.findById(playerId);
  }

  @Post()
  async createPlayer(@Body() createPlayerDto: CreatePlayerDto) {
    return this.playerService.create(createPlayerDto);
  }

  @Post(':id/update-position')
  async updatePlayerPosition(
    @Param('id') playerId: string,
    @Body() body: { x: number; y: number }
  ) {
    const { x, y } = body;
    return this.playerService.updatePosition(playerId, x, y);
  }
}
```

```typescript
// 文件：src/service/player_service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { Player } from '../model/player_entity';
import { CreatePlayerDto } from '../model/dto/create_player_dto';

const DEFAULT_HEALTH = 100;
const DEFAULT_SPEED = 5;

@Injectable()
export class PlayerService {
  private players: Map<string, Player> = new Map();

  findAll(): Player[] {
    return Array.from(this.players.values());
  }

  findById(playerId: string): Player {
    const player = this.players.get(playerId);
    if (!player) {
      throw new NotFoundException(`Player with ID ${playerId} not found`);
    }
    return player;
  }

  create(createPlayerDto: CreatePlayerDto): Player {
    const newPlayer: Player = {
      id: this.generatePlayerId(),
      name: createPlayerDto.name,
      health: DEFAULT_HEALTH,
      speed: DEFAULT_SPEED,
      position: { x: 0, y: 0 },
      isAlive: true,
      createdAt: new Date(),
    };
    this.players.set(newPlayer.id, newPlayer);
    return newPlayer;
  }

  updatePosition(playerId: string, x: number, y: number): Player {
    const player = this.findById(playerId);
    player.position = { x, y };
    return player;
  }

  private generatePlayerId(): string {
    return `player_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  private calculateDamage(attackPower: number, defense: number): number {
    return Math.max(0, attackPower - defense);
  }

  isPlayerAlive(playerId: string): boolean {
    const player = this.findById(playerId);
    return player.isAlive && player.health > 0;
  }
}
```

```typescript
// 文件：src/model/player_entity.ts
export interface Player {
  id: string;
  name: string;
  health: number;
  speed: number;
  position: Position;
  isAlive: boolean;
  createdAt: Date;
}

export interface Position {
  x: number;
  y: number;
}

export enum PlayerStatus {
  IDLE = 'idle',
  MOVING = 'moving',
  ATTACKING = 'attacking',
  DEAD = 'dead',
}
```

```typescript
// 文件：src/model/dto/create_player_dto.ts
import { IsString, IsNotEmpty, MinLength, MaxLength } from 'class-validator';

export class CreatePlayerDto {
  @IsString()
  @IsNotEmpty()
  @MinLength(3)
  @MaxLength(20)
  name: string;
}
```

## 检查清单

在提交代码前，请确保：

- [ ] 所有文件和文件夹使用下划线分隔命名
- [ ] 所有变量和函数使用小驼峰命名
- [ ] 所有类、接口、DTO 使用大驼峰命名
- [ ] 所有常量和枚举值使用全大写 + 下划线命名
- [ ] 所有路由使用全小写 + 短横线命名
- [ ] 函数名清晰表达其功能
- [ ] 布尔变量使用 is/has/can 前缀
- [ ] 避免使用无意义的缩写
- [ ] 注释使用标准JSDoc标签
- [ ] 修改记录使用标准化修改类型
- [ ] 版本号遵循语义化版本规范
- [ ] 修改现有文件时添加了修改记录和更新版本号
- [ ] 修改记录只保留最近5次，保持注释简洁

## 工具配置

### ESLint 配置建议

```json
{
  "rules": {
    "@typescript-eslint/naming-convention": [
      "error",
      {
        "selector": "variable",
        "format": ["camelCase", "UPPER_CASE"]
      },
      {
        "selector": "function",
        "format": ["camelCase"]
      },
      {
        "selector": "class",
        "format": ["PascalCase"]
      },
      {
        "selector": "interface",
        "format": ["PascalCase"]
      }
    ]
  }
}
```

## 总结

遵循统一的命名规范能够：

- 提高代码可读性
- 减少团队沟通成本
- 降低代码维护难度
- 避免命名冲突
- 提升项目专业度

记住：**好的命名是自解释的，不需要额外的注释。**
