createFeature function

void createFeature(
  1. CreateOptions opts,
  2. ProjectContext ctx
)

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.');
  }
}