feat: 添加项目代码规范文档,包含 JS/TS 基础规范、文件命名、NestJS 项目规范和测试代码规范

This commit is contained in:
Lyda
2026-01-22 12:06:02 +08:00
parent 24d7dc34c7
commit f6861a9c8d
7 changed files with 587 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
# Review Spec
该仓库是小管家代码规范仓库,规范是基于 Gitea Flows Review Spec 协议编写。

130
docs/js&ts.base.md Normal file
View File

@@ -0,0 +1,130 @@
# 基础代码规范 `[JsTs.Base]`
下面是 JS/TS 的代码规范
## 常量名使用大写加下划线命名UPPER_CASE单词间以下划线分隔 `[JsTs.Base.ConstUpperCase]`
### Good
```javascript
const MAX_COUNT = 100;
```
### Bad
```javascript
const maxCount = 100;
```
## 函数名使用小驼峰命名 `[JsTs.Base.FuncLowerCamel]`
### Good
```javascript
function getUserInfo() {
// ...
}
```
### Bad
```javascript
function getuserinfo() {
// ...
}
```
## 禁止使用字面量魔法字符串和魔法数字 `[JsTs.Base.NoMagicStringsAndNumbers]`
- 只检查数字字面量和字符串字面量,不要检查其他(比如 布尔字面量)
- 无需检查单词是否完整拼写
- throw 的错误信息无需审查
- new Error 的错误信息无需审查
- console.log 的打印代码无需审查
- console.error 的错误信息无需审查
- console.warn 的错误信息无需审查
- console.info 的错误信息无需审查
- console.debug 的错误信息无需审查
- console.trace 的错误信息无需审查
- 无需考虑类型是否合理匹配
### Good
```javascript
const MAX_COUNT = 100;
const USER_STATUS = {
ACTIVE: "active",
INACTIVE: "inactive",
};
```
### Bad
```javascript
const maxCount = 100;
const userStatus = "active";
```
## class 和 interface 命名使用大驼峰命名 `[JsTs.Base.ClassUpperCamel]`
### Good
```javascript
class UserInfo {
// ...
}
```
### Bad
```javascript
class userinfo {
// ...
}
```
## 变量名使用小驼峰命名 `[JsTs.Base.VarLowerCamel]`
### Good
```javascript
let userName = "John";
```
### Bad
```javascript
let username = "John";
```
## 单文件代码不超过 700 行 `[JsTs.Base.CodeNotMoreThan700Lines]`
### Good
```javascript
// 代码不超过 700 行
```
### Bad
```javascript
// 代码超过 700 行
```
## 单个函数或方法不能超出 200 行 `[JsTs.Base.FuncNotMoreThan200Lines]`
### Good
```javascript
function getUserInfo() {
// ... 小于等于 200
}
```
### Bad
```javascript
function getUserInfo() {
// ... 大于 200
}
```

49
docs/js&ts.file-name.md Normal file
View File

@@ -0,0 +1,49 @@
# 文件命名规范 `[JsTs.FileName]`
下面是 JS/TS 的文件命名规范.
## class 和 interface 文件使用大驼峰命名 `[JsTs.FileName.UpperCamel]`
- 文件名必须与主导类或接口名称完全一致。
- 适用于定义单一主要实体的文件。
### Good
```javascript
// UserInfo.js
class UserInfo {
// ...
}
```
### Bad
```javascript
// userinfo.js
class userinfo {
// ...
}
```
## 函数文件使用小驼峰命名 `[JsTs.FileName.LowerCamel]`
- 适用于导出一个或多个工具函数的文件。
- 文件名应反映其包含的核心功能。
### Good
```javascript
// getUserInfo.js
function getUserInfo() {
// ...
}
```
### Bad
```javascript
// getuserinfo.js
function getuserinfo() {
// ...
}
```

244
docs/js&ts.nest.md Normal file
View File

@@ -0,0 +1,244 @@
# Nestjs 项目下的规范 `[JsTs.Nest]`
> - includes `*.controller.ts` `*.service.ts` `*.module.ts` `*.dto.ts` `*.pipe.ts` `*.guard.ts` `*.interceptor.ts` `*.filter.ts` `*.exception-filter.ts` `*.proxy.ts` `*.model.ts`
> - override `[JsTs.FileName]`
## 目录框架规范 `[JsTs.Nest.DirStructure]`
- 使用下面的 Good 目录结构
- 文件名使用小写加横线命名(如 `user-extends.module.ts`
- 每个模块的目录下必须包含 `module.ts` 文件
- 每个模块的目录下必须包含 `controller.ts` 文件
- 每个模块的目录下必须包含 `service.ts` 文件
- 每个模块的目录下可以包含 `dto` 目录,用于存放数据传输对象
- 每个模块的目录下可以包含 `pipe` 目录,用于存放管道
- 每个模块的目录下可以包含 `guard` 目录,用于存放守卫
- 每个模块的目录下可以包含 `interceptor` 目录,用于存放拦截器
- 每个模块的目录下可以包含 `filter` 目录,用于存放异常过滤器
### Good
```txt
src/
├── user/ # 用户模块
│ ├── user.module.ts
│ ├── user.controller.ts
│ ├── user.service.ts
│ ├── user.proxy.ts
│ ├── user.model.ts
│ └── dto/ # 数据传输对象
├── auth/ # 认证模块
│ ├── auth.module.ts
│ ├── auth.controller.ts
│ ├── auth.service.ts
│ ├── auth.proxy.ts
│ ├── auth.model.ts
├── common/ # 公共模块
│ ├── filters/ # 异常过滤器
│ ├── guards/ # 守卫
│ ├── interceptors/ # 拦截器
│ └── pipes/ # 管道
├── config/ # 配置文件
├── app.module.ts # 根模块
└── main.ts # 应用入口
```
### Bad
```txt
src/
├── user.controller.ts
├── user.service.ts
├── auth.controller.ts
├── auth.service.ts
├── filter.ts
├── guard.ts
└── main.ts
```
## 控制器命名规范 `[JsTs.Nest.ControllerDefinition]`
- 该文件不能写业务逻辑,只能写调用 service 的代码
- 文件名使用小写加横线命名(如 `user-extends.controller.ts`
- 文件名必须加 `.controller.ts` 后缀
### Good
```txt
user-extends.controller.ts
```
### Bad
```txt
userController.ts
```
## 服务命名规范 `[JsTs.Nest.ServiceDefinition]`
- 这个是目前业务代码核心编写的地方
- 规定不能直接调用数据库查询,只能通过 model 来调用
- 规定不能直接调用旧的业务代码,只能通过 proxy 来调用
- 文件名使用小写加横线命名(如 `user-extends.service.ts`
- 文件名必须加 `.service.ts` 后缀
### Good
```txt
user-extends.service.ts
```
### Bad
```txt
userService.ts
```
## 模块命名规范 `[JsTs.Nest.ModuleDefinition]`
- 文件名使用小写加横线命名(如 `user-extends.module.ts`
- 文件名必须加 `.module.ts` 后缀
### Good
```txt
user-extends.module.ts
```
### Bad
```txt
userModule.ts
```
## Dto 命名规范 `[JsTs.Nest.DtoDefinition]`
- 文件名使用小写加横线命名(如 `user-extends.dto.ts`
- 文件名必须加 `.dto.ts` 后缀
- dto 目录下必须包含 `dto.ts` 文件
### Good
```txt
user-extends.dto.ts
```
### Bad
```txt
userDto.ts
```
## Proxy 编写规范 `[JsTs.Nest.ProxyDefinition]`
- 这是专门为了和旧的业务通讯而存在的和旧代码通讯使用的方式就是 SyncService
- 文件名使用小写加横线命名(如 `user.proxy.ts`
- 文件名必须加 `.proxy.ts` 后缀
- 内部只能写使用 syncService 调用的逻辑
- SyncService 只能在 proxy.ts 中使用
### Good
```typescript
// user.proxy.ts
import { Injectable } from "@nestjs/common";
import { User } from "@app/entity/models";
import { SyncService } from "@app/sync";
@Injectable()
export class UserProxy {
constructor(private readonly syncService: SyncService) {}
getUsersByNames(names: string[], callback: (user: User) => void) {
return this.syncService.call("userProxy").getUsersByNames(names, callback);
}
}
```
### Bad
```typescript
// user.proxy.ts
import { Injectable } from "@nestjs/common";
import { User } from "@app/entity/models";
import { InjectModel } from "@app/entity/decorator";
import { Model } from "mongoose";
@Injectable()
export class UserProxy {
constructor(@InjectModel(User) private readonly userModel: Model<User>) {}
getUsersByNames(names: string[], callback: (user: User) => void) {
return this.userModel.find({ name: { $in: names } }, callback);
// 不能写数据库查询,只能写和旧的业务通讯代码,数据库查询的逻辑要放在 user.model.ts
}
}
```
## Model 编写规范 `[JsTs.Nest.ModelDefinition]`
- 内部只能写使用 model 数据库调用的逻辑
- 文件名使用小写加横线命名(如 `user.model.ts`
- 文件名必须加 `.model.ts` 后缀
### Good
```typescript
// user.model.ts
import { Injectable } from "@nestjs/common";
import { User } from "@app/entity/models";
import { InjectModel } from "@app/entity/decorator";
import { Model } from "mongoose";
@Injectable()
export class UserProxy {
constructor(@InjectModel(User) private readonly userModel: Model<User>) {}
getUsersByNames(names: string[], callback: (user: User) => void) {
return this.userModel.find({ name: { $in: names } }, callback);
}
}
```
### Bad
```typescript
// user.model.ts
import { Injectable } from "@nestjs/common";
import { User } from "@app/entity/models";
import { SyncService } from "@app/sync";
@Injectable()
export class UserProxy {
constructor(private readonly syncService: SyncService) {}
getUsersByNames(names: string[], callback: (user: User) => void) {
return this.syncService.call("userProxy").getUsersByNames(names, callback);
// 不能写和旧的业务通讯代码,只能写数据库查询的逻辑,和旧的业务通讯的代码要放在 proxy.ts 中
}
}
```
## 业务代码编写规范 `[JsTs.Nest.BusinessDefinition]`
- 目前所有的新代码都应该写在 nest 里
### Good
```typescript
// nest-src/apps/app/src/user/user.controller.ts
```
```typescript
// nest-src/apps/app/src/user/user.service.ts
```
```typescript
// nest-src/apps/app/src/user/user.module.ts
```
### Bad
```typescript
// proxy/user.js
```

85
docs/js&ts.test-code.md Normal file
View File

@@ -0,0 +1,85 @@
# 测试代码规范 `[JsTs.TestCode]`
下面是 JS/TS 的测试代码规范.
## 测试文件命名 `[JsTs.TestCode.FileName]`
- 必须以 `.test.js``.test.ts`(或 `.spec.ts`)结尾。
- 前缀部分应与被测试源文件名保持一致。
### Good
```javascript
// userInfo.js
// userInfo.test.js
describe("UserInfo", () => {
// ...
});
```
### Bad
```javascript
// userInfo.js
// userinfo.test.js
describe("userinfo", () => {
// ...
});
```
## 测试代码块命名 `[JsTs.TestCode.BlockName]`
- 测试代码命名结构:`describe(文件名)` -> `describe(函数名/类名.方法名)` -> `it(场景描述)`
- 场景描述应使用 "should ..." 格式,描述预期行为。
### Good
```javascript
// uUerInfo.js
export class UserInfo {
getUserInfo() {
// ...
}
}
// userInfo.test.js
describe("UserInfo", () => {
describe("UserInfo.getUserInfo", () => {
it("should return user info", () => {
// ...
});
});
});
```
```javascript
// userInfo.js
export function getUserInfo() {
// ...
}
// userInfo.test.js
describe("userInfo", () => {
describe("getUserInfo", () => {
it("should return user info", () => {
// ...
});
});
});
```
### Bad
```javascript
// userInfo.js
export function getUserInfo() {
// ...
}
// userInfo.test.js
describe("userInfo", () => {
it("should return user info", () => {
// ...
});
});
```

39
docs/vue.base.md Normal file
View File

@@ -0,0 +1,39 @@
# Vue 基础代码 `[Vue.Base]`
> - includes `*.vue`
## Vue 自定义组件命名规则 `[Vue.Base.CustomComponentName]`
必须使用大驼峰命名并且使用的时候也是,并且至少两个单词。
### Good
```vue
<!-- UserInfo.vue -->
<template>
<div></div>
</template>
<script>
export default {
name: "UserInfo",
// ...
};
</script>
```
### Bad
```vue
<!-- userinfo.vue -->
<template>
<div></div>
</template>
<script>
export default {
name: "userinfo",
// ...
};
</script>
```

37
docs/vue.file-name.md Normal file
View File

@@ -0,0 +1,37 @@
# Vue 文件命名 `[Vue.FileName]`
> - includes `*.vue`
## Vue 组件文件使用大驼峰命名 `[Vue.FileName.UpperCamel]`
### Good
```vue
<!-- UserInfo.vue -->
<template>
<div></div>
</template>
<script>
export default {
name: "UserInfo",
// ...
};
</script>
```
### Bad
```vue
<!-- userinfo.vue -->
<template>
<div></div>
</template>
<script>
export default {
name: "userinfo",
// ...
};
</script>
```