mirror of
https://github.com/samiyev/puaros.git
synced 2025-12-27 23:06:54 +05:00
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:
37
.editorconfig
Normal file
37
.editorconfig
Normal 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
15
.prettierrc
Normal 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
216
LINTING.md
Normal 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
134
eslint.config.mjs
Normal 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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user