code_formatter_package 1.0.0 copy "code_formatter_package: ^1.0.0" to clipboard
code_formatter_package: ^1.0.0 copied to clipboard

A Flutter package for formatting and splitting Dart code into widgets.

example/example.dart

// ignore_for_file: avoid_print

import 'package:code_formatter_package/code_formatter_package.dart';
import 'package:flutter/material.dart';

/// Example code containing multiple widgets to be split
const String sampleCode = '''
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// A simple home screen widget
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        backgroundColor: Colors.blue,
      ),
      body: const Center(
        child: Text(
          'Welcome to Home Screen!',
          style: TextStyle(fontSize: 24),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: const Icon(Icons.add),
      ),
    );
  }
}

/// A profile screen with state management
class ProfileScreen extends StatefulWidget {
  final String userId;

  const ProfileScreen({super.key, required this.userId});

  @override
  State<ProfileScreen> createState() => _ProfileScreenState();
}

class _ProfileScreenState extends State<ProfileScreen> {
  bool _isLoading = true;
  String _userName = '';

  @override
  void initState() {
    super.initState();
    _loadUserData();
  }

  Future<void> _loadUserData() async {
    await Future.delayed(const Duration(seconds: 1));
    setState(() {
      _userName = 'John Doe';
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return const Scaffold(
        body: Center(child: CircularProgressIndicator()),
      );
    }

    return Scaffold(
      appBar: AppBar(title: Text('Profile: \$_userName')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const CircleAvatar(
              radius: 50,
              child: Icon(Icons.person, size: 50),
            ),
            const SizedBox(height: 16),
            Text(
              _userName,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            Text('User ID: \${widget.userId}'),
          ],
        ),
      ),
    );
  }
}

/// A settings screen widget
class SettingsScreen extends StatelessWidget {
  const SettingsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Settings')),
      body: ListView(
        children: const [
          ListTile(
            leading: Icon(Icons.notifications),
            title: Text('Notifications'),
            trailing: Icon(Icons.chevron_right),
          ),
          ListTile(
            leading: Icon(Icons.security),
            title: Text('Privacy'),
            trailing: Icon(Icons.chevron_right),
          ),
          ListTile(
            leading: Icon(Icons.help),
            title: Text('Help & Support'),
            trailing: Icon(Icons.chevron_right),
          ),
        ],
      ),
    );
  }
}
''';

void main() {
  runApp(const ExampleApp());
}

/// Example Flutter app demonstrating the code formatter package
class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Code Formatter Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const FormatterDemoScreen(),
    );
  }
}

/// Demo screen showing various ways to use the formatter
class FormatterDemoScreen extends StatefulWidget {
  const FormatterDemoScreen({super.key});

  @override
  State<FormatterDemoScreen> createState() => _FormatterDemoScreenState();
}

class _FormatterDemoScreenState extends State<FormatterDemoScreen> {
  String _status = 'Ready to format';
  List<ExtractedWidget> _extractedWidgets = [];
  bool _isProcessing = false;

  @override
  void initState() {
    super.initState();
    // Example: Initialize formatter when app starts
    _previewWidgets();
  }

  /// Preview widgets without saving to files
  void _previewWidgets() {
    final widgets = CodeFormatter.previewWidgets(sampleCode);
    setState(() {
      _extractedWidgets = widgets;
      _status = 'Found ${widgets.length} widgets (preview mode)';
    });
  }

  /// Format code and save to files
  Future<void> _formatAndSave() async {
    setState(() {
      _isProcessing = true;
      _status = 'Processing...';
    });

    // Example 1: Basic formatting with default config
    final result = CodeFormatter.formatCode(sampleCode);

    if (result.success) {
      setState(() {
        _extractedWidgets = result.widgets;
        _status = 'Successfully saved ${result.widgets.length} widgets!';
      });

      // Show where files were saved
      for (final widget in result.widgets) {
        print('Saved: ${widget.className} -> ${widget.savedPath}');
      }

      // Check for warnings
      if (result.warnings.isNotEmpty) {
        print('Warnings:');
        for (final warning in result.warnings) {
          print('  - $warning');
        }
      }
    } else {
      setState(() {
        _status = 'Error: ${result.errorMessage}';
      });

      // Handle specific error types
      switch (result.errorType) {
        case CodeFormatterErrorType.noWidgetsFound:
          print('No widgets found in the code');
          break;
        case CodeFormatterErrorType.parseError:
          print('Failed to parse the code');
          break;
        default:
          print('Error: ${result.errorMessage}');
      }
    }

    setState(() {
      _isProcessing = false;
    });
  }

  /// Format with custom configuration
  Future<void> _formatWithCustomConfig() async {
    setState(() {
      _isProcessing = true;
      _status = 'Processing with custom config...';
    });

    final result = CodeFormatter.formatCode(
      sampleCode,
      config: const FormatterConfig(
        outputDir: 'lib/custom_widgets',
        useClassNameAsFileName: true,
        includeFlutterImports: true,
        includeHeaderComment: true,
        overwriteExisting: true,
      ),
    );

    setState(() {
      _isProcessing = false;
      if (result.success) {
        _extractedWidgets = result.widgets;
        _status = 'Custom format: ${result.widgets.length} widgets saved!';
      } else {
        _status = 'Error: ${result.errorMessage}';
      }
    });
  }

  /// Format with custom file names
  Future<void> _formatWithCustomNames() async {
    setState(() {
      _isProcessing = true;
      _status = 'Processing with custom names...';
    });

    final result = CodeFormatter.formatCode(
      sampleCode,
      config: const FormatterConfig(
        outputDir: 'lib/named_widgets',
        customNames: ['main_home', 'user_profile', 'app_settings'],
      ),
    );

    setState(() {
      _isProcessing = false;
      if (result.success) {
        _extractedWidgets = result.widgets;
        _status = 'Named format: ${result.widgets.length} widgets saved!';
      } else {
        _status = 'Error: ${result.errorMessage}';
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Code Formatter Demo'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Status card
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Status',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    Text(_status),
                    if (_isProcessing)
                      const Padding(
                        padding: EdgeInsets.only(top: 8.0),
                        child: LinearProgressIndicator(),
                      ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // Action buttons
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                ElevatedButton.icon(
                  onPressed: _isProcessing ? null : _previewWidgets,
                  icon: const Icon(Icons.visibility),
                  label: const Text('Preview'),
                ),
                ElevatedButton.icon(
                  onPressed: _isProcessing ? null : _formatAndSave,
                  icon: const Icon(Icons.save),
                  label: const Text('Format & Save'),
                ),
                ElevatedButton.icon(
                  onPressed: _isProcessing ? null : _formatWithCustomConfig,
                  icon: const Icon(Icons.settings),
                  label: const Text('Custom Config'),
                ),
                ElevatedButton.icon(
                  onPressed: _isProcessing ? null : _formatWithCustomNames,
                  icon: const Icon(Icons.edit),
                  label: const Text('Custom Names'),
                ),
              ],
            ),

            const SizedBox(height: 16),

            // Extracted widgets list
            Text(
              'Extracted Widgets (${_extractedWidgets.length})',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 8),

            Expanded(
              child: ListView.builder(
                itemCount: _extractedWidgets.length,
                itemBuilder: (context, index) {
                  final widget = _extractedWidgets[index];
                  return Card(
                    child: ListTile(
                      leading: Icon(
                        widget.isStateful ? Icons.sync : Icons.widgets,
                        color: widget.isStateful ? Colors.orange : Colors.blue,
                      ),
                      title: Text(widget.className),
                      subtitle: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            widget.isStateful
                                ? 'StatefulWidget'
                                : 'StatelessWidget',
                          ),
                          if (widget.savedPath != null)
                            Text(
                              'Saved: ${widget.savedPath}',
                              style: Theme.of(context).textTheme.bodySmall,
                            ),
                          if (widget.associatedClasses.isNotEmpty)
                            Text(
                              'Associated: ${widget.associatedClasses.join(", ")}',
                              style: Theme.of(context).textTheme.bodySmall,
                            ),
                        ],
                      ),
                      isThreeLine: true,
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// =============================================================================
// Additional Examples (for documentation purposes)
// =============================================================================

/// Example: Format a file from disk
void exampleFormatFile() {
  final result = CodeFormatter.formatFile(
    'lib/screens/large_screen.dart',
    config: const FormatterConfig(
      outputDir: 'lib/widgets',
    ),
  );

  if (result.success) {
    print('Formatted ${result.widgets.length} widgets from file');
  }
}

/// Example: Async file formatting
Future<void> exampleAsyncFormat() async {
  final result = await CodeFormatter.formatFileAsync(
    'lib/screens/async_screen.dart',
  );

  if (result.success) {
    for (final widget in result.widgets) {
      print('${widget.className}: ${widget.savedPath}');
    }
  }
}

/// Example: Using initializeFormatter with callback
class InitializerExample extends StatefulWidget {
  const InitializerExample({super.key});

  @override
  State<InitializerExample> createState() => _InitializerExampleState();
}

class _InitializerExampleState extends State<InitializerExample> {
  String _message = 'Initializing...';

  @override
  void initState() {
    super.initState();

    // This runs after the first frame
    CodeFormatter.initializeFormatter(
      'lib/screens/home.dart',
      config: const FormatterConfig(
        outputDir: 'lib/generated',
      ),
      onComplete: (result) {
        setState(() {
          if (result.success) {
            _message = 'Formatted ${result.widgets.length} widgets!';
          } else {
            _message = 'Error: ${result.errorMessage}';
          }
        });
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: Text(_message)),
    );
  }
}

/// Example: Error handling
void exampleErrorHandling() {
  final result = CodeFormatter.formatFile('nonexistent_file.dart');

  if (!result.success) {
    switch (result.errorType) {
      case CodeFormatterErrorType.fileNotFound:
        print('The file does not exist');
        break;
      case CodeFormatterErrorType.parseError:
        print('Could not parse the Dart code');
        break;
      case CodeFormatterErrorType.noWidgetsFound:
        print('No StatelessWidget or StatefulWidget classes found');
        break;
      case CodeFormatterErrorType.directoryCreationError:
        print('Could not create output directory');
        break;
      case CodeFormatterErrorType.fileWriteError:
        print('Could not write to output file');
        break;
      case CodeFormatterErrorType.invalidInput:
        print('Invalid input provided');
        break;
      case CodeFormatterErrorType.unknown:
      case null:
        print('Unknown error: ${result.errorMessage}');
        break;
    }
  }

  // Always check warnings even on success
  for (final warning in result.warnings) {
    print('Warning: $warning');
  }
}
2
likes
150
points
134
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package for formatting and splitting Dart code into widgets.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

analyzer, flutter, path

More

Packages that depend on code_formatter_package