chore: configure code quality tools

Add EditorConfig for consistent editor settings, Prettier for formatting (4-space indentation), ESLint with TypeScript rules, and linting documentation
This commit is contained in:
imfozilbek
2025-11-23 21:19:34 +05:00
parent 530cbdf14d
commit 5e9477cd21
4 changed files with 402 additions and 0 deletions

37
.editorconfig Normal file
View File

@@ -0,0 +1,37 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# TypeScript, JavaScript files
[*.{ts,tsx,js,jsx,mjs,cjs}]
indent_style = space
indent_size = 4
max_line_length = 160
# JSON, YAML files
[*.{json,yaml,yml}]
indent_style = space
indent_size = 4
# Markdown files
[*.md]
trim_trailing_whitespace = false
max_line_length = off
# Package.json
[package.json]
indent_style = space
indent_size = 4
# Shell scripts
[*.sh]
indent_style = space
indent_size = 4

15
.prettierrc Normal file
View File

@@ -0,0 +1,15 @@
{
"printWidth": 100,
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"endOfLine": "lf",
"embeddedLanguageFormatting": "auto"
}

216
LINTING.md Normal file
View File

@@ -0,0 +1,216 @@
# Linting & Code Style Guide
## Overview
This project uses **ESLint** + **Prettier** with strict TypeScript rules and **4-space indentation**.
## Quick Start
```bash
# Format all code
pnpm format
# Lint and auto-fix
pnpm lint
# Check only (no fix)
pnpm eslint "packages/**/*.ts"
```
## Configuration Files
- **`.prettierrc`** - Prettier code formatting (4 spaces, single quotes, etc.)
- **`eslint.config.mjs`** - ESLint rules (TypeScript strict mode + best practices)
- **`.editorconfig`** - Editor settings (consistent across IDEs)
## Key Rules
### TypeScript Strictness
| Rule | Level | Description |
|------|-------|-------------|
| `@typescript-eslint/no-explicit-any` | warn | Avoid `any` type - use proper typing |
| `@typescript-eslint/explicit-function-return-type` | warn | Functions must declare return types |
| `@typescript-eslint/no-floating-promises` | error | Always handle promises |
| `@typescript-eslint/no-unsafe-*` | warn | Strict type safety checks |
### Code Quality
| Rule | Level | Description |
|------|-------|-------------|
| `no-console` | warn | Use logger instead (except `console.warn/error`) |
| `prefer-const` | error | Use `const` for non-reassigned variables |
| `eqeqeq` | error | Always use `===` instead of `==` |
| `curly` | error | Always use curly braces for if/for/while |
| `complexity` | warn | Max cyclomatic complexity: 15 |
| `max-params` | warn | Max function parameters: 5 |
| `max-lines-per-function` | warn | Max 100 lines per function |
### Code Style
- **Indentation:** 4 spaces (not tabs)
- **Line Length:** 100 characters max
- **Quotes:** Single quotes `'string'`
- **Semicolons:** Always required `;`
- **Trailing Commas:** Always in multiline
- **Arrow Functions:** Always use parentheses `(x) => x`
## Handling Warnings
### `any` Type Usage
**Before:**
```typescript
function process(data: any) {
return data.value;
}
```
**After:**
```typescript
interface ProcessData {
value: string;
}
function process(data: ProcessData): string {
return data.value;
}
```
### Missing Return Types
**Before:**
```typescript
async function fetchData() {
return await api.get('/data');
}
```
**After:**
```typescript
async function fetchData(): Promise<DataResponse> {
return await api.get('/data');
}
```
### Floating Promises
**Before:**
```typescript
async function init() {
startServer(); // ❌ Promise not handled
}
```
**After:**
```typescript
async function init(): Promise<void> {
await startServer(); // ✅ Promise awaited
}
```
## Ignoring Rules (Use Sparingly)
```typescript
// Disable specific rule for next line
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const legacyData: any = getLegacyApi();
// Disable for entire file (add at top)
/* eslint-disable @typescript-eslint/no-explicit-any */
```
**Note:** Only use `eslint-disable` for legacy code or when type safety is genuinely impossible.
## Pre-commit Hooks (Optional)
To automatically format on commit, install Husky:
```bash
pnpm add -D husky lint-staged
npx husky init
# Add to .husky/pre-commit:
pnpm lint-staged
```
Create `lint-staged` config in `package.json`:
```json
{
"lint-staged": {
"*.{ts,tsx}": [
"prettier --write",
"eslint --fix"
]
}
}
```
## IDE Setup
### VS Code
Install extensions:
- **ESLint** (`dbaeumer.vscode-eslint`)
- **Prettier** (`esbenp.prettier-vscode`)
Add to `.vscode/settings.json`:
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": ["typescript", "javascript"]
}
```
### WebStorm / IntelliJ IDEA
1. **Settings → Languages & Frameworks → JavaScript → Prettier**
- Enable "On save"
- Set "Run for files": `{**/*,*}.{ts,js,tsx,jsx}`
2. **Settings → Languages & Frameworks → JavaScript → Code Quality Tools → ESLint**
- Enable "Automatic ESLint configuration"
- Enable "Run eslint --fix on save"
## Common Issues
### "Parsing error: ESLint was configured to run..."
**Solution:** Make sure `tsconfig.json` exists in the project root.
### "Rule 'indent' conflicts with Prettier"
**Solution:** Already handled - ESLint `indent` rule is disabled in favor of Prettier.
### Too many warnings after upgrade
**Solution:** Run auto-fix first, then address remaining issues:
```bash
pnpm lint
# Review warnings, fix manually
```
## Best Practices
1. **Run `pnpm format` before committing** - ensures consistent formatting
2. **Fix warnings incrementally** - don't disable rules without reason
3. **Add types instead of `any`** - improves code quality and IDE support
4. **Use ESLint ignore comments sparingly** - only for edge cases
## Resources
- [TypeScript ESLint Rules](https://typescript-eslint.io/rules/)
- [Prettier Options](https://prettier.io/docs/en/options.html)
- [ESLint Rules](https://eslint.org/docs/latest/rules/)
- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
---
**Last Updated:** 2025-01-19

134
eslint.config.mjs Normal file
View File

@@ -0,0 +1,134 @@
// @ts-check
import eslint from '@eslint/js';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tseslint from 'typescript-eslint';
export default tseslint.config(
{
ignores: [
'eslint.config.mjs',
'**/dist/**',
'**/node_modules/**',
'**/coverage/**',
'**/.puaros/**',
'**/build/**',
],
},
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
eslintPluginPrettierRecommended,
{
languageOptions: {
globals: {
...globals.node,
...globals.jest,
...globals.es2021,
},
sourceType: 'commonjs',
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
rules: {
// ========================================
// TypeScript Best Practices
// ========================================
'@typescript-eslint/no-explicit-any': 'warn', // Warn about 'any' usage
'@typescript-eslint/no-unsafe-assignment': 'warn',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-call': 'warn',
'@typescript-eslint/no-unsafe-return': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn',
'@typescript-eslint/explicit-function-return-type': [
'warn',
{
allowExpressions: true,
allowTypedFunctionExpressions: true,
allowHigherOrderFunctions: true,
},
],
'@typescript-eslint/explicit-module-boundary-types': 'warn',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
'@typescript-eslint/prefer-optional-chain': 'warn',
'@typescript-eslint/prefer-readonly': 'warn',
'@typescript-eslint/promise-function-async': 'warn',
'@typescript-eslint/require-await': 'warn',
'@typescript-eslint/no-unnecessary-condition': 'warn',
'@typescript-eslint/no-non-null-assertion': 'warn',
// ========================================
// Code Quality & Best Practices
// ========================================
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-debugger': 'error',
'no-alert': 'error',
'no-var': 'error',
'prefer-const': 'error',
'prefer-arrow-callback': 'warn',
'prefer-template': 'warn',
'no-nested-ternary': 'warn',
'no-unneeded-ternary': 'error',
'no-else-return': 'warn',
eqeqeq: ['error', 'always'],
curly: ['error', 'all'],
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-trailing-spaces': 'error',
'comma-dangle': ['error', 'always-multiline'],
// ========================================
// Code Style (handled by Prettier mostly)
// ========================================
indent: ['error', 4, { SwitchCase: 1 }],
'@typescript-eslint/indent': 'off', // Let Prettier handle this
quotes: ['error', 'single', { avoidEscape: true }],
semi: ['error', 'always'],
// ========================================
// Prettier Integration
// ========================================
'prettier/prettier': [
'error',
{
tabWidth: 4,
endOfLine: 'auto',
},
],
// ========================================
// Complexity & Maintainability
// ========================================
complexity: ['warn', 15],
'max-depth': ['warn', 4],
'max-lines-per-function': ['warn', { max: 100, skipBlankLines: true, skipComments: true }],
'max-params': ['warn', 5],
// ========================================
// Imports & Dependencies
// ========================================
'no-duplicate-imports': 'error',
'sort-imports': [
'warn',
{
ignoreCase: true,
ignoreDeclarationSort: true,
},
],
},
},
);