codemod_recipe 0.1.0
codemod_recipe: ^0.1.0 copied to clipboard
Reusable recipe primitives for deterministic Dart codemods and file scaffolds.
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.