generateBoilerplate method

void generateBoilerplate({
  1. required String featureName,
  2. required String basePath,
  3. required String templateBasePath,
  4. required Context context,
  5. required bool overwrite,
})

Renders all Mustache templates (model, entity, repository, datasource, usecase, bloc/event/state, or riverpod notifier) into the feature directory.

Each template receives a simple map to keep the generator decoupled from the Mustache engine.

Implementation

void generateBoilerplate({
  required String featureName,
  required String basePath,
  required String templateBasePath,
  required Context context,
  required bool overwrite,
}) {
  // ── Shared helpers ────────────────────────────────────────────────────

  // Deduplicated list of response entities used for import generation.
  // In single-response mode this is just the one feature entity.
  final responseEntities = _buildResponseEntities(context);

  // Common enriched methods map (adds methodNameLowerCase + response fields).
  List<Map<String, dynamic>> enrichedMethods(List<ContextMethod> methods) {
    return methods
        .map(
          (e) => {
            ...e.toMap(),
            'methodNameLowerCase': e.methodName.camelCaseToSnakeCase(),
          },
        )
        .toList();
  }

  // Root context additions shared across templates.
  Map<String, dynamic> baseCtx() => {
    ...context.toMap(),
    'featureNameLower': featureName,
    'responseEntities': responseEntities,
  };

  // ── Injector ──────────────────────────────────────────────────────────
  renderTemplate(
    '$templateBasePath/injector.mustache',
    '${context.projectRoot}/lib/core/di/injector.dart',
    {'projectName': context.projectName},
    overwrite: overwrite,
  );

  // ── Model & Entity ────────────────────────────────────────────────────
  if (context.isMultiResponse) {
    // One entity file + one model file per named response.
    for (final entity in context.entities) {
      renderTemplate(
        '$templateBasePath/domain/entity.mustache',
        '$basePath/domain/entities/${entity.nameLower}_entity.dart',
        entity.toMap(),
        overwrite: overwrite,
      );

      renderTemplate(
        '$templateBasePath/data/model.mustache',
        '$basePath/data/models/${entity.nameLower}_model.dart',
        {
          ...entity.toMap(),
          'nameLowerCase': entity.nameLower,
          'featureNameLower': featureName,
          'projectName': context.projectName,
        },
        overwrite: overwrite,
      );
    }
  } else {
    // Single-response: original behaviour.
    renderTemplate(
      '$templateBasePath/data/model.mustache',
      '$basePath/data/models/${featureName}_model.dart',
      {
        ...context.toMap(),
        'featureNameLower': featureName,
      },
      overwrite: overwrite,
    );

    renderTemplate(
      '$templateBasePath/domain/entity.mustache',
      '$basePath/domain/entities/${featureName}_entity.dart',
      context.toMap(),
      overwrite: overwrite,
    );
  }

  // ── Repository (abstract) ─────────────────────────────────────────────
  renderTemplate(
    '$templateBasePath/domain/repository.mustache',
    '$basePath/domain/repositories/${featureName}_repository.dart',
    {
      ...baseCtx(),
      'methods': enrichedMethods(context.methods),
    },
    overwrite: overwrite,
  );

  // ── Repository Impl ───────────────────────────────────────────────────
  renderTemplate(
    '$templateBasePath/data/repository_impl.mustache',
    '$basePath/data/repositories/${featureName}_repository_impl.dart',
    {
      ...baseCtx(),
      'methods': enrichedMethods(context.methods),
    },
    overwrite: overwrite,
  );

  // ── Remote Datasource ─────────────────────────────────────────────────
  renderTemplate(
    '$templateBasePath/data/remote_datasource.mustache',
    '$basePath/data/datasources/${featureName}_remote_datasource.dart',
    {
      ...baseCtx(),
      'methods': enrichedMethods(context.methods),
    },
    overwrite: overwrite,
  );

  // ── Use Cases ─────────────────────────────────────────────────────────
  if (context.generateUseCase) {
    renderTemplate(
      '$templateBasePath/usecase.mustache',
      '${context.projectRoot}/lib/features/shared/usecase/usecase.dart',
      context.toMap(),
      overwrite: overwrite,
    );

    for (var method in context.methods) {
      renderTemplate(
        '$templateBasePath/domain/usecase.mustache',
        '$basePath/domain/usecases/${method.methodName.camelCaseToSnakeCase()}_usecase.dart',
        {
          'name': context.name,
          'isList': context.isList,
          'nameLowerCase': context.nameLowerCase,
          'nameCamelCase': context.nameCamelCase,
          'projectName': context.projectName,
          'isMultiResponse': context.isMultiResponse,
          ...method.toMap(),
        },
        overwrite: overwrite,
      );
    }
  }

  // ── Presentation — Bloc ───────────────────────────────────────────────
  if (context.config.bloc == true) {
    renderTemplate(
      '$templateBasePath/presentation/bloc/bloc.mustache',
      '$basePath/presentation/bloc/${featureName}_bloc.dart',
      {
        ...baseCtx(),
        'methods': enrichedMethods(context.methods),
      },
      overwrite: overwrite,
    );

    renderTemplate(
      '$templateBasePath/presentation/bloc/event.mustache',
      '$basePath/presentation/bloc/${featureName}_event.dart',
      {
        'name': context.name,
        'projectName': context.projectName,
        'methods': enrichedMethods(context.methods).map((e) => {
          ...e,
          'nameLowerCase': context.nameLowerCase,
        }).toList(),
      },
      overwrite: overwrite,
    );

    renderTemplate(
      '$templateBasePath/presentation/state.mustache',
      '$basePath/presentation/bloc/${featureName}_state.dart',
      {
        ...baseCtx(),
        'methods': enrichedMethods(context.methods),
      },
      overwrite: overwrite,
    );

    renderTemplate(
      '$templateBasePath/presentation/screen/screen_bloc.mustache',
      '$basePath/presentation/screen/${featureName}_screen.dart',
      context.toMap(),
      overwrite: overwrite,
    );
  }

  // ── Presentation — Riverpod ───────────────────────────────────────────
  if (context.config.riverpod == true) {
    renderTemplate(
      '$templateBasePath/presentation/state.mustache',
      '$basePath/presentation/riverpod/${featureName}_state.dart',
      {
        ...baseCtx(),
        'methods': enrichedMethods(context.methods),
      },
      overwrite: overwrite,
    );

    renderTemplate(
      '$templateBasePath/presentation/riverpod/notifier.mustache',
      '$basePath/presentation/riverpod/${featureName}_notifier.dart',
      {
        ...baseCtx(),
        'methods': enrichedMethods(context.methods),
      },
      overwrite: overwrite,
    );

    renderTemplate(
      '$templateBasePath/presentation/screen/screen_riverpod.mustache',
      '$basePath/presentation/screen/${featureName}_screen.dart',
      context.toMap(),
      overwrite: overwrite,
    );
  }
}