NanoFlow 项目编码标准和约定
NanoFlow 项目的统一编码标准和最佳实践。
@Component({
selector: 'app-task-card',
standalone: true, // ✅ 独立组件
changeDetection: ChangeDetectionStrategy.OnPush, // ✅ OnPush
imports: [CommonModule, ...],
template: `...`
})
export class TaskCardComponent {
// ✅ 使用 Signals
private readonly store = inject(StoreService);
// ✅ input/output 信号
task = input.required<Task>();
taskSelected = output<string>();
// ✅ computed 派生状态
isCompleted = computed(() => this.task().status === 'completed');
}
@Injectable({ providedIn: 'root' })
export class TaskOperationService {
// ✅ 使用 Result 模式
async createTask(data: TaskInput): Promise<Result<Task, AppError>> {
try {
const task = await this.repository.create(data);
return success(task);
} catch (error) {
return failure(ErrorCodes.CREATE_FAILED, '创建任务失败');
}
}
}
| 类型 | 建议行数 | 最大行数 |
|---|---|---|
| 组件 | 100-200 | 400 |
| 服务 | 150-300 | 500 |
| 工具函数 | 50-100 | 200 |
| 测试文件 | 100-300 | 600 |
超过限制的处理:
// 文件命名:kebab-case
task-operation.service.ts
flow-view.component.ts
result.utils.ts
// 类命名:PascalCase
class TaskOperationService {}
class FlowViewComponent {}
// 变量/函数:camelCase
const taskList = [];
function calculateTotal() {}
// 常量:SCREAMING_SNAKE_CASE
const MAX_RETRY_COUNT = 3;
const SYNC_DEBOUNCE_DELAY = 3000;
// 接口:PascalCase,不加 I 前缀
interface Task {} // ✅
interface ITask {} // ❌
// ✅ 使用 Result 类型
type Result<T, E> =
| { ok: true; value: T }
| { ok: false; error: E };
// 使用
const result = await service.createTask(data);
if (result.ok) {
console.log(result.value);
} else {
console.error(result.error);
}
| 级别 | 处理方式 | 示例 |
|---|---|---|
| SILENT | 仅日志 | ResizeObserver 循环 |
| NOTIFY | Toast 提示 | 保存失败 |
| RECOVERABLE | 恢复对话框 | 同步冲突 |
| FATAL | 错误页面 | Store 初始化失败 |
// ✅ 中文注释描述业务逻辑
/**
* 计算任务的 displayId
* 格式:父任务序号 + 当前任务字母,如 "1,a"
*
* @param task 目标任务
* @param siblings 同级任务列表
* @returns 格式化的 displayId
*/
function calculateDisplayId(task: Task, siblings: Task[]): string {
// 获取父任务的序号
const parentIndex = getParentIndex(task.parentId);
// 计算当前任务在同级中的位置
const siblingIndex = siblings.findIndex(t => t.id === task.id);
return `${parentIndex},${indexToLetter(siblingIndex)}`;
}
describe('TaskOperationService', () => {
// ✅ 清晰的测试描述
it('should create task with generated UUID', async () => {
// Arrange
const input = { title: 'Test Task' };
// Act
const result = await service.createTask(input);
// Assert
expect(result.ok).toBe(true);
expect(result.value.id).toMatch(UUID_REGEX);
});
// ✅ 测试边界情况
it('should return error when title is empty', async () => {
const result = await service.createTask({ title: '' });
expect(result.ok).toBe(false);
expect(result.error.code).toBe(ErrorCodes.VALIDATION_FAILED);
});
});
| everything-claude-code | 本项目实现 |
|---|---|
rules/coding-style.md | .github/instructions/frontend.instructions.md |
| Code style instincts | 本 skill 文件 |
| Linting hooks | ESLint + Prettier 配置 |
项目使用的工具:
# 检查 + 修复
npm run lint:fix
# 仅检查
npm run lint
# 类型检查
npx tsc --noEmit
# 格式化
npx prettier --write .