diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index e0c878e43e..121837695b 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -10,6 +10,7 @@ import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/generated/source_io.dart'; +import 'package:dartdoc/dartdoc.dart' show DartdocFailure; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/logging.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; @@ -63,6 +64,10 @@ class PackageGraph with CommentReferable, Nameable { var libraryElement = resolvedLibrary.element; var packageMeta = packageMetaProvider.fromElement(libraryElement, config.sdkDir); + if (packageMeta == null) { + throw DartdocFailure(packageMetaProvider.getMessageForMissingPackageMeta( + libraryElement, config)); + } var lib = Library.fromLibraryResult( resolvedLibrary, this, Package.fromPackageMeta(packageMeta, this)); packageMap[packageMeta.name].libraries.add(lib); diff --git a/lib/src/package_meta.dart b/lib/src/package_meta.dart index af7c277e4d..603a9f4e3a 100644 --- a/lib/src/package_meta.dart +++ b/lib/src/package_meta.dart @@ -44,7 +44,8 @@ final PackageMetaProvider pubPackageMetaProvider = PackageMetaProvider( .getFile(PhysicalResourceProvider.INSTANCE.pathContext .absolute(Platform.resolvedExecutable)) .parent2 - .parent2); + .parent2, + messageForMissingPackageMeta: PubPackageMeta.messageForMissingPackageMeta); /// Sets the supported way of constructing [PackageMeta] objects. /// @@ -63,15 +64,32 @@ class PackageMetaProvider { _fromElement; final PackageMeta Function(String, ResourceProvider) _fromFilename; final PackageMeta Function(Folder, ResourceProvider) _fromDir; + final String Function(LibraryElement, DartdocOptionContext) + _messageForMissingPackageMeta; PackageMeta fromElement(LibraryElement library, String s) => _fromElement(library, s, resourceProvider); + PackageMeta fromFilename(String s) => _fromFilename(s, resourceProvider); + PackageMeta fromDir(Folder dir) => _fromDir(dir, resourceProvider); + String getMessageForMissingPackageMeta( + LibraryElement library, DartdocOptionContext optionContext) => + _messageForMissingPackageMeta(library, optionContext); + PackageMetaProvider(this._fromElement, this._fromFilename, this._fromDir, this.resourceProvider, this.defaultSdkDir, - {this.defaultSdk}); + {this.defaultSdk, + Function(LibraryElement, DartdocOptionContext) + messageForMissingPackageMeta}) + : _messageForMissingPackageMeta = messageForMissingPackageMeta ?? + _defaultMessageForMissingPackageMeta; + + static String _defaultMessageForMissingPackageMeta( + LibraryElement library, DartdocOptionContext optionContext) { + return 'Unknown package for library: ${library.source.fullName}'; + } } /// Describes a single package in the context of `dartdoc`. @@ -255,6 +273,17 @@ abstract class PubPackageMeta extends PackageMeta { return _packageMetaCache[pathContext.absolute(folder.path)]; } + /// Create a helpful user error message for a case where a package can not + /// be found. + static String messageForMissingPackageMeta( + LibraryElement library, DartdocOptionContext optionContext) { + var libraryString = library.librarySource.fullName; + var dartOrFlutter = optionContext.flutterRoot == null ? 'dart' : 'flutter'; + return 'Unknown package for library: $libraryString. Consider `$dartOrFlutter pub get` and/or ' + '`$dartOrFlutter pub global deactivate dartdoc` followed by `$dartOrFlutter pub global activate dartdoc` to fix. ' + 'Also, be sure that `$dartOrFlutter analyze` completes without errors.'; + } + @override String sdkType(String flutterRootPath) { if (flutterRootPath != null) { diff --git a/test/documentation_comment_test.dart b/test/documentation_comment_test.dart index d6b5deb679..bacfea1cfb 100644 --- a/test/documentation_comment_test.dart +++ b/test/documentation_comment_test.dart @@ -44,13 +44,14 @@ void main() { sdkFolder = utils.writeMockSdkFiles(mockSdk); packageMetaProvider = PackageMetaProvider( - PubPackageMeta.fromElement, - PubPackageMeta.fromFilename, - PubPackageMeta.fromDir, - resourceProvider, - sdkFolder, - defaultSdk: mockSdk, - ); + PubPackageMeta.fromElement, + PubPackageMeta.fromFilename, + PubPackageMeta.fromDir, + resourceProvider, + sdkFolder, + defaultSdk: mockSdk, + messageForMissingPackageMeta: + PubPackageMeta.messageForMissingPackageMeta); var optionSet = await DartdocOptionSet.fromOptionGenerators( 'dartdoc', [createDartdocOptions], packageMetaProvider); optionSet.parseArguments([]); diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart index 80019df082..1a64fafc9a 100644 --- a/test/end2end/model_test.dart +++ b/test/end2end/model_test.dart @@ -93,6 +93,16 @@ void main() { packageGraph.libraries.firstWhere((lib) => lib.name == 'base_class'); }); + group('PackageMeta and PackageGraph integration', () { + test('PackageMeta error messages generate correctly', () { + var message = packageGraph.packageMetaProvider + .getMessageForMissingPackageMeta( + fakeLibrary.element, packageGraph.config); + expect(message, contains('fake.dart')); + expect(message, contains('pub global activate dartdoc')); + }); + }); + group('triple-shift', () { Library tripleShift; Class C, E, F; diff --git a/test/src/utils.dart b/test/src/utils.dart index 0e41a0aa98..413b072244 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -93,6 +93,7 @@ PackageMetaProvider get testPackageMetaProvider { resourceProvider, sdkFolder, defaultSdk: mockSdk, + messageForMissingPackageMeta: PubPackageMeta.messageForMissingPackageMeta, ); }