flutter_prunekit 1.1.0
flutter_prunekit: ^1.1.0 copied to clipboard
Blazing-fast static analyzer for detecting unused classes, enums, mixins & extensions in Dart/Flutter. 100% precision, zero false positives.
[Flutter PruneKit]
π― Find and eliminate dead code in your Dart & Flutter projects
Blazing-fast β’ 100% Accurate β’ Zero Config
π Why flutter_prunekit? #
Dead code bloats your app, confuses developers, and slows down builds. flutter_prunekit uses advanced static analysis to find unused classes, enums, mixins, and extensionsβso you can ship faster, cleaner code.
The Problem #
// Somewhere in your codebase...
class OldUserWidget extends StatelessWidget { ... } // β Unused for 6 months
class DeprecatedHelper { ... } // β Nobody uses this
enum LegacyStatus { active, inactive } // β Dead code
The Solution #
$ dart run flutter_prunekit
βββ Flutter Dead Code Analysis βββ
β Found 3 unused declaration(s):
Classes: 2
lib/models/old_user.dart:12
OldUser
lib/models/deprecated.dart:5
DeprecatedHelper
Enums: 1
lib/utils/deprecated_helper.dart:8
LegacyStatus
β¨ Remove these to save ~500 lines of code!
β¨ Key Benefits #
| Benefit | Impact |
|---|---|
| π― 100% Precision | Zero false positives - every result is real dead code |
| β‘ Lightning Fast | Analyze 10k LOC in 3-4 seconds |
| π§Ή Clean Codebase | Remove technical debt systematically |
| π¦ Smaller Apps | Reduce bundle size by eliminating unused code |
| π§ Zero Config | Works out-of-the-box, customizable when needed |
| π Cross-Platform | macOS, Linux, Windows support |
| π Smart Analysis | Understands inheritance, generics, extensions, part files |
| π‘οΈ Battle-Tested | 119 passing tests, production-proven |
β¨ Key Features #
What We Detect (v1.0.0) #
- β Classes - Regular and abstract classes
- β Enums - All enum declarations
- β Mixins - Mixin declarations
- β
Extensions - Named and unnamed extensions with full semantic analysis
- Extension methods, getters, operators
- Cross-file extension usage tracking
- Generic type-parameterized extensions
Smart Analysis #
- π― 100% Accurate - Perfect precision and recall in production use
- β‘ Lightning Fast - 3-4s for 10k LOC projects
- π§ Semantic Resolution - Understands inheritance, generics, type checks
- π¦ Part File Support - Full analysis across part boundaries
- π§ Generated Code Aware - Auto-excludes
*.g.dart,*.freezed.dart,*.realm.dart - π¨ Flexible Ignore System - Annotations, patterns, or CLI flags
- π Cross-Platform - macOS, Linux, Windows tested
π Coming Soon (Roadmap) #
We're actively working on detecting unused:
- π Top-level functions - Unused global functions
- π Methods - Unused class methods (instance & static)
- π Fields & Properties - Unused class fields and getters/setters
- π Variables - Unused top-level and local variables
- π Type aliases - Unused typedef declarations
- π Constructor parameters - Unused named parameters
Want a feature? Open an issue!
π¦ Installation #
Option 1: Add to Your Project (Recommended) #
dart pub add --dev flutter_prunekit
Or manually add to pubspec.yaml:
dev_dependencies:
flutter_prunekit: ^1.1.0
Then run:
dart pub get
Option 2: Global Installation #
dart pub global activate flutter_prunekit
π Quick Start #
Basic Usage #
# Analyze your project (scans lib/ by default)
dart run flutter_prunekit
# Or if globally installed
flutter_prunekit
That's it! The tool will scan your code and show you any unused classes, enums, mixins, or extensions.
Example Output #
βββ Flutter Dead Code Analysis βββ
β Found 3 unused declaration(s):
Classes: 2
lib/models/old_user.dart:12
OldUser
lib/widgets/legacy_button.dart:8
LegacyButton
Enums: 1
lib/utils/deprecated_helper.dart:5
DeprecatedStatus
βββ Summary βββ
Files analyzed: 156
Total declarations: 89
Unused: 3
Usage rate: 96.6%
Analysis time: 2.1s
Programmatic Usage #
Prefer to drive the analyzer from Dart code? Check out example/basic_usage.dart
for a minimal script that wires together the public APIs to scan any project
directory. Running it without arguments analyzes the bundled sample project:
dart run example/basic_usage.dart
This points the analyzer at example/sample_project, which deliberately contains
unused classes, mixins, enums, and extensions so you can see the tool in action.
π Usage Guide #
Common Scenarios #
# Scan specific directories
dart run flutter_prunekit --path lib --path packages/core/lib
# Exclude legacy code from analysis
dart run flutter_prunekit --exclude 'lib/legacy/**'
# Include test files in analysis
dart run flutter_prunekit --include-tests
# Verbose mode - see detailed progress
dart run flutter_prunekit --verbose
# Quiet mode - only show results
dart run flutter_prunekit --quiet
# Scan generated code (use carefully!)
dart run flutter_prunekit --include-generated
ποΈ CLI Options Reference #
| Option | Description | Default |
|---|---|---|
-p, --path <path> |
Path(s) to analyze (can specify multiple times) | lib/ |
-e, --exclude <pattern> |
Glob pattern(s) to exclude from analysis | - |
--include-tests |
Analyze test files (test/**) |
false |
--include-generated |
Analyze generated files (*.g.dart, *.freezed.dart, etc.) |
false |
--ignore-analysis-options |
Don't respect analysis_options.yaml excludes |
false |
-q, --quiet |
Only show final report (suppress progress) | false |
-v, --verbose |
Show detailed analysis progress | false |
-h, --help |
Display help information | - |
--version |
Show version number | - |
βοΈ Configuration #
Method 1: Config File (Recommended) #
Create flutter_prunekit.yaml in your project root:
# Exclude entire directories or specific files
exclude:
- 'lib/legacy/**' # All files in legacy folder
- 'lib/generated/**' # Generated code folder
- '**/old_*.dart' # Files starting with 'old_'
- 'lib/deprecated.dart' # Specific file
# Custom annotations to treat as "keep" markers
ignore_annotations:
- 'deprecated' # Classes with @deprecated won't be flagged
- 'experimental' # Your custom @experimental annotation
Method 2: Use Existing analysis_options.yaml #
The tool automatically respects your analyzer excludes:
analyzer:
exclude:
- 'lib/generated/**'
- '**/*.g.dart'
- '**/*.freezed.dart'
No additional configuration needed!
π― Ignoring False Positives #
Sometimes you need to keep code that appears unused (reflection, dynamic loading, etc.). Here's how:
Ignore Priority Order #
When multiple ignore methods conflict:
@keepUnusedannotation (highest)flutter_prunekit.yamlpatterns--excludeCLI flag (lowest)
Option 1: Annotate Specific Classes β Recommended #
Perfect for individual classes that should never be removed:
@keepUnused // β Add this annotation
class LegacyWidget extends StatelessWidget {
// Won't be flagged as unused
}
@keepUnused
mixin ReflectionMixin {
// Used via reflection - keep it!
}
@keepUnused
enum PlatformStatus { active, inactive }
@keepUnused
extension StringHelpers on String {
// Extension used in other packages
}
Option 2: Pattern-Based Exclusion #
Use config file for excluding multiple files:
# flutter_prunekit.yaml
exclude:
- 'lib/legacy/**' # Entire folder
- '**/experimental_*.dart' # Name pattern
- 'lib/platform_specific.dart' # Single file
Option 3: Runtime Exclusion (Temporary) #
Use CLI flags for one-off analyses:
# Test excluding certain code
dart run flutter_prunekit --exclude 'lib/legacy/**' --exclude '**/old_*.dart'
π Exit Codes (Automation-Friendly) #
Perfect for integrating into your build pipeline:
| Exit Code | Meaning | Use Case |
|---|---|---|
| 0 | β No unused code found | Pass - codebase is clean |
| 1 | β οΈ Unused code detected | Warning - review before deployment |
| 2 | β Analysis errors/warnings | Fail - syntax errors or config issues |
Integration Examples #
# Fail build if unused code is found
dart run flutter_prunekit || exit 1
# Warning only (don't fail build)
dart run flutter_prunekit || echo "β οΈ Unused code detected"
# Save results to file
dart run flutter_prunekit > dead_code_report.txt
π Performance & Accuracy #
Battle-Tested Quality #
| Metric | Industry Standard | flutter_prunekit | Validation |
|---|---|---|---|
| Precision | β₯99% | 100% β | 1000-class test fixture |
| Recall | β₯80% | 100% β | 100-class recall test |
| False Positives | β€1% | 0% β | Production verified |
| False Negatives | β€20% | 0% β | Comprehensive test suite |
π― 119 passing tests across 18 test suites covering edge cases, part files, extensions, and real-world scenarios.
β‘ Lightning-Fast Analysis #
| Project Size | Lines of Code | Analysis Time | Memory Usage |
|---|---|---|---|
| π’ Small | <10,000 | ~3-4 seconds | <100 MB |
| π‘ Medium | 10k-50k | ~15-20 seconds | <200 MB |
| π΄ Large | 50k-100k | ~35-45 seconds | <500 MB |
Why so fast?
- Parallel file processing
- Optimized AST traversal
- Smart caching strategies
- No disk I/O overhead
π» System Requirements #
| Component | Requirement | Notes |
|---|---|---|
| Dart SDK | β₯3.0.0 <4.0.0 | Works with latest stable Dart |
| Platform | macOS, Linux, Windows | Full cross-platform support |
| RAM | 4GB minimum | 8GB recommended for large projects |
| Disk Space | ~5MB | No cache files created |
Supported IDEs:
- VS Code with Dart extension
- Android Studio / IntelliJ IDEA
- Any editor with Dart SDK
π What Gets Detected #
β Fully Supported (100% Accuracy) #
Basic Usage:
- β
Direct instantiation -
MyClass(),const MyClass() - β
Type annotations -
MyClass variable,List<MyClass> - β
Static access -
MyClass.staticMethod(),MyClass.constant - β
Factory constructors -
MyClass.factoryConstructor() - β
Type checks -
obj is MyClass,obj as MyClass
Advanced Features:
- β
Inheritance -
extends,implements,with - β
Generics -
Repository<Product>, nested generics - β
Annotations -
@MyAnnotation, custom annotations - β Part Files - Full cross-part reference tracking
- β Extensions - Named/unnamed, methods, getters, operators
- β
Generic Extensions -
extension ListExtension<T> on List<T> - β Cross-File Extensions - Import/export tracking
Special Cases:
- β
Realm Models -
$MyModelwith@RealmModel()annotation - β Freezed Classes - Generated code in part files
- β
Generated Code - Optional
--include-generatedsupport
β οΈ Known Limitations (Edge Cases) #
These are rare but worth knowing:
1. Dynamic Type Usage
dynamic obj = getObject();
obj.method(); // β οΈ Cannot statically determine class type
Solution: Avoid dynamic where possible, or use @keepUnused
2. Reflection & Mirrors
Type type = reflectClass(MyClass); // β οΈ Runtime-only reference
Solution: Add @keepUnused to reflected classes
3. Conditional Imports (Platform-Specific Code)
import 'stub.dart'
if (dart.library.io) 'io_impl.dart'
if (dart.library.html) 'web_impl.dart';
Solution: Annotate platform-specific classes with @keepUnused
4. Unnamed Extensions (Analyzer API Limitation)
// If ANY unnamed extension is used, ALL get marked as used
extension on String { ... } // Shares identifier with below
extension on int { ... } // Shares identifier with above
Solution: Use named extensions for better tracking:
extension StringHelpers on String { ... }
extension IntHelpers on int { ... }
ποΈ Code Generation Support #
β Fully Supported #
- Freezed -
*.freezed.dartpart files fully analyzed - Realm -
*.realm.dartwith$Model/_Modelpattern - json_serializable -
*.g.dartfiles - built_value - Generated builders and serializers
How It Works #
By default, generated files are excluded (recommended). Use --include-generated to analyze them:
# Include generated code in analysis
dart run flutter_prunekit --include-generated
β οΈ Note: Generated classes may appear unused if only referenced in other generated code. This is usually safe to ignore.
Best Practice: Run analysis both with and without --include-generated to understand your codebase.
π‘ Best Practices #
Recommended Workflow #
-
First Run - Baseline analysis
dart run flutter_prunekit -
Review Results - Check for false positives
-
Add Annotations - Mark intentionally unused code
@keepUnused // Loaded via reflection class PluginRegistry { } -
Configure Excludes - Set up
flutter_prunekit.yaml -
Integrate - Add to your build/test scripts
Tips for Large Codebases #
- Start with
--exclude 'lib/legacy/**'to focus on active code - Use
--verboseto understand what's being analyzed - Run incrementally on changed modules
- Schedule periodic full scans (e.g., monthly)
When to Use @keepUnused #
- β Classes loaded via reflection
- β Platform-specific implementations
- β Public API classes (even if unused internally)
- β Classes used by external packages
- β Migration/deprecation code
- β Test fixtures/mocks (if excluding tests)
π€ Contributing #
We welcome contributions! Whether it's:
- π Bug reports
- π‘ Feature requests
- π Documentation improvements
- π§ Code contributions
Please see CONTRIBUTING.md for guidelines.
Development Setup #
# Clone the repository
git clone https://github.com/furkanvatandas/flutter_prunekit.git
cd flutter_prunekit
# Install dependencies
dart pub get
# Run the tool locally
dart run bin/flutter_prunekit.dart --path lib
π License #
MIT License - see LICENSE file for details.
π¬ Support & Community #
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
β Show Your Support #
If flutter_prunekit helped clean up your codebase, consider:
- β Starring the repo
- π¦ Sharing on social media
- π Writing a blog post about it