generateBoilerplate method
void
generateBoilerplate({})
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,
);
}
}