codemod_recipe
Reusable primitives for deterministic, recipe-based Dart codemods and file scaffolds.
This package intentionally contains no project-specific transforms, paths, or naming conventions. Projects build their own integration layer on top of the generic recipe, runner, template, operation, patch, and Dart analyzer editor APIs.
Installation
Add codemod_recipe to your pubspec.yaml:
dependencies:
codemod_recipe: ^0.1.0
Or install via command line:
dart pub add codemod_recipe
Core Concepts
CLI args -> CodemodContext -> CodemodRecipe -> CodemodOperation -> FileChange -> preview/apply -> PostExecution
CodemodRecipedeclares arguments, ordered operations, and post actions.CodemodRunnerhandles CLI parsing, dry-run/apply, and errors.CodemodContextstores raw argument values and generic case helpers.CodemodTemplaterenders inline or file-backed templates.CodemodOperationplans file edits or file creation.CodeTransformconverts source text into deterministicSourcePatches.CodeEditorprovides AST-guided Dart insertion helpers.PostExecutionruns reusable commands after successful apply.
Example
import 'package:codemod_recipe/codemod_recipe.dart';
Future<void> main(List<String> args) {
return CodemodRunner(addMethodRecipe).run(args);
}
final addMethodRecipe = CodemodRecipe(
name: 'add_method',
args: [
CodemodArg.required('file'),
CodemodArg.required('class'),
CodemodArg.required('method'),
],
operations: [
EditDartFileOperation(
path: (context) => context.require('file'),
transforms: (context) => [
AddMethodTransform(
className: (context) => context.require('class'),
methodName: (context) => context.camel('method'),
body: const CodemodTemplate.inline('''
void {{method:camel}}() {}
'''),
),
],
),
],
postExecution: const [DartFormatPostExecution()],
);
Templates
Templates use Mustache-style placeholders with package-defined casing filters:
lib/features/{{feature:snake}}/{{feature:snake}}_view.dart
class {{feature:pascal}}View {}
final {{feature:camel}}Controller = ...
Supported casing filters are snake, camel, and pascal. Missing variables
and unsupported placeholders fail the run instead of rendering silently.
File Creation
Use CreateFileOperation to scaffold files:
CreateFileOperation(
path: (context) => context.render(
'lib/features/{{feature:snake}}/{{feature:snake}}_view.dart',
),
template: const CodemodTemplate.inline('''
class {{feature:pascal}}View {}
'''),
)
The default behavior fails when a file already exists. Use
FileExistsStrategy.skip or FileExistsStrategy.overwrite only when a recipe
explicitly wants that behavior.
Post Execution
Post actions run only after --apply succeeds. Built-ins include:
DartFormatPostExecutionProcessPostExecutionBuildRunnerPostExecution
Project Integration
Keep project conventions outside this package:
extension ProjectCodemodContext on CodemodContext {
String get featureName => require('feature');
String get featureFile => 'lib/features/${snake('feature')}.dart';
}
Then project-specific recipes can import this package plus their local extension file.
API Reference
See the API documentation for detailed information about all public classes and functions.
Key components:
- CodemodRecipe: Define recipes with arguments, operations, and post-execution actions.
- CodemodRunner: Execute recipes with CLI parsing and dry-run/apply support.
- CodemodContext: Access arguments and convert between naming conventions.
- CodemodTemplate: Render file and code templates with variable substitution.
- CodeEditor: AST-guided code modifications using the Dart analyzer.
- Transforms: Pre-built transforms for common operations like adding imports, methods, fields, and annotations.
Examples
The example/ directory contains runnable examples demonstrating:
add_method_example: Adding methods to existing classesscaffold_feature_example: Creating new feature files from templatescomposed_recipe_example: Combining multiple recipes with shared arguments
Run an example:
cd example/add_method_example
dart pub get
dart run bin/add_method.dart --help
Testing
Run package tests:
dart test
Tests should cover generic template rendering, operation behavior, patch behavior, recipe composition, and AST-guided editor primitives. Project-specific transforms should be tested in the consuming project.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines on development setup, running tests, and submitting pull requests.
License
This project is licensed under the BSD-3-Clause License - see the LICENSE file for details.
Libraries
- codemod_recipe
- Public API for building deterministic, recipe-based Dart codemods.