From d6de9e116400fc43de5df2900b76ca0bbc9e8735 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Sun, 18 Jun 2017 17:29:49 -0700 Subject: [PATCH 1/3] Add helpers and checks for partial names. --- lib/src/builder.dart | 19 +++++++++++++++---- lib/src/utils.dart | 36 ++++++++++++++++++++++++++++++++++++ test/builder_test.dart | 9 +++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/lib/src/builder.dart b/lib/src/builder.dart index 83c31ed7..a8cd970f 100644 --- a/lib/src/builder.dart +++ b/lib/src/builder.dart @@ -50,20 +50,31 @@ class GeneratorBuilder extends Builder { Future _generateForLibrary( LibraryElement library, BuildStep buildStep) async { + print('Hello'); log.fine('Running $generators for ${buildStep.inputId}'); var generatedOutputs = await _generate(library, generators, buildStep).toList(); - // Don't outputs useless files. - if (generatedOutputs.isEmpty) return; - var contentBuffer = new StringBuffer(); if (!isStandalone) { - contentBuffer.writeln('part of ${library.name};'); + var asset = buildStep.inputId; + var name = nameOfPartial(library, asset); + if (name == null) { + var suggest = suggestLibraryName(asset); + throw new InvalidGenerationSourceError( + 'Could not find library identifier so a "part of" cannot be built.', + todo: '' + 'Consider adding the following to your source file:\n\n' + 'library $suggest;'); + } + contentBuffer.writeln('part of $name;'); contentBuffer.writeln(); } + // Don't outputs useless files. + if (generatedOutputs.isEmpty) return; + for (GeneratedOutput output in generatedOutputs) { contentBuffer.writeln(''); contentBuffer.writeln(_headerLine); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 35327ff0..4c17244c 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,9 +1,11 @@ // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. + import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/standard_resolution_map.dart'; import 'package:analyzer/dart/element/element.dart'; +import 'package:build/build.dart'; String friendlyNameForElement(Element element) { var friendlyName = element.displayName; @@ -38,6 +40,40 @@ String friendlyNameForElement(Element element) { return names.join(' '); } +/// Returns a name suitable for `part of "..."` when pointing to [element]. +/// +/// Returns `null` if [element] is missing identifier. +/// +/// Starting in `1.25.0`, setting [allowUnnamedPartials] will fallback +/// (actually, preferred) to `'part of "package:foo/path.dart'`, and null will +/// never be returned. +String nameOfPartial( + LibraryElement element, + AssetId source, { + bool allowUnnamedPartials: false, +}) { + if (element.name != null && element.name.isNotEmpty) { + return element.name; + } + if (allowUnnamedPartials) { + return '\'package:${source.package}/${source.path}\''; + } + return null; +} + +/// Returns a suggested library identifier based on [source] path and package. +String suggestLibraryName(AssetId source) { + // lib/test.dart --> [lib/test.dart] + var parts = source.path.split('/'); + // [lib/test.dart] --> [lib/test] + parts[parts.length - 1] = parts.last.split('.').first; + // [lib/test] --> [test] + if (parts.first == 'lib') { + parts = parts.skip(1); + } + return '${source.package}.${parts.join('.')}'; +} + /// Returns all of the declarations in [unit], including [unit] as the first /// item. Iterable getElementsFromLibraryElement(LibraryElement unit) sync* { diff --git a/test/builder_test.dart b/test/builder_test.dart index 8225832e..09a4de96 100644 --- a/test/builder_test.dart +++ b/test/builder_test.dart @@ -66,6 +66,15 @@ void main() { returnsNormally); }); + test('Throws an exception when no library identifier is found', () async { + var sources = _createPackageStub(pkgName, testLibContent: 'class A {}'); + var builder = new GeneratorBuilder([const CommentGenerator()]); + expect( + testBuilder(builder, sources, + outputs: {'$pkgName|lib/test_lib.g.dart': ''}), + throwsA(const isInstanceOf())); + }); + test( 'Simple Generator test for library', () => _generateTest( From 818eb4ec3ccec3a6e2074a92356b629dbd1c49b7 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Sun, 18 Jun 2017 17:30:39 -0700 Subject: [PATCH 2/3] Oops. --- lib/src/builder.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/builder.dart b/lib/src/builder.dart index a8cd970f..31880b29 100644 --- a/lib/src/builder.dart +++ b/lib/src/builder.dart @@ -50,7 +50,6 @@ class GeneratorBuilder extends Builder { Future _generateForLibrary( LibraryElement library, BuildStep buildStep) async { - print('Hello'); log.fine('Running $generators for ${buildStep.inputId}'); var generatedOutputs = await _generate(library, generators, buildStep).toList(); From 0b94084fe186f52389250815203adb7409a2cb15 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 19 Jun 2017 15:54:40 -0700 Subject: [PATCH 3/3] CHANGELOG. --- CHANGELOG.md | 40 +++++++++++++++++++++++++++------------- lib/src/builder.dart | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0ca1765..69427a34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,21 +4,35 @@ * Deprecated `builder.dart`: import `source_gen.dart` instead. * Added `TypeChecker`, a high-level API for performing static type checks: -```dart -import 'package:analyzer/dart/element/type.dart'; -import 'package:source_gen/source_gen.dart'; - -void checkType(DartType dartType) { - // Checks compared to runtime type `SomeClass`. - print(const TypeChecker.forRuntime(SomeClass).isExactlyType(dartType)); + ```dart + import 'package:analyzer/dart/element/type.dart'; + import 'package:source_gen/source_gen.dart'; + + void checkType(DartType dartType) { + // Checks compared to runtime type `SomeClass`. + print(const TypeChecker.forRuntime(SomeClass).isExactlyType(dartType)); + + // Checks compared to a known Url/Symbol: + const TypeChecker.forUrl('package:foo/foo.dart#SomeClass'); + + // Checks compared to another resolved `DartType`: + const TypeChecker.forStatic(anotherDartType); + } + ``` + +* Failing to add a `library` directive to a library that is being used as a + generator target that generates partial files (`part of`) is now an explicit + error that gives a hint on how to name and fix your library: - // Checks compared to a known Url/Symbol: - const TypeChecker.forUrl('package:foo/foo.dart#SomeClass'); + ```bash + > Could not find library identifier so a "part of" cannot be built. + > + > Consider adding the following to your source file: + > + > "library foo.bar;" + ``` - // Checks compared to another resolved `DartType`: - const TypeChecker.forStatic(anotherDartType); -} -``` + In Dart SDK `>=1.25.0` this can be relaxed as `part of` can refer to a path. ## 0.5.8 diff --git a/lib/src/builder.dart b/lib/src/builder.dart index 282340c8..7aa4a148 100644 --- a/lib/src/builder.dart +++ b/lib/src/builder.dart @@ -99,7 +99,7 @@ class GeneratorBuilder extends Builder { contentBuffer.writeln(); } - // Don't outputs useless files. + // Don't output useless files. if (generatedOutputs.isEmpty) return; for (GeneratedOutput output in generatedOutputs) {