代码规范
分类:elysia
发布于:
阅读时间:48 分钟
EndWorld 代码规范
总体原则
- 类型安全优先: 使用 TypeScript 和 TypeBox 确保类型安全
- 一致性: 保持代码风格和结构的一致性
- 可读性: 代码应该自文档化,必要时添加注释
- 可维护性: 模块化设计,便于后续扩展和维护
文件和目录结构
数据库模型文件 (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: 修复bugrefactor: 重构代码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" };
};
遵循这些规范可以确保代码质量、一致性和可维护性。所有新代码都应该符合这些标准。