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 into the feature directory.

Delegates per-layer presentation files to focused private helpers so each layer's templates are managed in one place, making it straightforward to add new layers without touching unrelated code.

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).
  final enriched = _enrichedMethods(context.methods);

  // Root context additions shared across templates.
  final 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': enriched},
    overwrite: overwrite,
  );

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

  // ── Remote Datasource ─────────────────────────────────────────────────
  renderTemplate(
    '$templateBasePath/data/remote_datasource.mustache',
    '$basePath/data/datasources/${featureName}_remote_datasource.dart',
    {...baseCtx, 'methods': enriched},
    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 layer ────────────────────────────────────────────────
  switch (context.config.layer) {
    case PresentationLayer.bloc:
      _generateBlocFiles(
        featureName: featureName,
        basePath: basePath,
        templateBasePath: templateBasePath,
        context: context,
        enriched: enriched,
        baseCtx: baseCtx,
        overwrite: overwrite,
      );
    case PresentationLayer.riverpod:
      _generateRiverpodFiles(
        featureName: featureName,
        basePath: basePath,
        templateBasePath: templateBasePath,
        context: context,
        enriched: enriched,
        baseCtx: baseCtx,
        overwrite: overwrite,
      );
    case PresentationLayer.getx:
      _generateGetXFiles(
        featureName: featureName,
        basePath: basePath,
        templateBasePath: templateBasePath,
        context: context,
        enriched: enriched,
        baseCtx: baseCtx,
        overwrite: overwrite,
      );
    case null:
      // Unreachable after validateSchema; here for exhaustive switch safety.
      break;
  }
}