返回首页

代码规范

分类:elysia
发布于:
阅读时间:48 分钟

EndWorld 代码规范

总体原则

  1. 类型安全优先: 使用 TypeScript 和 TypeBox 确保类型安全
  2. 一致性: 保持代码风格和结构的一致性
  3. 可读性: 代码应该自文档化,必要时添加注释
  4. 可维护性: 模块化设计,便于后续扩展和维护

文件和目录结构

数据库模型文件 (src/db/model/)

// 文件命名: 小驼峰 + .ts
// 例如: player.ts, enemyer.ts, stage.ts, wave.ts

// 标准文件结构:
import { relations } from "drizzle-orm";
import { ... } from "drizzle-orm/pg-core";
import {
  createInsertSchema,
  createSelectSchema,
  createUpdateSchema,
} from "drizzle-typebox";
import { t } from "elysia";
import { UnoPageQuerySchema } from "./utils";

// 1. 表定义
export const xxxTable = pgTable("table_name", {
  id: serial("id").primaryKey(),
  // 字段定义...
});

// 2. 关系定义
export const xxxRelations = relations(xxxTable, ({ one, many }) => ({
  // 关系配置...
}));

// 3. Model Namespace
export namespace XxxModel {
  // Schemas 和类型定义...
}

命名规范

1. 数据库相关

// 表名: 小写下划线
const playersTable = pgTable("player", {...});
const waveEnemyerTable = pgTable("wave_enemyer", {...});

// 字段名: 小写下划线
id: serial("id").primaryKey(),
basic_instance_id: integer("basic_instance_id"),
created_at: timestamp("created_at").defaultNow(),

// 变量名: 小驼峰
const playersTable = pgTable("player");
const stageRelations = relations(stageTable);

2. Schema 和类型

// Namespace: 大驼峰 + Model
export namespace PlayerModel { }
export namespace StageModel { }
export namespace WaveModel { }

// Schema: 大驼峰
export const Insert = createInsertSchema(playersTable);
export const Create = t.Omit(Insert, ["id"]);
export const ListQuery = t.Composite([UnoPageQuerySchema, ...]);

// 类型: 大驼峰
export type Entity = typeof Select.static;
export type ViewObject = Entity & {...};
export type CreateInput = typeof Create.static;

3. 函数和变量

// 函数: 小驼峰
function createPlayer() { }
function validateStageInput() { }

// 变量: 小驼峰
const playerName = "hero";
const stageList = [];
const isCompleted = true;

// 常量: 大写下划线
const MAX_PLAYERS = 100;
const DEFAULT_DIFFICULTY = 1;

代码格式规范

1. 导入顺序

// 1. Node.js 内置模块
import { readFileSync } from "fs";

// 2. 第三方库
import { Elysia } from "elysia";
import { relations } from "drizzle-orm";

// 3. 项目内部模块
import { UnoPageQuerySchema } from "./utils";
import { playersTable } from "./player";

2. 注释规范

/**
 * 模块/文件描述
 * 说明模块的作用和主要功能
 */

// 单行注释: 解释具体实现
export const playersTable = pgTable("player", {
  id: serial("id").primaryKey(), // 行内注释: 解释字段含义
  name: varchar("name", { length: 100 }), // 玩家名称
});

/**
 * 函数/方法描述
 * @param param 参数说明
 * @returns 返回值说明
 */
function calculateLevel(exp: number): number {
  // 实现注释: 解释复杂逻辑
  return Math.floor(exp / 100) + 1;
}

// =<mark> 分组注释 </mark>=
// =<mark> 基础 TypeBox Schema </mark>=
export const Insert = createInsertSchema(playersTable);

// =<mark> 业务 DTO Schemas </mark>=
export const Create = t.Omit(Insert, ["id"]);

3. 类型定义规范

// 基础类型: 使用自动生成
export const Insert = createInsertSchema(playersTable);
export const Select = createSelectSchema(playersTable);
export const Update = createUpdateSchema(playersTable);

// 业务类型: 基于基础类型组合
export const Create = t.Omit(Insert, ["id"]);
export const Patch = t.Omit(Update, ["id", "basicInstanceID"]);

// 复杂类型: 详细定义和验证
export const PlayerStats = t.Object({
  level: t.Integer({ minimum: 1, maximum: 100 }),
  exp: t.Integer({ minimum: 0 }),
  name: t.String({ minLength: 1, maxLength: 50 }),
});

// TypeScript 类型: 基于 Schema
export type Entity = typeof Select.static;
export type CreateInput = typeof Create.static;

数据库模型规范

1. 表定义规范

export const playersTable = pgTable("player", {
  id: serial("id").primaryKey(), // 主键
  basicInstanceID: integer("basic_instance_id")
    .notNull()
    .references(() => basicInstancesTable.id), // 外键
  level: integer("level").notNull().default(1), // 默认值
  property: jsonb("property")
    .$type<{...}>()
    .notNull()
    .default({}), // JSON 类型
});

2. 关系定义规范

export const playersRelations = relations(playersTable, ({ one, many }) => ({
  basicInstance: one(basicInstancesTable, {
    fields: [playersTable.basicInstanceID],
    references: [basicInstancesTable.id],
  }),
  gameRecords: many(gameRecordsTable),
}));

3. Model Namespace 规范

export namespace PlayerModel {
  // =<mark> 基础 Schema </mark>=
  export const Insert = createInsertSchema(playersTable);
  export const Update = createUpdateSchema(playersTable);
  export const Select = createSelectSchema(playersTable);

  // =<mark> 业务 DTO </mark>=
  export const Create = t.Omit(Insert, ["id"]);
  export const Patch = t.Omit(Update, ["id", "basicInstanceID"]);

  // =<mark> 查询 Schema </mark>=
  export const ListQuery = t.Composite([
    UnoPageQuerySchema,
    t.Object({
      level: t.Optional(t.Integer({ minimum: 1 })),
      search: t.Optional(t.String()),
    }),
  ]);

  // =<mark> 类型定义 </mark>=
  export type Entity = typeof Select.static;
  export type CreateInput = typeof Create.static;
  export type ListQueryInput = typeof ListQuery.static;

  // =<mark> 展示类型 </mark>=
  export type ViewObject = Entity & {
    gameRecords?: GameRecordModel.ViewObject[];
    totalGames: number;
    winRate: number;
  };

  // =<mark> 业务类型 </mark>=
  export type PlayerStats = {
    totalPlayers: number;
    averageLevel: number;
    // ...
  };
}

路由代码规范

1. 路由文件结构

// src/routes/xxx/index.ts
import { Elysia } from "elysia";
import { XxxModel } from "../../db/model/xxx";

export const xxxRoutes = new Elysia({ prefix: "/xxx" })
  .get("/", async ({ query }) => {
    // 实现逻辑
  })
  .post("/", async ({ body }) => {
    // 实现逻辑
  });

// src/routes/xxx/[id].ts
export const xxxIdRoutes = new Elysia({ prefix: "/xxx/:id" })
  .get("/", async ({ params }) => {
    // 实现逻辑
  });

2. 错误处理规范

// 统一错误响应
export const handleError = (error: unknown, message: string) => {
  console.error(message, error);
  return {
    success: false,
    message,
    error: error instanceof Error ? error.message : String(error),
  };
};

// 使用示例
.get("/:id", async ({ params, error }) => {
  try {
    const result = await getPlayerById(params.id);
    return { success: true, data: result };
  } catch (err) {
    throw error(500, handleError(err, "Failed to get player"));
  }
})

工具函数规范

1. 工具文件结构

// src/utils/validation.ts
import { t } from "elysia";

export const PaginationSchema = t.Object({
  page: t.Integer({ minimum: 1, default: 1 }),
  limit: t.Integer({ minimum: 1, maximum: 100, default: 10 }),
});

export const DateRangeSchema = t.Object({
  startDate: t.Optional(t.Date()),
  endDate: t.Optional(t.Date()),
});

2. 常量定义

// src/constants/game.ts
export const GAME_CONSTANTS = {
  MAX_LEVEL: 100,
  EXP_PER_LEVEL: 1000,
  DEFAULT_HP: 100,
} as const;

export const DIFFICULTY_LEVELS = {
  EASY: 1,
  NORMAL: 2,
  HARD: 3,
  EXTREME: 4,
} as const;

测试规范

1. 测试文件命名

// 单元测试
xxx.test.ts
xxx.spec.ts

// 集成测试
integration/xxx.test.ts

2. 测试结构

import { describe, it, expect } from "bun:test";

describe("PlayerModel", () => {
  describe("Create Schema", () => {
    it("should validate valid input", () => {
      const input = { name: "Test Player" };
      expect(() => PlayerModel.Create.parse(input)).not.toThrow();
    });

    it("should reject invalid input", () => {
      const input = { name: "" }; // 无效名称
      expect(() => PlayerModel.Create.parse(input)).toThrow();
    });
  });
});

Git 提交规范

1. 提交信息格式

<type>(<scope>): <description>

<body>

<footer>

2. 提交类型

  • feat: 新功能
  • fix: 修复bug
  • refactor: 重构代码
  • style: 代码格式调整
  • docs: 文档更新
  • test: 测试相关
  • chore: 构建工具、依赖更新

3. 示例

git commit -m "feat(model): 添加关卡波次数据模型

- 新增 stage.ts 和 wave.ts 模型文件
- 添加完整的 TypeBox namespace 定义
- 支持关卡-波次-敌人的游戏逻辑

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>"

性能优化规范

1. 数据库查询

// 使用索引优化查询
const stages = await db.select()
  .from(stageTable)
  .where(eq(stageTable.difficulty, difficulty))
  .limit(limit);

// 避免N+1查询
const stagesWithWaves = await db.query({
  stages: {
    with: {
      waves: {
        with: {
          waveEnemyers: {
            with: {
              enemyer: true
            }
          }
        }
      }
    }
  }
});

2. 类型优化

// 使用Pick减少不必要的字段
export const PlayerListResponse = t.Pick(PlayerModel.Select, [
  "id", "name", "level"
]);

// 使用Partial处理可选更新
export const PlayerUpdate = t.Partial(PlayerModel.Patch);

安全规范

1. 输入验证

// 始终验证用户输入
export const CreateUserSchema = t.Object({
  username: t.String({
    minLength: 3,
    maxLength: 20,
    pattern: /^[a-zA-Z0-9_]+$/,
  }),
  email: t.String({ format: "email" }),
});

// 使用schema验证
const result = CreateUserSchema.safeParse(body);
if (!result.success) {
  throw error(400, { message: "Invalid input", errors: result.error });
}

2. 错误处理

// 不要暴露敏感信息
export const handleError = (error: unknown) => {
  if (error instanceof DatabaseError) {
    console.error("Database error:", error);
    return { message: "Internal server error" };
  }

  if (error instanceof ValidationError) {
    return { message: "Invalid input", details: error.message };
  }

  return { message: "An error occurred" };
};

遵循这些规范可以确保代码质量、一致性和可维护性。所有新代码都应该符合这些标准。