codemod_recipe 0.1.0 copy "codemod_recipe: ^0.1.0" to clipboard
codemod_recipe: ^0.1.0 copied to clipboard

Reusable recipe primitives for deterministic Dart codemods and file scaffolds.

codemod_recipe #

Pub Version Dart CI License: BSD-3-Clause

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
  • CodemodRecipe declares arguments, ordered operations, and post actions.
  • CodemodRunner handles CLI parsing, dry-run/apply, and errors.
  • CodemodContext stores raw argument values and generic case helpers.
  • CodemodTemplate renders inline or file-backed templates.
  • CodemodOperation plans file edits or file creation.
  • CodeTransform converts source text into deterministic SourcePatches.
  • CodeEditor provides AST-guided Dart insertion helpers.
  • PostExecution runs 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:

  • DartFormatPostExecution
  • ProcessPostExecution
  • BuildRunnerPostExecution

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 classes
  • scaffold_feature_example: Creating new feature files from templates
  • composed_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.

0
likes
140
points
62
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Reusable recipe primitives for deterministic Dart codemods and file scaffolds.

Topics

#codemod #code-generation #dart #scaffolding #ast

License

BSD-3-Clause (license)

Dependencies

analyzer, args, mustache_template

More

Packages that depend on codemod_recipe