diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart index 917ee0339a..eaa0b4a284 100644 --- a/bin/dartdoc.dart +++ b/bin/dartdoc.dart @@ -12,17 +12,11 @@ import 'package:dartdoc/options.dart'; /// Analyzes Dart files and generates a representation of included libraries, /// classes, and members. Uses the current directory to look for libraries. Future main(List arguments) async { - var config = await parseOptions(arguments); + var config = await parseOptions(pubPackageMetaProvider, arguments); if (config == null) { // There was an error while parsing options. return; } - // Set the default way to construct [PackageMeta]. - PackageMeta.setPackageMetaFactories( - PubPackageMeta.fromElement, - PubPackageMeta.fromFilename, - PubPackageMeta.fromDir, - ); final packageBuilder = PubPackageBuilder(config); final dartdoc = config.generateDocs ? await Dartdoc.fromContext(config, packageBuilder) diff --git a/lib/options.dart b/lib/options.dart index 9383a6ed01..37627ddf8b 100644 --- a/lib/options.dart +++ b/lib/options.dart @@ -28,9 +28,12 @@ Future> createDartdocProgramOptions() async { ]; } -Future parseOptions(List arguments) async { +Future parseOptions( + PackageMetaProvider packageMetaProvider, + List arguments, +) async { var optionSet = await DartdocOptionSet.fromOptionGenerators('dartdoc', [ - createDartdocOptions, + () => createDartdocOptions(packageMetaProvider), createDartdocProgramOptions, createLoggingOptions, createGeneratorOptions, diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index ea316e1834..d542d7d7f4 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -1429,7 +1429,9 @@ class DartdocOptionContext extends DartdocOptionContextBase /// Instantiate dartdoc's configuration file and options parser with the /// given command line arguments. -Future> createDartdocOptions() async { +Future> createDartdocOptions( + PackageMetaProvider packageMetaProvider, +) async { return [ DartdocOptionArgOnly('allowTools', false, help: 'Execute user-defined tools to fill in @tool directives.', @@ -1562,7 +1564,7 @@ Future> createDartdocOptions() async { DartdocOptionSyntheticOnly( 'packageMeta', (DartdocSyntheticOption option, Directory dir) { - var packageMeta = PackageMeta.fromDir(dir); + var packageMeta = packageMetaProvider.fromDir(dir); if (packageMeta == null) { throw DartdocOptionError( 'Unable to determine package for directory: ${dir.path}'); @@ -1590,8 +1592,8 @@ Future> createDartdocOptions() async { help: "Label categories that aren't documented", negatable: true), DartdocOptionSyntheticOnly('topLevelPackageMeta', (DartdocSyntheticOption option, Directory dir) { - var packageMeta = PackageMeta.fromDir( - Directory(option.parent['inputDir'].valueAt(dir))); + var packageMeta = packageMetaProvider + .fromDir(Directory(option.parent['inputDir'].valueAt(dir))); if (packageMeta == null) { throw DartdocOptionError( 'Unable to generate documentation: no package found'); @@ -1632,7 +1634,7 @@ Future> createDartdocOptions() async { // TODO(jcollins-g): refactor so there is a single static "create" for // each DartdocOptionContext that traverses the inheritance tree itself. ...await createExperimentOptions(), - ...await createPackageWarningOptions(), + ...await createPackageWarningOptions(packageMetaProvider), ...await createSourceLinkerOptions(), ]; } diff --git a/lib/src/model/library.dart b/lib/src/model/library.dart index c0f8d184af..83d8357c45 100644 --- a/lib/src/model/library.dart +++ b/lib/src/model/library.dart @@ -426,7 +426,10 @@ class Library extends ModelElement with Categorization, TopLevelContainer { PackageMeta _packageMeta; PackageMeta get packageMeta { - _packageMeta ??= PackageMeta.fromElement(element, config.sdkDir); + _packageMeta ??= packageGraph.packageMetaProvider.fromElement( + element, + config.sdkDir, + ); return _packageMeta; } diff --git a/lib/src/model/package_builder.dart b/lib/src/model/package_builder.dart index 12466ea038..80c3d9fb21 100644 --- a/lib/src/model/package_builder.dart +++ b/lib/src/model/package_builder.dart @@ -26,7 +26,8 @@ import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/io_utils.dart'; import 'package:dartdoc/src/logging.dart'; import 'package:dartdoc/src/model/model.dart'; -import 'package:dartdoc/src/package_meta.dart' show PackageMeta; +import 'package:dartdoc/src/package_meta.dart' + show PackageMeta, pubPackageMetaProvider; import 'package:dartdoc/src/render/renderer_factory.dart'; import 'package:dartdoc/src/special_elements.dart'; import 'package:package_config/discovery.dart' as package_config; @@ -62,7 +63,12 @@ class PubPackageBuilder implements PackageBuilder { var rendererFactory = RendererFactory.forFormat(config.format); var newGraph = PackageGraph.UninitializedPackageGraph( - config, sdk, hasEmbedderSdkFiles, rendererFactory); + config, + sdk, + hasEmbedderSdkFiles, + rendererFactory, + pubPackageMetaProvider, + ); await getLibraries(newGraph); await newGraph.initializePackageGraph(); return newGraph; @@ -238,7 +244,7 @@ class PubPackageBuilder implements PackageBuilder { Set _packageMetasForFiles(Iterable files) { var metas = {}; for (var filename in files) { - metas.add(PackageMeta.fromFilename(filename)); + metas.add(pubPackageMetaProvider.fromFilename(filename)); } return metas; } diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index 4bdd9f6fee..97f34fb5f4 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -14,7 +14,8 @@ import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/logging.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/model_utils.dart' as utils; -import 'package:dartdoc/src/package_meta.dart' show PackageMeta; +import 'package:dartdoc/src/package_meta.dart' + show PackageMeta, PackageMetaProvider; import 'package:dartdoc/src/render/renderer_factory.dart'; import 'package:dartdoc/src/special_elements.dart'; import 'package:dartdoc/src/tuple.dart'; @@ -22,8 +23,12 @@ import 'package:dartdoc/src/warnings.dart'; class PackageGraph { PackageGraph.UninitializedPackageGraph( - this.config, this.sdk, this.hasEmbedderSdk, this.rendererFactory) - : packageMeta = config.topLevelPackageMeta { + this.config, + this.sdk, + this.hasEmbedderSdk, + this.rendererFactory, + this.packageMetaProvider, + ) : packageMeta = config.topLevelPackageMeta { _packageWarningCounter = PackageWarningCounter(this); // Make sure the default package exists, even if it has no libraries. // This can happen for packages that only contain embedder SDKs. @@ -38,7 +43,7 @@ class PackageGraph { void addLibraryToGraph(DartDocResolvedLibrary resolvedLibrary) { assert(!allLibrariesAdded); var element = resolvedLibrary.element; - var packageMeta = PackageMeta.fromElement(element, config.sdkDir); + var packageMeta = packageMetaProvider.fromElement(element, config.sdkDir); var lib = Library.fromLibraryResult( resolvedLibrary, this, Package.fromPackageMeta(packageMeta, this)); packageMap[packageMeta.name].libraries.add(lib); @@ -214,6 +219,9 @@ class PackageGraph { /// Factory for renderers final RendererFactory rendererFactory; + /// PackageMeta Provider for building [PackageMeta]s. + final PackageMetaProvider packageMetaProvider; + Package _defaultPackage; Package get defaultPackage { @@ -849,7 +857,7 @@ class PackageGraph { resolvedLibrary, this, Package.fromPackageMeta( - PackageMeta.fromElement(elementLibrary, config.sdkDir), + packageMetaProvider.fromElement(elementLibrary, config.sdkDir), packageGraph)); allLibraries[elementLibrary] = foundLibrary; return foundLibrary; diff --git a/lib/src/package_meta.dart b/lib/src/package_meta.dart index d751d8aa89..a03a2c2cf1 100644 --- a/lib/src/package_meta.dart +++ b/lib/src/package_meta.dart @@ -35,6 +35,28 @@ final List> __sdkDirFilePathsPosix = [ ['lib/core/core.dart'], ]; +final PackageMetaProvider pubPackageMetaProvider = PackageMetaProvider( + PubPackageMeta.fromElement, + PubPackageMeta.fromFilename, + PubPackageMeta.fromDir, +); + +/// Sets the supported way of constructing [PackageMeta] objects. +/// +/// These objects can be constructed from a filename, a directory +/// or a [LibraryElement]. We allow different dartdoc implementations to +/// provide their own [PackageMeta] types. +/// +/// By using a different provider, these implementations can control how +/// [PackageMeta] objects is built. +class PackageMetaProvider { + final PackageMeta Function(LibraryElement, String) fromElement; + final PackageMeta Function(String) fromFilename; + final PackageMeta Function(Directory) fromDir; + + PackageMetaProvider(this.fromElement, this.fromFilename, this.fromDir); +} + /// Describes a single package in the context of `dartdoc`. /// /// The primary function of this class is to allow canonicalization of packages @@ -104,46 +126,6 @@ abstract class PackageMeta { @override String toString() => name; - - /// Sets the supported ways of constructing [PackageMeta] objects. - /// - /// These objects can be constructed from a filename, a directory - /// or a [LibraryElement]. We allow different dartdoc implementations to - /// provide their own [PackageMeta] types. - /// - /// By calling this function, these implementations can control how - /// [PackageMeta] is built. - static void setPackageMetaFactories( - PackageMeta Function(LibraryElement, String) fromElementFactory, - PackageMeta Function(String) fromFilenameFactory, - PackageMeta Function(Directory) fromDirFactory, - ) { - assert(fromElementFactory != null); - assert(fromFilenameFactory != null); - assert(fromDirFactory != null); - if (_fromElement == fromElementFactory && - _fromFilename == fromFilenameFactory && - _fromDir == fromDirFactory) { - // Nothing to do. - return; - } - if (_fromElement != null || _fromFilename != null || _fromDir != null) { - throw StateError('PackageMeta factories cannot be changed once defined.'); - } - _fromElement = fromElementFactory; - _fromFilename = fromFilenameFactory; - _fromDir = fromDirFactory; - } - - static PackageMeta Function(LibraryElement, String) _fromElement; - static PackageMeta Function(String) _fromFilename; - static PackageMeta Function(Directory) _fromDir; - static PackageMeta Function(LibraryElement, String) get fromElement => - _fromElement ?? PubPackageMeta.fromElement; - static PackageMeta Function(String) get fromFilename => - _fromFilename ?? PubPackageMeta.fromFilename; - static PackageMeta Function(Directory) get fromDir => - _fromDir ?? PubPackageMeta.fromDir; } /// Default implementation of [PackageMeta] depends on pub packages. diff --git a/lib/src/warnings.dart b/lib/src/warnings.dart index a874cae8d3..e41a058100 100644 --- a/lib/src/warnings.dart +++ b/lib/src/warnings.dart @@ -23,7 +23,9 @@ abstract class PackageWarningOptionContext implements DartdocOptionContextBase { bool get verboseWarnings => optionSet['verboseWarnings'].valueAt(context); } -Future> createPackageWarningOptions() async { +Future> createPackageWarningOptions( + PackageMetaProvider packageMetaProvider, +) async { return [ DartdocOptionArgOnly('allowNonLocalWarnings', false, negatable: true, @@ -79,7 +81,10 @@ Future> createPackageWarningOptions() async { .join('\n')), // Synthetic option uses a factory to build a PackageWarningOptions from all the above flags. DartdocOptionSyntheticOnly( - 'packageWarningOptions', PackageWarningOptions.fromOptions), + 'packageWarningOptions', + (DartdocSyntheticOption option, Directory dir) => + PackageWarningOptions.fromOptions(option, dir, packageMetaProvider), + ), ]; } @@ -303,10 +308,13 @@ class PackageWarningOptions { /// [packageMeta] parameter is for testing. static PackageWarningOptions fromOptions( - DartdocSyntheticOption option, Directory dir) { + DartdocSyntheticOption option, + Directory dir, + PackageMetaProvider packageMetaProvider, + ) { // First, initialize defaults. var newOptions = PackageWarningOptions(); - var packageMeta = PackageMeta.fromDir(dir); + var packageMeta = packageMetaProvider.fromDir(dir); // Interpret errors/warnings/ignore options. In the event of conflict, warning overrides error and // ignore overrides warning. diff --git a/test/dartdoc_integration_test.dart b/test/dartdoc_integration_test.dart index 704df2cfa1..1fdb27fedb 100644 --- a/test/dartdoc_integration_test.dart +++ b/test/dartdoc_integration_test.dart @@ -164,7 +164,7 @@ void main() { await subprocessLauncher.runStreamed(Platform.resolvedExecutable, args, workingDirectory: _testPackagePath, perLine: (s) => output.writeln(s)); - var dartdocMeta = PackageMeta.fromFilename(dartdocPath); + var dartdocMeta = pubPackageMetaProvider.fromFilename(dartdocPath); expect(output.toString(), endsWith('dartdoc version: ${dartdocMeta.version}\n')); }); diff --git a/test/package_meta_test.dart b/test/package_meta_test.dart index b7b97b9375..4e4295a0f2 100644 --- a/test/package_meta_test.dart +++ b/test/package_meta_test.dart @@ -16,7 +16,7 @@ void main() { setUp(() { var d = Directory.systemTemp.createTempSync('test_package_not_valid'); - p = PackageMeta.fromDir(d); + p = pubPackageMetaProvider.fromDir(d); }); test('is not valid', () { @@ -25,7 +25,7 @@ void main() { }); group('PackageMeta for the test package', () { - var p = PackageMeta.fromDir(Directory( + var p = pubPackageMetaProvider.fromDir(Directory( path.join(Directory.current.path, 'testing', 'test_package'))); test('readme with corrupt UTF-8 loads without throwing', () { @@ -35,7 +35,7 @@ void main() { }); group('PackageMeta.fromDir for this package', () { - var p = PackageMeta.fromDir(Directory.current); + var p = pubPackageMetaProvider.fromDir(Directory.current); test('has a name', () { expect(p.name, 'dartdoc'); @@ -82,7 +82,7 @@ void main() { }); group('PackageMeta.fromSdk', () { - var p = PackageMeta.fromDir(defaultSdkDir); + var p = pubPackageMetaProvider.fromDir(defaultSdkDir); test('has a name', () { expect(p.name, 'Dart'); diff --git a/test/src/utils.dart b/test/src/utils.dart index 66cb3a3a3c..2099295825 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -24,7 +24,7 @@ final RegExp observatoryPortRegexp = RegExp(r'^Observatory listening on http://.*:(\d+)'); Directory sdkDir = defaultSdkDir; -PackageMeta sdkPackageMeta = PackageMeta.fromDir(sdkDir); +PackageMeta sdkPackageMeta = pubPackageMetaProvider.fromDir(sdkDir); final _testPackageGraphMemo = AsyncMemoizer(); Future get testPackageGraph => _testPackageGraphMemo.runOnce(() => @@ -98,8 +98,10 @@ final Directory testPackageCustomTemplates = /// the '--input' flag. Future generatorContextFromArgv( List argv) async { - var optionSet = await DartdocOptionSet.fromOptionGenerators( - 'dartdoc', [createDartdocOptions, createGeneratorOptions]); + var optionSet = await DartdocOptionSet.fromOptionGenerators('dartdoc', [ + () => createDartdocOptions(pubPackageMetaProvider), + createGeneratorOptions, + ]); optionSet.parseArguments(argv); return DartdocGeneratorOptionContext(optionSet, null); } @@ -107,8 +109,9 @@ Future generatorContextFromArgv( /// Convenience factory to build a [DartdocOptionContext] and associate it with a /// [DartdocOptionSet] based on the current working directory. Future contextFromArgv(List argv) async { - var optionSet = await DartdocOptionSet.fromOptionGenerators( - 'dartdoc', [createDartdocOptions]); + var optionSet = await DartdocOptionSet.fromOptionGenerators('dartdoc', [ + () => createDartdocOptions(pubPackageMetaProvider), + ]); optionSet.parseArguments(argv); return DartdocOptionContext(optionSet, Directory.current); } diff --git a/test/warnings_test.dart b/test/warnings_test.dart index 3dc54b23e4..fc14061663 100644 --- a/test/warnings_test.dart +++ b/test/warnings_test.dart @@ -8,6 +8,7 @@ library dartdoc.warnings_test; import 'dart:io'; import 'package:dartdoc/src/dartdoc_options.dart'; +import 'package:dartdoc/src/package_meta.dart'; import 'package:dartdoc/src/warnings.dart'; import 'package:path/path.dart' as path; import 'package:test/test.dart'; @@ -47,7 +48,7 @@ dartdoc: setUp(() async { optionSet = await DartdocOptionSet.fromOptionGenerators( - 'dartdoc', [createDartdocOptions]); + 'dartdoc', [() => createDartdocOptions(pubPackageMetaProvider)]); }); test('Verify that options for enabling/disabling packages work', () { diff --git a/tool/grind.dart b/tool/grind.dart index 943dc93b5a..4fde62e630 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -779,8 +779,12 @@ Future> _buildFlutterDocs( /// Returns the directory in which we generated documentation. Future _buildPubPackageDocs( - String pubPackageName, List dartdocParameters, - [String version, String label]) async { + String pubPackageName, + List dartdocParameters, + PackageMetaProvider packageMetaProvider, [ + String version, + String label, +]) async { var env = _createThrowawayPubCache(); var launcher = SubprocessLauncher( 'build-${pubPackageName}${version == null ? "" : "-$version"}${label == null ? "" : "-$label"}', @@ -793,7 +797,7 @@ Future _buildPubPackageDocs( Directory(path.join(env['PUB_CACHE'], 'hosted', 'pub.dartlang.org')); Directory pubPackageDir = cache.listSync().firstWhere((e) => e.path.contains(pubPackageName)); - if (PackageMeta.fromDir(pubPackageDir).requiresFlutter) { + if (packageMetaProvider.fromDir(pubPackageDir).requiresFlutter) { var flutterRepo = await FlutterRepo.fromExistingFlutterRepo(await cleanFlutterRepo); await launcher.runStreamed(flutterRepo.cachePub, ['get'], @@ -835,7 +839,12 @@ Future buildPubPackage() async { assert(Platform.environment.containsKey('PACKAGE_NAME')); var packageName = Platform.environment['PACKAGE_NAME']; var version = Platform.environment['PACKAGE_VERSION']; - return _buildPubPackageDocs(packageName, extraDartdocParameters, version); + return _buildPubPackageDocs( + packageName, + extraDartdocParameters, + pubPackageMetaProvider, + version, + ); } @Task(