createFeature function
river_cli create feature:<name> --fields "..." (or --json)
The "amazing" generator: model + repository + AsyncNotifier controller + list view + registered route, all wired together and adapted to the installed modules.
Implementation
void createFeature(CreateOptions opts, ProjectContext ctx) {
final snake = Naming.snake(opts.name);
final featureDir = '${opts.path}/$snake';
final writer = FileWriter(force: opts.force, dryRun: opts.dryRun);
print('Creating feature: ${Naming.pascal(opts.name)} at $featureDir\n');
// Shared data layer (model may be inferred from JSON).
final inferred = _inferredModels(opts);
final modelContent = inferred != null
? modelsFileTemplate(inferred)
: modelTemplate(opts.name, opts.fields);
if (inferred != null) {
print(' inferred ${inferred.length} model(s) from JSON');
}
writer.write('lib/data/models/${snake}_model.dart', modelContent);
writer.write(
'lib/data/repositories/${snake}_repository.dart',
repositoryTemplate(opts.name, ctx),
);
// Feature layer.
writer.write(
'$featureDir/controllers/${snake}_controller.dart',
crudControllerTemplate(opts.name, ctx),
);
writer.write(
'$featureDir/bindings/${snake}_binding.dart',
crudBindingTemplate(opts.name),
);
writer.write(
'$featureDir/views/${snake}_view.dart',
crudViewTemplate(opts.name, opts.fields, ctx),
);
_maybeWriteModelTest(opts, ctx, writer,
fieldsForTest: opts.fields, blockedByJson: inferred != null);
// Route registration.
RouteRegistrar.register(
opts.name,
viewDir: featureDir,
ctx: ctx,
dryRun: opts.dryRun,
);
writer.printSummary();
if (!ctx.hasNetwork) {
print('\nTip: run "river_cli init --modules network" to wire the '
'repository to the Dio API client.');
}
}