1# Flutter Code Quality & Formatting Guide 2 3This guide covers linting, formatting, and automated code quality checks for the Coves mobile app. 4 5--- 6 7## Tools Overview 8 9### 1. **flutter analyze** (Static Analysis / Linting) 10Checks code for errors, warnings, and style issues based on `analysis_options.yaml`. 11 12### 2. **dart format** (Code Formatting) 13Auto-formats code to Dart style guide (spacing, indentation, line length). 14 15### 3. **analysis_options.yaml** (Configuration) 16Defines which lint rules are enforced. 17 18--- 19 20## Quick Start 21 22### Run All Quality Checks 23```bash 24# Format code 25dart format . 26 27# Analyze code 28flutter analyze 29 30# Run tests 31flutter test 32``` 33 34--- 35 36## 1. Code Formatting with `dart format` 37 38### Basic Usage 39```bash 40# Check if code needs formatting (exits with 1 if changes needed) 41dart format --output=none --set-exit-if-changed . 42 43# Format all Dart files 44dart format . 45 46# Format specific directory 47dart format lib/ 48 49# Format specific file 50dart format lib/services/coves_api_service.dart 51 52# Dry run (show what would change without modifying files) 53dart format --output=show . 54``` 55 56### Dart Formatting Rules 57- **80-character line limit** (configurable in analysis_options.yaml) 58- **2-space indentation** 59- **Trailing commas** for better git diffs 60- **Consistent spacing** around operators 61 62### Example: Trailing Commas 63```dart 64// ❌ Without trailing comma (bad for diffs) 65Widget build(BuildContext context) { 66 return Container( 67 child: Text('Hello') 68 ); 69} 70 71// ✅ With trailing comma (better for diffs) 72Widget build(BuildContext context) { 73 return Container( 74 child: Text('Hello'), // ← Trailing comma 75 ); 76} 77``` 78 79--- 80 81## 2. Static Analysis with `flutter analyze` 82 83### Basic Usage 84```bash 85# Analyze entire project 86flutter analyze 87 88# Analyze specific directory 89flutter analyze lib/ 90 91# Analyze specific file 92flutter analyze lib/services/coves_api_service.dart 93 94# Analyze with verbose output 95flutter analyze --verbose 96``` 97 98### Understanding Output 99``` 100 error • Business logic in widgets • lib/screens/feed.dart:42 • custom_rule 101warning • Missing documentation • lib/services/api.dart:10 • public_member_api_docs 102 info • Line too long • lib/models/post.dart:55 • lines_longer_than_80_chars 103``` 104 105- **error**: Must fix (breaks build in CI) 106- **warning**: Should fix (may break CI depending on config) 107- **info**: Optional suggestions (won't break build) 108 109--- 110 111## 3. Upgrading to Stricter Lint Rules 112 113### Option A: Use Recommended Rules (Recommended) 114Replace your current `analysis_options.yaml` with the stricter version: 115 116```bash 117# Backup current config 118cp analysis_options.yaml analysis_options.yaml.bak 119 120# Use recommended config 121cp analysis_options_recommended.yaml analysis_options.yaml 122 123# Test it 124flutter analyze 125``` 126 127### Option B: Use Very Good Analysis (Most Strict) 128For maximum code quality, use Very Good Ventures' lint rules: 129 130```yaml 131# pubspec.yaml 132dev_dependencies: 133 very_good_analysis: ^6.0.0 134``` 135 136```yaml 137# analysis_options.yaml 138include: package:very_good_analysis/analysis_options.yaml 139``` 140 141### Option C: Customize Incrementally 142Start with your current rules and add these high-value rules: 143 144```yaml 145# analysis_options.yaml 146include: package:flutter_lints/flutter.yaml 147 148linter: 149 rules: 150 # High-value additions 151 - prefer_const_constructors 152 - prefer_const_literals_to_create_immutables 153 - prefer_final_locals 154 - avoid_print 155 - require_trailing_commas 156 - prefer_single_quotes 157 - lines_longer_than_80_chars 158 - unawaited_futures 159``` 160 161--- 162 163## 4. IDE Integration 164 165### VS Code 166Add to `.vscode/settings.json`: 167 168```json 169{ 170 "dart.lineLength": 80, 171 "editor.formatOnSave": true, 172 "editor.formatOnType": false, 173 "editor.rulers": [80], 174 "dart.showLintNames": true, 175 "dart.previewFlutterUiGuides": true, 176 "dart.previewFlutterUiGuidesCustomTracking": true, 177 "[dart]": { 178 "editor.formatOnSave": true, 179 "editor.selectionHighlight": false, 180 "editor.suggest.snippetsPreventQuickSuggestions": false, 181 "editor.suggestSelection": "first", 182 "editor.tabCompletion": "onlySnippets", 183 "editor.wordBasedSuggestions": "off" 184 } 185} 186``` 187 188### Android Studio / IntelliJ 1891. **Settings → Editor → Code Style → Dart** 190 - Set line length to 80 191 - Enable "Format on save" 1922. **Settings → Editor → Inspections → Dart** 193 - Enable all inspections 194 195--- 196 197## 5. Pre-Commit Hooks (Recommended) 198 199Automate quality checks before every commit using `lefthook`. 200 201### Setup 202```bash 203# Install lefthook 204brew install lefthook # macOS 205# or 206curl -1sLf 'https://dl.cloudsmith.io/public/evilmartians/lefthook/setup.deb.sh' | sudo -E bash 207sudo apt install lefthook # Linux 208 209# Initialize 210lefthook install 211``` 212 213### Configuration 214Create `lefthook.yml` in project root: 215 216```yaml 217# lefthook.yml 218pre-commit: 219 parallel: true 220 commands: 221 # Format Dart code 222 format: 223 glob: "*.dart" 224 run: dart format {staged_files} && git add {staged_files} 225 226 # Analyze Dart code 227 analyze: 228 glob: "*.dart" 229 run: flutter analyze {staged_files} 230 231 # Run quick tests (optional) 232 # test: 233 # glob: "*.dart" 234 # run: flutter test 235 236pre-push: 237 commands: 238 # Full test suite before push 239 test: 240 run: flutter test 241 242 # Full analyze before push 243 analyze: 244 run: flutter analyze 245``` 246 247### Alternative: Simple Git Hook 248Create `.git/hooks/pre-commit`: 249 250```bash 251#!/bin/bash 252 253echo "Running dart format..." 254dart format . 255 256echo "Running flutter analyze..." 257flutter analyze 258 259if [ $? -ne 0 ]; then 260 echo "❌ Analyze failed. Fix issues before committing." 261 exit 1 262fi 263 264echo "✅ Pre-commit checks passed!" 265``` 266 267Make it executable: 268```bash 269chmod +x .git/hooks/pre-commit 270``` 271 272--- 273 274## 6. CI/CD Integration 275 276### GitHub Actions 277Create `.github/workflows/code_quality.yml`: 278 279```yaml 280name: Code Quality 281 282on: 283 pull_request: 284 branches: [main, develop] 285 push: 286 branches: [main, develop] 287 288jobs: 289 analyze: 290 runs-on: ubuntu-latest 291 steps: 292 - uses: actions/checkout@v3 293 294 - uses: subosito/flutter-action@v2 295 with: 296 flutter-version: '3.24.0' 297 channel: 'stable' 298 299 - name: Install dependencies 300 run: flutter pub get 301 302 - name: Verify formatting 303 run: dart format --output=none --set-exit-if-changed . 304 305 - name: Analyze code 306 run: flutter analyze 307 308 - name: Run tests 309 run: flutter test 310``` 311 312### GitLab CI 313```yaml 314# .gitlab-ci.yml 315stages: 316 - quality 317 - test 318 319format: 320 stage: quality 321 image: cirrusci/flutter:stable 322 script: 323 - flutter pub get 324 - dart format --output=none --set-exit-if-changed . 325 326analyze: 327 stage: quality 328 image: cirrusci/flutter:stable 329 script: 330 - flutter pub get 331 - flutter analyze 332 333test: 334 stage: test 335 image: cirrusci/flutter:stable 336 script: 337 - flutter pub get 338 - flutter test 339``` 340 341--- 342 343## 7. Common Issues & Solutions 344 345### Issue: "lines_longer_than_80_chars" 346**Solution:** Break long lines with trailing commas 347```dart 348// Before 349final user = User(name: 'Alice', email: 'alice@example.com', age: 30); 350 351// After 352final user = User( 353 name: 'Alice', 354 email: 'alice@example.com', 355 age: 30, 356); 357``` 358 359### Issue: "prefer_const_constructors" 360**Solution:** Add const where possible 361```dart 362// Before 363return Container(child: Text('Hello')); 364 365// After 366return const Container(child: Text('Hello')); 367``` 368 369### Issue: "avoid_print" 370**Solution:** Use debugPrint with kDebugMode 371```dart 372// Before 373print('Error: $error'); 374 375// After 376if (kDebugMode) { 377 debugPrint('Error: $error'); 378} 379``` 380 381### Issue: "unawaited_futures" 382**Solution:** Either await or use unawaited() 383```dart 384// Before 385someAsyncFunction(); // Warning 386 387// After - Option 1: Await 388await someAsyncFunction(); 389 390// After - Option 2: Explicitly ignore 391import 'package:flutter/foundation.dart'; 392unawaited(someAsyncFunction()); 393``` 394 395--- 396 397## 8. Project-Specific Rules 398 399### Current Configuration 400We use `flutter_lints: ^5.0.0` with default rules. 401 402### Recommended Upgrade Path 4031. **Week 1:** Add format-on-save to IDEs 4042. **Week 2:** Add pre-commit formatting hook 4053. **Week 3:** Enable stricter analysis_options.yaml 4064. **Week 4:** Add CI/CD checks 4075. **Week 5:** Fix all existing violations 4086. **Week 6:** Enforce in CI (fail builds on violations) 409 410### Custom Rules for Coves 411Add these to `analysis_options.yaml` for Coves-specific quality: 412 413```yaml 414analyzer: 415 errors: 416 # Treat these as errors (not warnings) 417 missing_required_param: error 418 missing_return: error 419 420 exclude: 421 - '**/*.g.dart' 422 - '**/*.freezed.dart' 423 - 'packages/atproto_oauth_flutter/**' 424 425linter: 426 rules: 427 # Architecture enforcement 428 - avoid_print 429 - prefer_const_constructors 430 - prefer_final_locals 431 432 # Code quality 433 - require_trailing_commas 434 - lines_longer_than_80_chars 435 436 # Safety 437 - unawaited_futures 438 - close_sinks 439 - cancel_subscriptions 440``` 441 442--- 443 444## 9. Quick Reference 445 446### Daily Workflow 447```bash 448# Before committing 449dart format . 450flutter analyze 451flutter test 452 453# Or use pre-commit hook (automated) 454``` 455 456### Before PR 457```bash 458# Full quality check 459dart format --output=none --set-exit-if-changed . 460flutter analyze 461flutter test --coverage 462``` 463 464### Fix Formatting Issues 465```bash 466# Auto-fix all formatting 467dart format . 468 469# Fix specific file 470dart format lib/screens/home/feed_screen.dart 471``` 472 473### Ignore Specific Warnings 474```dart 475// Ignore for one line 476// ignore: avoid_print 477print('Debug message'); 478 479// Ignore for entire file 480// ignore_for_file: avoid_print 481 482// Ignore for block 483// ignore: lines_longer_than_80_chars 484final veryLongVariableName = 'This is a very long string that exceeds 80 characters'; 485``` 486 487--- 488 489## 10. Resources 490 491### Official Documentation 492- [Dart Linter Rules](https://dart.dev/lints) 493- [Flutter Lints Package](https://pub.dev/packages/flutter_lints) 494- [Effective Dart Style Guide](https://dart.dev/guides/language/effective-dart/style) 495 496### Community Resources 497- [Very Good Analysis](https://pub.dev/packages/very_good_analysis) 498- [Lint Package](https://pub.dev/packages/lint) 499- [Flutter Analyze Best Practices](https://docs.flutter.dev/testing/best-practices) 500 501--- 502 503## Next Steps 504 5051. ✅ Review `analysis_options_recommended.yaml` 5062. ⬜ Decide on strictness level (current / recommended / very_good) 5073. ⬜ Set up IDE format-on-save 5084. ⬜ Create pre-commit hooks 5095. ⬜ Add CI/CD quality checks 5106. ⬜ Schedule time to fix existing violations 5117. ⬜ Enforce in team workflow