Перейти к основному содержимому

Стандарты кода

Elftia использует строгую конфигурацию ESLint (typescript-eslint/strict) с прогрессивной стратегией применения.


Инструментальная цепочка

ИнструментНазначениеФайл конфигурации
ESLintПроверка качества кода (строгий режим)eslint.config.js
PrettierФорматирование кода.prettierrc
HuskyУправление Git Hooks.husky/pre-commit
lint-stagedПроверка staged-файловpackage.json

Часто используемые команды

# Запустить проверку ESLint
npm run lint:eslint

# Проверить форматирование Prettier
npm run lint:prettier

# Автоматически отформатировать код
npm run format

# Полная lint-проверка (ESLint + TypeScript)
npm run lint

# Проверить один файл
npx eslint path/to/file.ts

# Автоматически исправить один файл
npx eslint path/to/file.ts --fix

Автоматические проверки перед коммитом

При коммите Husky автоматически запускает lint-staged для staged-файлов .ts/.tsx с командой eslint --fix:

  • уровень error: Блокирует коммит, необходимо исправить
  • уровень warn: Выводит предупреждение, коммит разрешён
  • auto-fix: Автоматически исправляет устранимые проблемы, например сортировку импортов

Краткий справочник по правилам ESLint

Уровни серьёзности

УровеньЗначениеПоведение при коммите
errorОбязательно исправитьБлокирует коммит
warnРекомендуется исправитьКоммит разрешён
offОтключено-

Правила уровня error (блокируют коммит)

// simple-import-sort/imports — исправляется автоматически
// Импорты должны быть упорядочены по правилам; eslint --fix исправит автоматически

// prefer-const
let value = 1; // Никогда не переназначается — следует использовать const

// no-var
var x = 1; // Использование var запрещено

// eqeqeq
if (a == b) { } // Использовать == вместо === (кроме проверок на null)

// react-hooks/rules-of-hooks
if (condition) { useState(); } // Хуки можно вызывать только на верхнем уровне

Правила уровня warn (коммит разрешён)

Правила TypeScript

ПравилоОписаниеИсправление
@typescript-eslint/no-unused-varsНеиспользуемые переменныеУдалить или добавить префикс _
@typescript-eslint/no-explicit-anyИспользование типа anyЗаменить конкретным типом или unknown
@typescript-eslint/consistent-type-importsИмпорты без type-толькоЗаменить на import { type Foo }
@typescript-eslint/no-non-null-assertionНенулевое утверждение !Использовать опциональную цепочку ?. или защиту типа

Правила React

ПравилоОписаниеИсправление
react-hooks/exhaustive-depsНеполный массив зависимостей хукаДополнить массив зависимостей
react/jsx-no-leaked-renderУтечка рендера (count && <X />)Заменить на count > 0 && <X />
react/self-closing-compПустой тег без самозакрытия<Comp></Comp><Comp />
react/jsx-curly-brace-presenceЛишние фигурные скобкиprop={"val"}prop="val"
react/jsx-boolean-valueИзбыточное булево значениеdisabled={true}disabled
react/hook-use-stateИмя состояния не в camelCase[Value, setV][value, setV]

Прочие правила

ПравилоОписаниеИсправление
no-consoleИспользование console.log в процессе рендерингаЗаменить на console.warn/error/info/debug
jsx-a11y/*Проблемы доступностиСм. Design System

Правила сортировки импортов

Импорты должны быть упорядочены следующим образом (eslint --fix исправит автоматически):

// 1. Встроенные модули Node.js
import path from 'node:path';
import fs from 'node:fs';

// 2. Внешние пакеты
import React, { useState } from 'react';
import { useQuery } from '@tanstack/react-query';

// 3. Внутренний псевдоним @/
import { Button } from '@/components/ui/button';
import { useAppState } from '@/shared/hooks/useAppState';

// 4. Псевдоним @shared/
import type { Message } from '@shared/contracts';

// 5. Псевдоним @main/
import { AppPaths } from '@main/services/infra/paths/paths';

// 6. Импорты из родительских директорий
import { utils } from '../utils';

// 7. Импорты из текущей директории
import { helper } from './helper';

// 8. Импорты стилей
import './styles.css';

Конфигурация Prettier

ОпцияЗначениеОписание
semitrueИспользовать точки с запятой
singleQuotetrueИспользовать одинарные кавычки
tabWidth2Ширина отступа
trailingComma'es5'Завершающие запятые
printWidth100Максимальная длина строки

Ограничения на размер файлов

Золотое правило: один файл не должен превышать 600 строк кода.

Тип файлаРекомендуемый пределПредупреждениеЖёсткий предел
React-компонент400 строк600 строк800 строк
Пользовательский хук300 строк400 строк600 строк
Вспомогательные функции150 строк200 строк300 строк
Определения типов100 строк150 строк200 строк
Сервис/API300 строк400 строк600 строк

Последствия нарушений:

  • Превышение предупредительной линии → обязательно разбить файл в рамках текущей задачи, не откладывать
  • Превышение жёсткого предела → немедленно остановиться, сначала провести рефакторинг

Соглашения об именовании

Именование файлов

ТипПравилоПример
React-компонентPascalCase.tsxUserMessage.tsx
Хукиuse + PascalCase.tsuseChatActions.ts
Вспомогательные функцииcamelCase.tsmessageHelpers.ts
Определения типовcamelCase.ts или types.tschatTypes.ts
КонстантыUPPER_CASE.tsAPI_CONSTANTS.ts
СервисыPascalCase + Service.tsChatService.ts
Директорииkebab-casechat-messages/

Именование компонентов

// Хорошо: понятное, описательное
export function UserMessage() { }
export function EditTool() { }
export function ChatComposer() { }

// Плохо: слишком обобщённое
export function Message() { }
export function Tool() { }
export function Input() { }

Именование хуков

// Хорошо: use + описание функции
export function useChatActions() { }
export function useMessageEffects() { }

// Плохо: не соответствует соглашению об именовании React Hook
export function chatActions() { }
export function messageHook() { }

Стандарты структуры директорий

Директория компонентов

components/
├── ComponentName/
│ ├── index.ts # Единая точка экспорта
│ ├── ComponentName.tsx # Основной компонент
│ ├── types.ts # Определения типов
│ ├── utils.ts # Вспомогательные функции
│ ├── SubComponent.tsx # Дочерний компонент
│ └── __tests__/
│ └── ComponentName.test.tsx

Директория хуков

hooks/
├── domain/
│ ├── index.ts # Единая точка экспорта
│ ├── useDomainState.ts # Состояние
│ ├── useDomainActions.ts # Действия
│ └── useDomainEffects.ts # Побочные эффекты

Директория сервисов

services/
├── ServiceName/
│ ├── index.ts # Единая точка экспорта
│ ├── ServiceName.ts # Основной сервис
│ ├── types.ts # Определения типов
│ └── subdomain/ # Поддомен

Лучшие практики TypeScript

Импорты типов

// Использовать только type-импорты
import { type SomeType } from './types';
import type { AnotherType } from '@shared/contracts';

Избегайте any

// Плохо
function handle(data: any) { }

// Хорошо: использовать конкретные типы
function handle(data: Message) { }

// Хорошо: использовать обобщения
function handle<T extends BaseMessage>(data: T) { }

// Хорошо: использовать unknown + защита типа
function handle(data: unknown) {
if (isMessage(data)) { /* data: Message */ }
}

Barrel Export

// components/chat/messages/index.ts
export { MessageItem } from './MessageItem';
export { MessageList } from './MessageList';
export type { MessageItemProps } from './MessageItem';

Порядок организации кода

Структура React-компонента

// 1. Импорты
// 2. Определения типов
// 3. Константы
// 4. Вспомогательные функции
// 5. Основной компонент
// 5.1 Хуки
// 5.2 Производное состояние (useMemo)
// 5.3 Обработчики событий (useCallback)
// 5.4 Эффекты (useEffect)
// 5.5 Рендер (return)
// 6. Дочерние компоненты (если простые)

Принцип единственной ответственности

Каждый файл должен иметь только одну причину для изменения. Компонент следует разбить, если:

  1. Он превышает 300 строк кода
  2. Содержит 3 и более независимых логических блока
  3. Имеет части, пригодные для повторного использования
  4. Разные части изменяются с разной частотой
  5. Тестирование становится затруднительным

Стратегии разбиения:

СтратегияКогда применятьПример
По функцииUI-блоки независимыТулбар / список сообщений / поле ввода → отдельные компоненты
По потоку данныхСложная логика состоянияСостояние / Действия / Побочные эффекты → отдельные хуки
По доменуНесколько однотипных элементовEditTool / WriteTool / BashTool → отдельные файлы

Git-процесс

Соглашение о коммитах

Используйте формат Conventional Commits:

feat: описание новой функции
fix: описание исправления
refactor: описание рефакторинга
docs: обновление документации
style: изменения форматирования (без изменений логики)
test: изменения, связанные с тестами
chore: изменения инструментов сборки или вспомогательных инструментов

Контрольный список перед коммитом

  1. Запустить npm run lint — убедиться в отсутствии ошибок
  2. Исправить все проблемы уровня error
  3. По возможности исправить проблемы уровня warn
  4. Запустить npm run format — отформатировать код
  5. Новые файлы должны иметь 0 предупреждений
  6. При изменении существующих файлов — заодно исправить предупреждения в них