Code Formatter Package
A powerful Flutter package for splitting large Dart files containing multiple widgets into separate, well-organized files.
Features
- Widget Extraction: Automatically extracts
StatelessWidgetandStatefulWidgetclasses from your code - State Class Bundling: Automatically includes the corresponding
Stateclass with eachStatefulWidget - Import Preservation: Preserves all import statements from the original file
- Smart Naming: Uses widget class names for file naming (PascalCase to snake_case conversion)
- Flexible Configuration: Customize output directory, file names, and more
- Detailed Results: Returns comprehensive results with success/failure status and warnings
- Async Support: Provides both sync and async methods for file operations
- Error Handling: Proper error types and messages for debugging
Installation
Add this to your pubspec.yaml:
dependencies:
code_formatter_package: ^1.0.0
Then run:
flutter pub get
Usage
Basic Usage - Format Code from String
import 'package:code_formatter_package/code_formatter_package.dart';
void main() {
const code = '''
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(child: Text('Hello World')),
);
}
}
class ProfileScreen extends StatefulWidget {
@override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('Profile')),
);
}
}
''';
final result = CodeFormatter.formatCode(code);
if (result.success) {
print('Successfully extracted ${result.widgets.length} widgets:');
for (final widget in result.widgets) {
print(' - ${widget.className} -> ${widget.savedPath}');
}
} else {
print('Error: ${result.errorMessage}');
}
}
This will create:
lib/generated_widgets/home_screen.dartlib/generated_widgets/profile_screen.dart(includes_ProfileScreenStateclass)
Format Code from File
final result = CodeFormatter.formatFile('lib/screens/all_screens.dart');
if (result.success) {
print('Extracted ${result.widgets.length} widgets');
} else {
print('Error: ${result.errorMessage}');
}
Using Configuration Options
final result = CodeFormatter.formatCode(
myCode,
config: FormatterConfig(
outputDir: 'lib/widgets/generated',
useClassNameAsFileName: true,
includeFlutterImports: true,
includeHeaderComment: true,
overwriteExisting: false,
),
);
Custom File Names
final result = CodeFormatter.formatCode(
myCode,
config: FormatterConfig(
customNames: ['home_widget', 'profile_widget'],
outputDir: 'lib/custom_widgets',
),
);
Async File Formatting
final result = await CodeFormatter.formatFileAsync(
'lib/screens/large_file.dart',
config: FormatterConfig(outputDir: 'lib/widgets'),
);
Preview Widgets Without Saving
final widgets = CodeFormatter.previewWidgets(myCode);
for (final widget in widgets) {
print('Found widget: ${widget.className}');
print('Is StatefulWidget: ${widget.isStateful}');
if (widget.associatedClasses.isNotEmpty) {
print('Associated classes: ${widget.associatedClasses.join(", ")}');
}
}
Flutter App Integration
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
CodeFormatter.initializeFormatter(
'lib/screens/home.dart',
config: FormatterConfig(outputDir: 'lib/widgets'),
onComplete: (result) {
if (result.success) {
print('Formatted ${result.widgets.length} widgets');
} else {
print('Error: ${result.errorMessage}');
}
},
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(home: HomeScreen());
}
}
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
outputDir |
String |
'lib/generated_widgets' |
Output directory for generated files |
customNames |
List<String>? |
null |
Custom file names for generated widgets |
useClassNameAsFileName |
bool |
true |
Use widget class name as file name |
includeFlutterImports |
bool |
true |
Add Flutter imports if not present |
includeHeaderComment |
bool |
true |
Add header comment to generated files |
formatOutput |
bool |
true |
Format the output code |
overwriteExisting |
bool |
true |
Overwrite existing files |
API Reference
Classes
CodeFormatter
Main class with static methods for formatting code.
Methods:
formatCode(String code, {FormatterConfig config})- Format code from stringformatFile(String filePath, {FormatterConfig config})- Format code from fileformatFileAsync(String filePath, {FormatterConfig config})- Async file formattinginitializeFormatter(String filePath, {FormatterConfig config, Function? onComplete})- Flutter lifecycle integrationpreviewWidgets(String code)- Preview widgets without saving
FormatterResult
Result object returned by formatting methods.
Properties:
success- Whether the operation succeededwidgets- List of extracted widgetserrorMessage- Error message if failederrorType- Type of error if failedwarnings- List of warnings
ExtractedWidget
Represents an extracted widget.
Properties:
className- Name of the widget classsourceCode- Full source code including importssavedPath- Path where widget was savedisStateful- Whether it's a StatefulWidgetassociatedClasses- List of associated class names
FormatterConfig
Configuration options for the formatter.
CodeFormatterException
Exception thrown when formatting fails.
CodeFormatterErrorType
Enum of possible error types:
fileNotFoundfileWriteErrorparseErrornoWidgetsFounddirectoryCreationErrorinvalidInputunknown
Error Handling
final result = CodeFormatter.formatFile('lib/my_file.dart');
if (!result.success) {
switch (result.errorType) {
case CodeFormatterErrorType.fileNotFound:
print('File not found!');
break;
case CodeFormatterErrorType.noWidgetsFound:
print('No widgets in this file');
break;
case CodeFormatterErrorType.parseError:
print('Could not parse the code');
break;
default:
print('Error: ${result.errorMessage}');
}
}
// Check for warnings
if (result.warnings.isNotEmpty) {
print('Warnings:');
for (final warning in result.warnings) {
print(' - $warning');
}
}
Example Output
Input file with multiple widgets:
// lib/screens/home.dart
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget { ... }
class SettingsScreen extends StatefulWidget { ... }
class _SettingsScreenState extends State<SettingsScreen> { ... }
Output files:
lib/generated_widgets/
├── home_screen.dart // Contains HomeScreen
└── settings_screen.dart // Contains SettingsScreen + _SettingsScreenState
Each generated file includes:
- Header comment with widget name
- Required imports (Flutter + original imports)
- Widget class definition
- Associated State class (for StatefulWidget)
Requirements
- Dart SDK:
>=3.4.4 <4.0.0 - Flutter:
>=3.0.0
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Issues
If you find a bug or have a feature request, please open an issue on GitHub.
Libraries
- code_formatter_package
- A Flutter package for formatting and splitting Dart code into separate widget files.