Skip to content

Commit eb8423c

Browse files
authored
Add helpers and checks for partial names. (#158)
* Add helpers and checks for partial names. * Oops. * CHANGELOG.
1 parent 93b006d commit eb8423c

File tree

4 files changed

+85
-17
lines changed

4 files changed

+85
-17
lines changed

CHANGELOG.md

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,35 @@
44
* Deprecated `builder.dart`: import `source_gen.dart` instead.
55
* Added `TypeChecker`, a high-level API for performing static type checks:
66

7-
```dart
8-
import 'package:analyzer/dart/element/type.dart';
9-
import 'package:source_gen/source_gen.dart';
10-
11-
void checkType(DartType dartType) {
12-
// Checks compared to runtime type `SomeClass`.
13-
print(const TypeChecker.forRuntime(SomeClass).isExactlyType(dartType));
7+
```dart
8+
import 'package:analyzer/dart/element/type.dart';
9+
import 'package:source_gen/source_gen.dart';
10+
11+
void checkType(DartType dartType) {
12+
// Checks compared to runtime type `SomeClass`.
13+
print(const TypeChecker.forRuntime(SomeClass).isExactlyType(dartType));
14+
15+
// Checks compared to a known Url/Symbol:
16+
const TypeChecker.forUrl('package:foo/foo.dart#SomeClass');
17+
18+
// Checks compared to another resolved `DartType`:
19+
const TypeChecker.forStatic(anotherDartType);
20+
}
21+
```
22+
23+
* Failing to add a `library` directive to a library that is being used as a
24+
generator target that generates partial files (`part of`) is now an explicit
25+
error that gives a hint on how to name and fix your library:
1426

15-
// Checks compared to a known Url/Symbol:
16-
const TypeChecker.forUrl('package:foo/foo.dart#SomeClass');
27+
```bash
28+
> Could not find library identifier so a "part of" cannot be built.
29+
>
30+
> Consider adding the following to your source file:
31+
>
32+
> "library foo.bar;"
33+
```
1734

18-
// Checks compared to another resolved `DartType`:
19-
const TypeChecker.forStatic(anotherDartType);
20-
}
21-
```
35+
In Dart SDK `>=1.25.0` this can be relaxed as `part of` can refer to a path.
2236

2337
## 0.5.8
2438

lib/src/builder.dart

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,26 @@ class GeneratorBuilder extends Builder {
8282
var generatedOutputs =
8383
await _generate(library, generators, buildStep).toList();
8484

85-
// Don't outputs useless files.
86-
if (generatedOutputs.isEmpty) return;
87-
8885
var contentBuffer = new StringBuffer();
8986

9087
if (!isStandalone) {
91-
contentBuffer.writeln('part of ${library.name};');
88+
var asset = buildStep.inputId;
89+
var name = nameOfPartial(library, asset);
90+
if (name == null) {
91+
var suggest = suggestLibraryName(asset);
92+
throw new InvalidGenerationSourceError(
93+
'Could not find library identifier so a "part of" cannot be built.',
94+
todo: ''
95+
'Consider adding the following to your source file:\n\n'
96+
'library $suggest;');
97+
}
98+
contentBuffer.writeln('part of $name;');
9299
contentBuffer.writeln();
93100
}
94101

102+
// Don't output useless files.
103+
if (generatedOutputs.isEmpty) return;
104+
95105
for (GeneratedOutput output in generatedOutputs) {
96106
contentBuffer.writeln('');
97107
contentBuffer.writeln(_headerLine);

lib/src/utils.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:analyzer/dart/ast/ast.dart';
66
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
77
import 'package:analyzer/dart/element/element.dart';
8+
import 'package:build/build.dart';
89

910
String friendlyNameForElement(Element element) {
1011
var friendlyName = element.displayName;
@@ -39,6 +40,40 @@ String friendlyNameForElement(Element element) {
3940
return names.join(' ');
4041
}
4142

43+
/// Returns a name suitable for `part of "..."` when pointing to [element].
44+
///
45+
/// Returns `null` if [element] is missing identifier.
46+
///
47+
/// Starting in `1.25.0`, setting [allowUnnamedPartials] will fallback
48+
/// (actually, preferred) to `'part of "package:foo/path.dart'`, and null will
49+
/// never be returned.
50+
String nameOfPartial(
51+
LibraryElement element,
52+
AssetId source, {
53+
bool allowUnnamedPartials: false,
54+
}) {
55+
if (element.name != null && element.name.isNotEmpty) {
56+
return element.name;
57+
}
58+
if (allowUnnamedPartials) {
59+
return '\'package:${source.package}/${source.path}\'';
60+
}
61+
return null;
62+
}
63+
64+
/// Returns a suggested library identifier based on [source] path and package.
65+
String suggestLibraryName(AssetId source) {
66+
// lib/test.dart --> [lib/test.dart]
67+
var parts = source.path.split('/');
68+
// [lib/test.dart] --> [lib/test]
69+
parts[parts.length - 1] = parts.last.split('.').first;
70+
// [lib/test] --> [test]
71+
if (parts.first == 'lib') {
72+
parts = parts.skip(1);
73+
}
74+
return '${source.package}.${parts.join('.')}';
75+
}
76+
4277
/// Returns all of the declarations in [unit], including [unit] as the first
4378
/// item.
4479
Iterable<Element> getElementsFromLibraryElement(LibraryElement unit) sync* {

test/builder_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ void main() {
6767
returnsNormally);
6868
});
6969

70+
test('Throws an exception when no library identifier is found', () async {
71+
var sources = _createPackageStub(pkgName, testLibContent: 'class A {}');
72+
var builder = new GeneratorBuilder([const CommentGenerator()]);
73+
expect(
74+
testBuilder(builder, sources,
75+
outputs: {'$pkgName|lib/test_lib.g.dart': ''}),
76+
throwsA(const isInstanceOf<InvalidGenerationSourceError>()));
77+
});
78+
7079
test(
7180
'Simple Generator test for library',
7281
() => _generateTest(

0 commit comments

Comments
 (0)