Skip to content

代码规范

本文档定义了XAI-SDK项目的代码规范和最佳实践,确保代码的一致性、可读性和可维护性。

📋 总体原则

核心理念

  1. 一致性:保持代码风格的一致性
  2. 可读性:代码应该易于理解和维护
  3. 简洁性:避免不必要的复杂性
  4. 安全性:遵循安全编码实践
  5. 性能:考虑性能影响

代码质量标准

  • 测试覆盖率: >= 90%
  • 复杂度: 圈复杂度 <= 10
  • 文件大小: <= 500行
  • 函数长度: <= 50行
  • 参数数量: <= 5个

🎯 TypeScript规范

基本配置

json
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "exactOptionalPropertyTypes": true
  }
}

类型定义

接口命名

typescript
// ✅ 好的做法
interface UserConfig {
  name: string;
  age: number;
}

interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

// ❌ 避免的做法
interface IUserConfig {
  // 不要使用I前缀
  name: string;
  age: number;
}

类型别名

typescript
// ✅ 好的做法
type EventType = 'click' | 'hover' | 'focus';
type UserId = string;
type Callback<T> = (data: T) => void;

// ❌ 避免的做法
type eventType = 'click' | 'hover' | 'focus'; // 首字母应大写

泛型约束

typescript
// ✅ 好的做法
interface Identifiable {
  id: string;
}

function updateEntity<T extends Identifiable>(entity: T): T {
  // 实现
  return entity;
}

// ❌ 避免的做法
function updateEntity<T>(entity: T): T {
  // 缺少约束,类型不安全
  return entity;
}

函数定义

函数签名

typescript
// ✅ 好的做法
function processUser(
  user: User,
  options: ProcessOptions = {}
): Promise<ProcessResult> {
  // 实现
}

// 箭头函数用于简单操作
const formatName = (firstName: string, lastName: string): string =>
  `${firstName} ${lastName}`;

// ❌ 避免的做法
function processUser(user: any, options?: any): any {
  // 类型不明确
}

异步函数

typescript
// ✅ 好的做法
async function fetchUserData(userId: string): Promise<User> {
  try {
    const response = await api.get(`/users/${userId}`);
    return response.data;
  } catch (error) {
    throw new UserNotFoundError(`User ${userId} not found`);
  }
}

// ❌ 避免的做法
function fetchUserData(userId: string): Promise<any> {
  return api
    .get(`/users/${userId}`)
    .then(response => response.data)
    .catch(error => {
      // 错误处理不当
      console.log(error);
    });
}

类定义

类结构

typescript
// ✅ 好的做法
class UserManager {
  private readonly users: Map<string, User> = new Map();
  private readonly logger: Logger;

  constructor(logger: Logger) {
    this.logger = logger;
  }

  public async createUser(userData: CreateUserData): Promise<User> {
    this.validateUserData(userData);

    const user = new User(userData);
    this.users.set(user.id, user);

    this.logger.info(`User created: ${user.id}`);
    return user;
  }

  private validateUserData(userData: CreateUserData): void {
    if (!userData.email) {
      throw new ValidationError('Email is required');
    }
  }
}

访问修饰符

typescript
// ✅ 明确使用访问修饰符
class ApiClient {
  private readonly baseUrl: string;
  protected readonly timeout: number;
  public readonly version: string;

  public constructor(config: ApiConfig) {
    this.baseUrl = config.baseUrl;
    this.timeout = config.timeout ?? 5000;
    this.version = config.version;
  }
}

🎨 命名规范

变量和函数

typescript
// ✅ 好的做法
const userName = 'john_doe';
const isUserActive = true;
const userCount = 42;

function getUserById(id: string): User | null {
  // 实现
}

function calculateTotalPrice(items: Item[]): number {
  // 实现
}

// ❌ 避免的做法
const u = 'john_doe'; // 名称太短
const user_name = 'john_doe'; // 使用下划线
const UserName = 'john_doe'; // 首字母大写(应该是常量)

function calc(items: any[]): number {
  // 名称不明确
}

常量

typescript
// ✅ 好的做法
const MAX_RETRY_COUNT = 3;
const API_ENDPOINTS = {
  USERS: '/api/users',
  POSTS: '/api/posts',
} as const;

const DEFAULT_CONFIG: Readonly<Config> = {
  timeout: 5000,
  retries: 3,
};

// ❌ 避免的做法
const maxRetryCount = 3; // 应该全大写
const apiEndpoints = {
  users: '/api/users', // 应该全大写
};

类和接口

typescript
// ✅ 好的做法
class HttpClient {
  // 实现
}

interface DatabaseConnection {
  connect(): Promise<void>;
  disconnect(): Promise<void>;
}

type RequestHandler = (req: Request) => Promise<Response>;

// ❌ 避免的做法
class httpClient {
  // 首字母应大写
  // 实现
}

interface databaseConnection {
  // 首字母应大写
  // 实现
}

文件命名

// ✅ 好的做法
user-manager.ts
api-client.ts
config.types.ts
user.test.ts
utils.spec.ts

// ❌ 避免的做法
UserManager.ts
APIClient.ts
user_manager.ts

📁 文件组织

目录结构

src/
├── core/                   # 核心功能
│   ├── sdk.ts
│   ├── config.ts
│   └── types.ts
├── adapters/              # 适配器
│   ├── base/
│   │   ├── adapter.ts
│   │   ├── types.ts
│   │   └── index.ts
│   ├── openai/
│   └── anthropic/
├── plugins/               # 插件
├── tools/                 # 工具
├── utils/                 # 工具函数
│   ├── validation.ts
│   ├── formatting.ts
│   └── index.ts
└── types/                 # 全局类型
    ├── common.ts
    ├── api.ts
    └── index.ts

导入导出

导入顺序

typescript
// ✅ 好的做法
// 1. Node.js内置模块
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';

// 2. 第三方库
import axios from 'axios';
import { z } from 'zod';

// 3. 内部模块(按路径深度排序)
import { Config } from '../config';
import { Logger } from '../utils/logger';
import { User } from './user';

// 4. 类型导入(分组)
import type { ApiResponse } from '../types/api';
import type { UserData } from './types';

导出方式

typescript
// ✅ 好的做法 - 命名导出
export class UserManager {
  // 实现
}

export interface UserConfig {
  // 定义
}

export type UserId = string;

// 默认导出用于主要功能
export default class XAI_SDK {
  // 实现
}

// ❌ 避免的做法
export default {
  UserManager,
  UserConfig,
}; // 避免对象形式的默认导出

索引文件

typescript
// src/adapters/index.ts
export { BaseAdapter } from './base';
export { OpenAIAdapter } from './openai';
export { AnthropicAdapter } from './anthropic';

export type { AdapterConfig } from './base/types';
export type { OpenAIConfig } from './openai/types';
export type { AnthropicConfig } from './anthropic/types';

🔧 ESLint配置

基础配置

javascript
// eslint.config.js
import js from '@eslint/js';
import typescript from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';

export default [
  js.configs.recommended,
  {
    files: ['**/*.ts', '**/*.tsx'],
    languageOptions: {
      parser: typescriptParser,
      parserOptions: {
        ecmaVersion: 2022,
        sourceType: 'module',
        project: './tsconfig.json',
      },
    },
    plugins: {
      '@typescript-eslint': typescript,
    },
    rules: {
      // TypeScript规则
      '@typescript-eslint/no-unused-vars': 'error',
      '@typescript-eslint/no-explicit-any': 'error',
      '@typescript-eslint/prefer-const': 'error',
      '@typescript-eslint/no-non-null-assertion': 'error',

      // 代码风格
      'prefer-const': 'error',
      'no-var': 'error',
      'object-shorthand': 'error',
      'prefer-template': 'error',

      // 最佳实践
      eqeqeq: ['error', 'always'],
      'no-console': 'warn',
      'no-debugger': 'error',
    },
  },
];

自定义规则

javascript
// 项目特定规则
rules: {
  // 强制使用特定的错误类型
  'prefer-custom-error': 'error',

  // 禁止使用console.log(除了特定情况)
  'no-console': ['error', { allow: ['warn', 'error'] }],

  // 强制异步函数返回Promise
  '@typescript-eslint/promise-function-async': 'error',

  // 禁止空的catch块
  'no-empty': ['error', { allowEmptyCatch: false }]
}

🎨 Prettier配置

javascript
// prettier.config.js
export default {
  // 基础格式
  printWidth: 80,
  tabWidth: 2,
  useTabs: false,
  semi: false,
  singleQuote: true,
  quoteProps: 'as-needed',

  // 尾随逗号
  trailingComma: 'es5',

  // 括号
  bracketSpacing: true,
  bracketSameLine: false,
  arrowParens: 'avoid',

  // 换行
  endOfLine: 'lf',

  // TypeScript
  parser: 'typescript',

  // 覆盖特定文件类型
  overrides: [
    {
      files: '*.json',
      options: {
        parser: 'json',
        printWidth: 120,
      },
    },
    {
      files: '*.md',
      options: {
        parser: 'markdown',
        printWidth: 100,
        proseWrap: 'always',
      },
    },
  ],
};

📝 注释规范

JSDoc注释

typescript
/**
 * 用户管理器,负责用户的创建、更新和删除操作
 *
 * @example
 * ```typescript
 * const manager = new UserManager(logger)
 * const user = await manager.createUser({
 *   name: 'John Doe',
 *   email: 'john@example.com'
 * })
 * ```
 */
class UserManager {
  /**
   * 创建新用户
   *
   * @param userData - 用户数据
   * @param options - 创建选项
   * @returns 创建的用户对象
   *
   * @throws {ValidationError} 当用户数据无效时
   * @throws {DuplicateUserError} 当用户已存在时
   *
   * @example
   * ```typescript
   * const user = await manager.createUser({
   *   name: 'John Doe',
   *   email: 'john@example.com'
   * })
   * ```
   */
  async createUser(
    userData: CreateUserData,
    options: CreateUserOptions = {}
  ): Promise<User> {
    // 实现
  }
}

内联注释

typescript
// ✅ 好的做法
function calculatePrice(items: Item[]): number {
  // 计算基础价格
  const basePrice = items.reduce((sum, item) => sum + item.price, 0);

  // 应用折扣(如果有)
  const discount = calculateDiscount(basePrice);

  // 添加税费
  const tax = basePrice * TAX_RATE;

  return basePrice - discount + tax;
}

// ❌ 避免的做法
function calculatePrice(items: Item[]): number {
  const basePrice = items.reduce((sum, item) => sum + item.price, 0); // 计算价格
  const discount = calculateDiscount(basePrice); // 折扣
  const tax = basePrice * TAX_RATE; // 税
  return basePrice - discount + tax; // 返回总价
}

TODO注释

typescript
// ✅ 好的做法
// TODO(username): 添加缓存机制以提高性能 - Issue #123
// FIXME(username): 修复并发访问时的竞态条件 - 2024-01-15
// HACK(username): 临时解决方案,等待上游库修复

// ❌ 避免的做法
// TODO: 优化这个函数
// FIXME: 有bug

🧪 测试规范

测试文件结构

typescript
// user-manager.test.ts
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { UserManager } from '../user-manager';
import { createMockLogger } from '../../test-utils';

describe('UserManager', () => {
  let userManager: UserManager;
  let mockLogger: MockLogger;

  beforeEach(() => {
    mockLogger = createMockLogger();
    userManager = new UserManager(mockLogger);
  });

  afterEach(() => {
    // 清理资源
  });

  describe('createUser', () => {
    it('should create user with valid data', async () => {
      // Arrange
      const userData = {
        name: 'John Doe',
        email: 'john@example.com',
      };

      // Act
      const user = await userManager.createUser(userData);

      // Assert
      expect(user).toBeDefined();
      expect(user.name).toBe(userData.name);
      expect(user.email).toBe(userData.email);
    });

    it('should throw ValidationError for invalid email', async () => {
      // Arrange
      const userData = {
        name: 'John Doe',
        email: 'invalid-email',
      };

      // Act & Assert
      await expect(userManager.createUser(userData)).rejects.toThrow(
        ValidationError
      );
    });
  });
});

测试命名

typescript
// ✅ 好的做法
describe('UserManager', () => {
  describe('createUser', () => {
    it('should create user with valid data', () => {});
    it('should throw ValidationError when email is invalid', () => {});
    it('should throw DuplicateUserError when user already exists', () => {});
  });

  describe('updateUser', () => {
    it('should update existing user', () => {});
    it('should throw UserNotFoundError when user does not exist', () => {});
  });
});

// ❌ 避免的做法
describe('UserManager', () => {
  it('test1', () => {}); // 名称不明确
  it('should work', () => {}); // 太模糊
  it('createUser should create user and updateUser should update user', () => {}); // 测试多个功能
});

🚨 错误处理

自定义错误类

typescript
// ✅ 好的做法
export class ValidationError extends Error {
  constructor(
    message: string,
    public readonly field?: string,
    public readonly code: string = 'VALIDATION_ERROR'
  ) {
    super(message);
    this.name = 'ValidationError';
  }
}

export class UserNotFoundError extends Error {
  constructor(
    public readonly userId: string,
    public readonly code: string = 'USER_NOT_FOUND'
  ) {
    super(`User with ID ${userId} not found`);
    this.name = 'UserNotFoundError';
  }
}

错误处理模式

typescript
// ✅ 好的做法
async function processUser(userId: string): Promise<ProcessResult> {
  try {
    const user = await userRepository.findById(userId);
    if (!user) {
      throw new UserNotFoundError(userId);
    }

    const result = await processUserData(user);
    return result;
  } catch (error) {
    if (error instanceof UserNotFoundError) {
      logger.warn(`User not found: ${userId}`);
      throw error;
    }

    if (error instanceof ValidationError) {
      logger.warn(`Validation failed: ${error.message}`);
      throw error;
    }

    logger.error('Unexpected error processing user', { userId, error });
    throw new ProcessingError('Failed to process user', { cause: error });
  }
}

// ❌ 避免的做法
async function processUser(userId: string): Promise<any> {
  try {
    const user = await userRepository.findById(userId);
    return await processUserData(user);
  } catch (error) {
    console.log(error); // 不当的错误处理
    return null;
  }
}

📊 性能最佳实践

异步操作

typescript
// ✅ 好的做法
async function processUsers(userIds: string[]): Promise<User[]> {
  // 并行处理
  const users = await Promise.all(
    userIds.map(id => userRepository.findById(id))
  );

  return users.filter(user => user !== null);
}

// 批量操作
async function createUsers(usersData: CreateUserData[]): Promise<User[]> {
  return await userRepository.createMany(usersData);
}

// ❌ 避免的做法
async function processUsers(userIds: string[]): Promise<User[]> {
  const users: User[] = [];

  // 串行处理,性能差
  for (const id of userIds) {
    const user = await userRepository.findById(id);
    if (user) {
      users.push(user);
    }
  }

  return users;
}

内存管理

typescript
// ✅ 好的做法
class DataProcessor {
  private readonly cache = new Map<string, ProcessedData>();
  private readonly maxCacheSize = 1000;

  process(data: RawData): ProcessedData {
    const key = this.generateCacheKey(data);

    if (this.cache.has(key)) {
      return this.cache.get(key)!;
    }

    const processed = this.processData(data);

    // 限制缓存大小
    if (this.cache.size >= this.maxCacheSize) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }

    this.cache.set(key, processed);
    return processed;
  }

  dispose(): void {
    this.cache.clear();
  }
}

🔒 安全最佳实践

输入验证

typescript
// ✅ 好的做法
import { z } from 'zod';

const CreateUserSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().min(0).max(150).optional(),
});

function createUser(userData: unknown): Promise<User> {
  const validatedData = CreateUserSchema.parse(userData);
  return userRepository.create(validatedData);
}

// ❌ 避免的做法
function createUser(userData: any): Promise<User> {
  // 没有验证,不安全
  return userRepository.create(userData);
}

敏感信息处理

typescript
// ✅ 好的做法
class ApiClient {
  private readonly apiKey: string;

  constructor(apiKey: string) {
    this.apiKey = apiKey;
  }

  private getHeaders(): Record<string, string> {
    return {
      Authorization: `Bearer ${this.apiKey}`,
      'Content-Type': 'application/json',
    };
  }

  // 日志中不暴露敏感信息
  private logRequest(url: string, method: string): void {
    logger.info('API request', {
      url,
      method,
      // 不记录Authorization header
    });
  }
}

遵循这些代码规范将帮助我们维护高质量、一致的代码库。如有疑问或建议,请在团队讨论中提出。

Released under the MIT License.