Skip to content

Migrating to 0.7.x

Nate Bosch edited this page Mar 2, 2018 · 5 revisions

source_gen 0.7.0 introduced some breaking changes to how Generators are run, use this guide to upgrade your usage.

When extending GeneratorForAnnotation

The method signature has changed, but behavior is otherwise not impacted. Your GeneratorForAnnotation will behave as before – generateForAnnotation will continue to be called once per annotated element in the source library.

Changes to make

  • Change the annotation argument to generateForAnnotation from an instance of the annotation to an instance of ConstantReader. Pull fields from the reader using the read method.

For example:

// Before
class SomeGenerator extends GeneratorForAnnotation<SomeAnnotation> {
  @override
  Future<String> generateForAnnotation(
      Element element, SomeAnnotation annotation, BuildStep buildStep) {
    //...
    var someField = annotation.someField;
    //...
  }
}
// After
class SomeGenerator extends GeneratorForAnnotation<SomeAnnotation> {
  @override
  Future<String> generateForAnnotation(
      Element element, SomeAnnotation annotation, BuildStep buildStep) {
    //...
    var someField = annotation.read('someField').stringValue;
    //...
  }
}

Behavior Differences

  • generateForAnnotatedElement may get called for an Element before the previous call's Future has completed. In 0.6.0 the steps for each element were serialized, while in 0.7.0 they may run in parallel. This will only impact Generators which have some global state and a dependency on the order of the build which should be avoided.

These will most likely only impact tests:

  • The output will look a little different - blocks will no longer be commented with the element causing a snippet of code to get generated
  • Exceptions thrown will cause no code to get generated at all rather than insert comments in the generated output with the error message
  • The generate method, if called manually in a test, should only be called for an entire library at a time.

When extending Generator

The generate method is now called once per library rather than once per element within a library. Iterating over elements, if required, is now the responsibility of the generator.

Changes to make

  • Change the signature to take a LibraryReader as the first argument.
  • If required to visit every element within a library, iterate over them with LibraryReader.allElements.

For example

// Before
class SomeGenerator extends Generator {
  @override
  Future<String> generate(Element element, BuildStep buildStep) {
    if (element is LibraryElement) {
      // Do library stuff
      return result;
    } else {
      // Do non-library stuff
      return result;
    }
  }
}
// After
class SomeGenerator extends Generator {
  @override
  Future<String> generate(LibraryReader library, BuildStep buildStep) {
    var generated = new StringBuffer();
    var libraryElement = library.element
    // Do library stuff
    generated.writeln(result);
    for(var element in library.allElements) {
      // Do non-library stuff
      generated.writeln(result);
    }
    return '$generated';
  }
}

Behavior Differences

  • The output will look a little different - blocks will no longer be commented with which element causes a snippet of code to get generated unless you add the comment manually
  • Exceptions thrown will cause no code to get generated at all rather than insert comments in the generated output with the error message - if these comments are needed (usually for backwards compatibility in tests) catch exceptions manually to write these comments and be sure to log.severe so that the build can be marked as a failure overall
  • The generate method, if called manually in a test, should only be called for an entire library at a time.

When using as a Builder

Depending on whether the isStandalone argument was passed as true, construct either a PartBuilder (no isStandalone argument, or passing false) or a LibraryBuilder ('isStandalone: true`).