Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
## 0.7.0

* **Breaking changes**
* `Generator.generate` now operates on a `LibraryElement` rather than being
* `Generator.generate` now operates on a `LibraryReader` rather than being
called for every `Element` within a library. Generators can iterate over
elements using the `allElements` utility. `GeneratorForAnnotation` will
elements using `LibraryReader.allElements`. `GeneratorForAnnotation` will
continue to call `generateForAnnotatedElement` repeatedly for each element.
* `GeneratorForAnnotation` passes in a `ConstantReader` for the annotation
instance rather than re-creating it using mirrors.
Expand All @@ -15,6 +15,7 @@
* Removed `OutputFormatter` typedef.
* Add `LibraryReader.allElements` - a utility to iterate across all `Element`
instances contained in Dart library.
* Add `LibraryReader.element` to get back to the `LibraryElement` instance.

## 0.6.1+1

Expand Down
4 changes: 3 additions & 1 deletion lib/src/builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:dart_style/dart_style.dart';

import 'generated_output.dart';
import 'generator.dart';
import 'library.dart';
import 'utils.dart';

typedef String _OutputFormatter(String code);
Expand Down Expand Up @@ -195,10 +196,11 @@ class LibraryBuilder extends _Builder {

Stream<GeneratedOutput> _generate(LibraryElement library,
List<Generator> generators, BuildStep buildStep) async* {
var libraryReader = new LibraryReader(library);
for (var gen in generators) {
try {
log.finer('Running $gen for $library');
var createdUnit = await gen.generate(library, buildStep);
var createdUnit = await gen.generate(libraryReader, buildStep);

if (createdUnit != null && createdUnit.isNotEmpty) {
log.finest(() => 'Generated $createdUnit for $library');
Expand Down
5 changes: 3 additions & 2 deletions lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

import 'dart:async';

import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';

import 'library.dart';

/// A tool to generate Dart code based on a Dart library source.
///
/// During a build [generate] is called once per input library.
Expand All @@ -19,7 +20,7 @@ abstract class Generator {
/// output is Dart code returned through the Future. If there is nothing to
/// generate for this library may return null, or a Future that resolves to
/// null or the empty string.
Future<String> generate(LibraryElement element, BuildStep buildStep) => null;
Future<String> generate(LibraryReader library, BuildStep buildStep) => null;

@override
String toString() => this.runtimeType.toString();
Expand Down
5 changes: 2 additions & 3 deletions lib/src/generator_for_annotation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ abstract class GeneratorForAnnotation<T> extends Generator {
TypeChecker get typeChecker => new TypeChecker.fromRuntime(T);

@override
Future<String> generate(LibraryElement library, BuildStep buildStep) async {
var elements = new LibraryReader(library)
.allElements
Future<String> generate(LibraryReader library, BuildStep buildStep) async {
var elements = library.allElements
.map((e) => new _AnnotatedElement(e, typeChecker.firstAnnotationOf(e)))
.where((e) => e.annotation != null);
var allOutput = await Future.wait(elements.map((e) =>
Expand Down
16 changes: 8 additions & 8 deletions lib/src/library.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@ import 'package:analyzer/src/dart/resolver/scope.dart';

/// A high-level wrapper API with common functionality for [LibraryElement].
class LibraryReader {
final LibraryElement _element;
final LibraryElement element;

Namespace _namespaceCache;

LibraryReader(this._element);
LibraryReader(this.element);

Namespace get _namespace => _namespaceCache ??=
new NamespaceBuilder().createExportNamespaceForLibrary(_element);
new NamespaceBuilder().createExportNamespaceForLibrary(element);

/// Returns a top-level [ClassElement] publicly visible in by [name].
///
/// Unlike [LibraryElement.getType], this also correctly traverses identifiers
/// that are accessible via one or more `export` directives.
ClassElement findType(String name) =>
_element.getType(name) ?? _namespace.get(name) as ClassElement;
element.getType(name) ?? _namespace.get(name) as ClassElement;

/// Returns all of the declarations in this library, including the
/// [LibraryElement] as the first item.
/// All of the declarations in this library, including the [LibraryElement] as
/// the first item.
Iterable<Element> get allElements sync* {
yield _element;
for (var cu in _element.units) {
yield element;
for (var cu in element.units) {
for (var compUnitMember in cu.unit.declarations) {
yield* _getElements(compUnitMember);
}
Expand Down
5 changes: 2 additions & 3 deletions test/builder_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
@TestOn('vm')
import 'dart:async';

import 'package:analyzer/dart/element/element.dart';
import 'package:build_test/build_test.dart';
import 'package:source_gen/source_gen.dart';
import 'package:test/test.dart';
Expand Down Expand Up @@ -175,12 +174,12 @@ Map<String, String> _createPackageStub(String pkgName,
/// Doesn't generate output for any element
class _NoOpGenerator extends Generator {
const _NoOpGenerator();
Future<String> generate(LibraryElement element, _) => null;
Future<String> generate(LibraryReader library, _) => null;
}

class _BadOutputGenerator extends Generator {
const _BadOutputGenerator();
Future<String> generate(LibraryElement element, _) async => 'not valid code!';
Future<String> generate(LibraryReader library, _) async => 'not valid code!';
}

const pkgName = 'pkg';
Expand Down
9 changes: 4 additions & 5 deletions test/src/comment_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ class CommentGenerator extends Generator {
const CommentGenerator({this.forClasses: true, this.forLibrary: false});

@override
Future<String> generate(LibraryElement library, _) async {
Future<String> generate(LibraryReader library, _) async {
var output = new StringBuffer();
if (forLibrary) {
output.writeln('// Code for "$library"');
output.writeln('// Code for "${library.element}"');
}
if (forClasses) {
for (var classElement in new LibraryReader(library)
.allElements
.where((e) => e is ClassElement)) {
for (var classElement
in library.allElements.where((e) => e is ClassElement)) {
if (classElement.displayName.contains('GoodError')) {
throw new InvalidGenerationSourceError(
"Don't use classes with the word 'Error' in the name",
Expand Down
3 changes: 1 addition & 2 deletions test/src/unformatted_code_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

import 'dart:async';

import 'package:analyzer/dart/element/element.dart';
import 'package:source_gen/source_gen.dart';

/// Generates a single-line of unformatted code.
class UnformattedCodeGenerator extends Generator {
const UnformattedCodeGenerator();

@override
Future<String> generate(LibraryElement element, _) async => unformattedCode;
Future<String> generate(LibraryReader library, _) async => unformattedCode;

static const formattedCode = '''
void hello() => print('hello');
Expand Down