createFeature function
Creates a new feature folder structure and optional state management boilerplate.
featureName - the feature folder name (e.g. "auth").
stateArg - optional: one of 'bloc','cubit','riverpod','provider','getx','none'.
Implementation
Future<void> createFeature(String featureName, {String? stateArg}) async {
final green = AnsiPen()..green();
final red = AnsiPen()..red();
final projectRoot = _findProjectRoot();
if (projectRoot == null) {
print(red('ā Could not find pubspec.yaml ā please run this inside a Flutter project.'));
exit(1);
}
// Start spinner
stdout.write('š Creating feature "$featureName"... ');
final spinner = ['|', '/', '-', '\\'];
var i = 0;
final timer = Timer.periodic(const Duration(milliseconds: 120), (_) {
stdout.write('\rš Creating feature "$featureName"... ${spinner[i++ % spinner.length]}');
});
try {
// Determine state management (use provided arg if valid, otherwise load/save or ask)
final stateManagement = _determineStateManagement(projectRoot, stateArg);
final base = p.join(projectRoot.path, 'lib', 'features', featureName);
final dirs = [
'data/models',
'data/datasources',
'domain/entities',
'domain/repositories',
'domain/usecases',
'presentation/screens',
'presentation/widgets',
];
// Add state-management specific folders
switch (stateManagement) {
case 'bloc':
case 'cubit':
dirs.add('presentation/bloc');
break;
case 'riverpod':
case 'provider':
dirs.add('presentation/providers');
break;
case 'getx':
dirs.add('presentation/controllers');
break;
case 'none':
default:
break;
}
// Create directories
for (var dir in dirs) {
createDir(p.join(base, dir));
}
// Create common files
createFile(p.join(base, 'data/models/${featureName}_model.dart'), '''
class ${_pascal(featureName)}Model {
// TODO: Define model fields
}
''');
createFile(p.join(base, 'domain/entities/${featureName}_entity.dart'), '''
class ${_pascal(featureName)}Entity {
// TODO: Define entity fields
}
''');
createFile(
p.join(base, 'domain/repositories/${featureName}_repository.dart'),
'''
abstract class ${_pascal(featureName)}Repository {
// TODO: Define abstract methods
}
''',
);
createFile(
p.join(base, 'presentation/screens/${featureName}_screen.dart'),
'''
import 'package:flutter/material.dart';
class ${_pascal(featureName)}Screen extends StatelessWidget {
const ${_pascal(featureName)}Screen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('${_pascal(featureName)} Screen')),
body: const Center(child: Text('Welcome to ${_pascal(featureName)} feature!')),
);
}
}
''',
);
// Generate state management boilerplate (if any)
_generateStateManagement(stateManagement, featureName, base);
// Success
stdout.write('\r'); // clear spinner line
print(green('ā
Feature "$featureName" with "$stateManagement" state management generated successfully!\n'));
} finally {
// Always cancel the spinner
if (timer.isActive) timer.cancel();
}
}