From 5ce8435ed0fdb54c33b2bd38cc0e191646d94aac Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Mon, 20 Apr 2020 11:16:20 -0700 Subject: [PATCH 1/5] Change default --- lib/src/dartdoc_options.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index 76d8757d40..f874b0610c 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -1529,14 +1529,14 @@ Future> createDartdocOptions() async { 'hosted', { 'pub.dartlang.org': - 'https://pub.dartlang.org/documentation/%n%/%v%' + 'https://pub.dev/documentation/%n%/%v%' }, help: 'Specify URLs for hosted pub packages'), DartdocOptionArgOnly>( 'sdks', { - 'Dart': 'https://api.dartlang.org/%b%/%v%', - 'Flutter': 'https://docs.flutter.io/flutter', + 'Dart': 'https://api.dart.dev/%b%/%v%', + 'Flutter': 'https://api.flutter.dev/flutter', }, help: 'Specify URLs for SDKs.', ), @@ -1558,7 +1558,7 @@ Future> createDartdocOptions() async { } return ''; }, help: 'Url to use for this particular package.'), - DartdocOptionArgOnly('remote', false, + DartdocOptionArgOnly('remote', true, help: 'Allow links to be generated for packages outside this one.', negatable: true), ]), From d02a71280c1d61885268de8fceb6a00d914e77b9 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Mon, 20 Apr 2020 17:14:04 -0700 Subject: [PATCH 2/5] Link to remote, spinner, doc fixes --- lib/dartdoc.dart | 2 +- lib/src/dartdoc_options.dart | 12 ++---- lib/src/generator/generator_frontend.dart | 1 - lib/src/logging.dart | 45 ++++++++++++++--------- lib/src/model/class.dart | 4 +- lib/src/model/inheritable.dart | 2 +- lib/src/model/locatable.dart | 2 + lib/src/model/model_element.dart | 1 + lib/src/model/nameable.dart | 2 +- lib/src/model/never.dart | 2 +- lib/src/model/package.dart | 6 +-- lib/src/model/package_builder.dart | 5 ++- lib/src/model/package_graph.dart | 3 ++ lib/src/model/top_level_container.dart | 2 +- pubspec.yaml | 1 + test/dartdoc_test.dart | 7 ++-- test/src/utils.dart | 29 +++++++++++---- 17 files changed, 75 insertions(+), 51 deletions(-) diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart index 1f491ae46f..18be6528ee 100644 --- a/lib/dartdoc.dart +++ b/lib/dartdoc.dart @@ -189,7 +189,7 @@ class Dartdoc extends PackageBuilder { } Future generateDocs() async { - logPrint("Documenting ${config.topLevelPackageMeta}..."); + logInfo("Documenting ${config.topLevelPackageMeta}..."); DartdocResults dartdocResults = await generateDocsBase(); if (dartdocResults.packageGraph.localPublicLibraries.isEmpty) { diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index f874b0610c..3ec23148c3 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -205,8 +205,8 @@ class Snapshot { bool _needsSnapshot = true; - /// Will return true precisely once, unless [toolPath] was already a snapshot. - /// In that case, will always return false. + /// Will return true precisely once, unless [snapshotFile] was already a + /// snapshot. In that case, will always return false. bool get needsSnapshot { if (_needsSnapshot == true) { _needsSnapshot = false; @@ -1525,12 +1525,8 @@ Future> createDartdocOptions() async { mustExist: true), DartdocOptionSet('linkTo') ..addAll([ - DartdocOptionArgOnly>( - 'hosted', - { - 'pub.dartlang.org': - 'https://pub.dev/documentation/%n%/%v%' - }, + DartdocOptionArgOnly>('hosted', + {'pub.dartlang.org': 'https://pub.dev/documentation/%n%/%v%'}, help: 'Specify URLs for hosted pub packages'), DartdocOptionArgOnly>( 'sdks', diff --git a/lib/src/generator/generator_frontend.dart b/lib/src/generator/generator_frontend.dart index 1f6225685a..b79a6c7cce 100644 --- a/lib/src/generator/generator_frontend.dart +++ b/lib/src/generator/generator_frontend.dart @@ -36,7 +36,6 @@ class GeneratorFrontEnd implements Generator { List indexAccumulator) { if (packageGraph == null) return; - logInfo('documenting ${packageGraph.defaultPackage.name}'); _generatorBackend.generatePackage( writer, packageGraph, packageGraph.defaultPackage); diff --git a/lib/src/logging.dart b/lib/src/logging.dart index ba162cefde..9b4f5154f2 100644 --- a/lib/src/logging.dart +++ b/lib/src/logging.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:cli_util/cli_logging.dart' show Ansi; import 'package:dartdoc/src/dartdoc_options.dart'; // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a @@ -29,6 +30,10 @@ void logInfo(Object message) { _logger.log(Level.INFO, message); } +void logDebug(Object message) { + _logger.log(Level.FINE, message); +} + void logProgress(Object message) { _logger.log(progressLevel, message); } @@ -74,12 +79,21 @@ void startLogging(LoggingContext config) { // Used to track if we're printing `...` to show progress. // Allows unified new-line tracking var writingProgress = false; + Ansi ansi = Ansi(Ansi.terminalSupportsAnsi); + int spinnerIndex = 0; + final List spinner = ['-', r'\', '|', '/']; Logger.root.onRecord.listen((record) { if (record.level == progressLevel) { - if (config.showProgress && stopwatch.elapsed.inMilliseconds > 250) { + if (!config.quiet && + config.showProgress && + stopwatch.elapsed.inMilliseconds > 125) { + if (writingProgress = false) { + stdout.write(' '); + } writingProgress = true; - stdout.write('.'); + stdout.write('${ansi.backspace}${spinner[spinnerIndex]}'); + spinnerIndex = (spinnerIndex + 1) % spinner.length; stopwatch.reset(); } return; @@ -87,9 +101,7 @@ void startLogging(LoggingContext config) { stopwatch.reset(); if (writingProgress) { - // print a new line after progress dots... - print(''); - writingProgress = false; + stdout.write('${ansi.backspace} ${ansi.backspace}'); } var message = record.message; assert(message == message.trimRight()); @@ -97,18 +109,17 @@ void startLogging(LoggingContext config) { if (record.level < Level.WARNING) { if (!config.quiet) { - if (config.showProgress && message.endsWith('...')) { - // Assume there may be more progress to print, so omit the trailing - // newline - writingProgress = true; - stdout.write(message); - } else { - print(message); - } + print(message); } } else { - stderr.writeln(message); + if (writingProgress) { + // Some console implementations, like IntelliJ, apparently need + // the backspace to occur for stderr as well. + stderr.write('${ansi.backspace} ${ansi.backspace}'); + } + stderr.write('${message}\n'); } + writingProgress = false; }); } } @@ -124,9 +135,9 @@ Future> createLoggingOptions() async { DartdocOptionArgOnly('json', false, help: 'Prints out progress JSON maps. One entry per line.', negatable: true), - DartdocOptionArgOnly('showProgress', false, - help: 'Display progress indications to console stdout', - negatable: false), + DartdocOptionArgOnly('showProgress', Ansi.terminalSupportsAnsi, + help: 'Display progress indications to console stdout.', + negatable: true), DartdocOptionArgSynth('quiet', (DartdocSyntheticOption option, Directory dir) { if (option.root['generateDocs']?.valueAt(dir) == false) { diff --git a/lib/src/model/class.dart b/lib/src/model/class.dart index dbe1cf883a..8c6dc0d68f 100644 --- a/lib/src/model/class.dart +++ b/lib/src/model/class.dart @@ -91,7 +91,7 @@ class Class extends Container Map> _allModelElementsByNamePart; - /// Helper for [_MarkdownCommentReference._getResultsForClass]. + /// Helper for `_MarkdownCommentReference._getResultsForClass`. Map> get allModelElementsByNamePart { if (_allModelElementsByNamePart == null) { _allModelElementsByNamePart = {}; @@ -435,8 +435,6 @@ class Class extends Container List _fields; - /// Internal only because subclasses are allowed to override how - /// these are mapped to [allInheritedFields] and so forth. @override List get allFields { if (_fields == null) { diff --git a/lib/src/model/inheritable.dart b/lib/src/model/inheritable.dart index ed41683987..dc16d342e8 100644 --- a/lib/src/model/inheritable.dart +++ b/lib/src/model/inheritable.dart @@ -16,7 +16,7 @@ import 'package:dartdoc/src/special_elements.dart'; /// namespace, that's the one we should treat as canonical and implementors /// of this class can use that knowledge to determine canonicalization. /// -/// We pick the class closest to the [definingEnclosingElement] so that all +/// We pick the class closest to the [definingEnclosingContainer] so that all /// children of that class inheriting the same member will point to the same /// place in the documentation, and we pick a canonical class because that's /// the one in the public namespace that will be documented. diff --git a/lib/src/model/locatable.dart b/lib/src/model/locatable.dart index 517c3d12d2..f140fb90ca 100644 --- a/lib/src/model/locatable.dart +++ b/lib/src/model/locatable.dart @@ -2,6 +2,8 @@ // 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/element/element.dart' show Element; + /// Something that can be located for warning purposes. abstract class Locatable { List get documentationFrom; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index f7ebe29928..a49cf64541 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -744,6 +744,7 @@ abstract class ModelElement extends Canonicalization @override bool get isCanonical { + if (!isPublic) return false; if (library == canonicalLibrary) { if (this is Inheritable) { Inheritable i = (this as Inheritable); diff --git a/lib/src/model/nameable.dart b/lib/src/model/nameable.dart index cd73e151f8..b344e5530e 100644 --- a/lib/src/model/nameable.dart +++ b/lib/src/model/nameable.dart @@ -24,7 +24,7 @@ abstract class Nameable { String _namePart; - /// Utility getter/cache for [_MarkdownCommentReference._getResultsForClass]. + /// Utility getter/cache for `_MarkdownCommentReference._getResultsForClass`. String get namePart { // TODO(jcollins-g): This should really be the same as 'name', but isn't // because of accessors and operators. diff --git a/lib/src/model/never.dart b/lib/src/model/never.dart index 5d25296f06..66783f0276 100644 --- a/lib/src/model/never.dart +++ b/lib/src/model/never.dart @@ -9,7 +9,7 @@ class NeverType extends ModelElement { NeverType(Element element, PackageGraph packageGraph) : super(element, null, packageGraph, null); - /// [never] is not a real object, and so we can't document it, so there + /// `Never` is not a real object, and so we can't document it, so there /// can be nothing canonical for it. @override ModelElement get canonicalModelElement => null; diff --git a/lib/src/model/package.dart b/lib/src/model/package.dart index 46721d50e5..9fe3fb8fe1 100644 --- a/lib/src/model/package.dart +++ b/lib/src/model/package.dart @@ -147,9 +147,9 @@ class Package extends LibraryContainer bool _isLocal; - /// Return true if this is the default package, this is part of an embedder SDK, - /// or if [config.autoIncludeDependencies] is true -- but only if the package - /// was not excluded on the command line. + /// Return true if this is the default package, this is part of an embedder + /// SDK, or if [DartdocOptionContext.autoIncludeDependencies] is true -- but + /// only if the package was not excluded on the command line. bool get isLocal { if (_isLocal == null) { _isLocal = ( diff --git a/lib/src/model/package_builder.dart b/lib/src/model/package_builder.dart index 2862a55081..ae44134b3d 100644 --- a/lib/src/model/package_builder.dart +++ b/lib/src/model/package_builder.dart @@ -163,7 +163,7 @@ class PackageBuilder { null, sourceFactory, options); - driver.results.listen((_) {}); + driver.results.listen((_) => logProgress('')); driver.exceptions.listen((_) {}); scheduler.start(); } @@ -243,11 +243,12 @@ class PackageBuilder { // Be careful here not to accidentally stack up multiple // ResolvedLibraryResults, as those eat our heap. for (String f in files) { + logProgress(f); ResolvedLibraryResult r = await processLibrary(f); if (r != null && !libraries.contains(r.element) && isLibraryIncluded(r.element)) { - logInfo('parsing ${f}...'); + logDebug('parsing ${f}...'); libraryAdder(r); libraries.add(r.element); } diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index 46e4bd7146..c3d96f48a7 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -14,6 +14,7 @@ import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/generated/source_io.dart'; import 'package:collection/collection.dart'; 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; @@ -103,11 +104,13 @@ class PackageGraph { !precachedElements.contains(d)) { precachedElements.add(d); yield d.precacheLocalDocs(); + logProgress(d.name); // TopLevelVariables get their documentation from getters and setters, // so should be precached if either has a template. if (m is TopLevelVariable && !precachedElements.contains(m)) { precachedElements.add(m); yield m.precacheLocalDocs(); + logProgress(d.name); } } } diff --git a/lib/src/model/top_level_container.dart b/lib/src/model/top_level_container.dart index b5fc82fbe0..32d61fb6bf 100644 --- a/lib/src/model/top_level_container.dart +++ b/lib/src/model/top_level_container.dart @@ -6,7 +6,7 @@ import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/model_utils.dart' as model_utils; /// A set of [Class]es, [Enum]s, [TopLevelVariable]s, [ModelFunction]s, -/// [Property]s, and [Typedef]s, possibly initialized after construction by +/// [Field]s, and [Typedef]s, possibly initialized after construction by /// accessing private member variables. Do not call any methods or members /// excepting [name] and the private Lists below before finishing initialization /// of a [TopLevelContainer]. diff --git a/pubspec.yaml b/pubspec.yaml index 10bbc3eeaf..a6c18fb617 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ dependencies: analyzer: ^0.39.6 args: '>=1.5.0 <2.0.0' collection: ^1.2.0 + cli_util: ^0.1.3+2 crypto: ^2.0.6 html: '>=0.12.1 <0.15.0' # We don't use http_parser directly; this dep exists to ensure that we get at diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart index 0d54e32247..17f724345d 100644 --- a/test/dartdoc_test.dart +++ b/test/dartdoc_test.dart @@ -211,8 +211,7 @@ void main() { }); test('basic interlinking test', () async { - Dartdoc dartdoc = - await buildDartdoc(['--link-to-remote'], testPackageDir, tempDir); + Dartdoc dartdoc = await buildDartdoc([], testPackageDir, tempDir); DartdocResults results = await dartdoc.generateDocs(); PackageGraph p = results.packageGraph; Package meta = p.publicPackages.firstWhere((p) => p.name == 'meta'); @@ -228,9 +227,9 @@ void main() { expect( useSomethingInAnotherPackage.modelType.linkedName, matches( - 'Required')); + 'Required')); RegExp stringLink = RegExp( - 'https://api.dartlang.org/(dev|stable|edge|be)/${Platform.version.split(' ').first}/dart-core/String-class.html">String'); + 'https://api.dart.dev/(dev|stable|edge|be|beta)/${Platform.version.split(' ').first}/dart-core/String-class.html">String'); expect(useSomethingInTheSdk.modelType.linkedName, contains(stringLink)); }); diff --git a/test/src/utils.dart b/test/src/utils.dart index 868b15590a..4b00313d54 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -28,29 +28,42 @@ PackageMeta sdkPackageMeta = PackageMeta.fromDir(sdkDir); final _testPackageGraphMemo = AsyncMemoizer(); Future get testPackageGraph => _testPackageGraphMemo.runOnce(() => - bootBasicPackage('testing/test_package', ['css', 'code_in_comments'])); + bootBasicPackage('testing/test_package', ['css', 'code_in_comments'], + additionalArguments: ['--no-link-to-remote'])); final _testPackageGraphExperimentsMemo = AsyncMemoizer(); Future get testPackageGraphExperiments => _testPackageGraphExperimentsMemo.runOnce(() => bootBasicPackage( - 'testing/test_package_experiments', [], - additionalArguments: ['--enable-experiment', 'non-nullable'])); + 'testing/test_package_experiments', [], additionalArguments: [ + '--enable-experiment', + 'non-nullable', + '--no-link-to-remote' + ])); final _testPackageGraphGinormousMemo = AsyncMemoizer(); Future get testPackageGraphGinormous => _testPackageGraphGinormousMemo.runOnce(() => bootBasicPackage( - 'testing/test_package', ['css', 'code_in_commnets', 'excluded'], - additionalArguments: ['--auto-include-dependencies'])); + 'testing/test_package', [ + 'css', + 'code_in_commnets', + 'excluded' + ], additionalArguments: [ + '--auto-include-dependencies', + '--no-link-to-remote' + ])); final _testPackageGraphSmallMemo = AsyncMemoizer(); -Future get testPackageGraphSmall => _testPackageGraphSmallMemo - .runOnce(() => bootBasicPackage('testing/test_package_small', [])); +Future get testPackageGraphSmall => + _testPackageGraphSmallMemo.runOnce(() => bootBasicPackage( + 'testing/test_package_small', [], + additionalArguments: ['--no-link-to-remote'])); final _testPackageGraphErrorsMemo = AsyncMemoizer(); Future get testPackageGraphErrors => _testPackageGraphErrorsMemo.runOnce(() => bootBasicPackage( 'testing/test_package_doc_errors', - ['css', 'code_in_comments', 'excluded'])); + ['css', 'code_in_comments', 'excluded'], + additionalArguments: ['--no-link-to-remote'])); final _testPackageGraphSdkMemo = AsyncMemoizer(); Future get testPackageGraphSdk => From 47936bc3cd55705dd2f8e01b2e4662b9333e6f57 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 21 Apr 2020 09:52:57 -0700 Subject: [PATCH 3/5] Fix dartdoc sanity check --- tool/grind.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tool/grind.dart b/tool/grind.dart index d338e3f1aa..529561f69d 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -960,7 +960,8 @@ Future testDartdoc() async { ]); expectFileContains(path.join(dartdocDocsDir.path, 'index.html'), ['dartdoc - Dart API docs']); - final RegExp object = RegExp('
  • Object
  • ', multiLine: true); + final RegExp object = + RegExp('Object-class.html">Object', multiLine: true); expectFileContains( path.join(dartdocDocsDir.path, 'dartdoc', 'ModelElement-class.html'), [object]); From 2802bb60d8101cfdd24437f0112c52b8a5f4eda9 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 21 Apr 2020 10:05:58 -0700 Subject: [PATCH 4/5] Update README for new outpu --- README.md | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 15ed8eaac5..63ec33d61c 100644 --- a/README.md +++ b/README.md @@ -20,25 +20,17 @@ For issues/details related to hosted Dart API docs, see ## Generating docs -Run `dartdoc` from the root directory of package. For example: +Run `dartdoc` from the root directory of a package. Here is an example of dartdoc documenting itself: ``` $ dartdoc -Generating documentation for 'server_code_lab' into /server_code_lab/doc/api/ - -parsing lib/client/piratesapi.dart... -parsing lib/common/messages.dart... -parsing lib/common/utils.dart... -parsing lib/server/piratesapi.dart... -Parsed 4 files in 8.1 seconds. - -generating docs for library pirate.messages from messages.dart... -generating docs for library pirate.server from piratesapi.dart... -generating docs for library pirate.utils from utils.dart... -generating docs for library server_code_lab.piratesApi.client from piratesapi.dart... -Documented 4 libraries in 9.6 seconds. - -Success! Docs generated into /server_code_lab/doc/api/index.html +Documenting dartdoc... +Initialized dartdoc with 766 libraries in 63.9 seconds +Generating docs for library dartdoc from package:dartdoc/dartdoc.dart... +Validating docs... +no issues found +Documented 1 public library in 17.9 seconds +Success! Docs generated into /doc/api ``` By default, the documentation is generated to the `doc/api` directory as static From 55a6d3512c93fb49332ffaa60c535edc4d0ac8e0 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 21 Apr 2020 12:58:04 -0700 Subject: [PATCH 5/5] Fix grinder tests --- tool/grind.dart | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tool/grind.dart b/tool/grind.dart index 529561f69d..27ee135d59 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -949,19 +949,19 @@ Future testDart2(Iterable tests) async { return CoverageSubprocessLauncher.generateCoverageToFile(File('lcov.info')); } -@Task('Generate docs for dartdoc') +@Task('Generate docs for dartdoc without link-to-remote') Future testDartdoc() async { var launcher = SubprocessLauncher('test-dartdoc'); await launcher.runStreamed(Platform.resolvedExecutable, [ '--enable-asserts', 'bin/dartdoc.dart', '--output', - dartdocDocsDir.path + dartdocDocsDir.path, + '--no-link-to-remote', ]); expectFileContains(path.join(dartdocDocsDir.path, 'index.html'), ['dartdoc - Dart API docs']); - final RegExp object = - RegExp('Object-class.html">Object', multiLine: true); + final RegExp object = RegExp('
  • Object
  • ', multiLine: true); expectFileContains( path.join(dartdocDocsDir.path, 'dartdoc', 'ModelElement-class.html'), [object]); @@ -971,12 +971,11 @@ Future testDartdoc() async { Future testDartdocRemote() async { var launcher = SubprocessLauncher('test-dartdoc-remote'); final RegExp object = RegExp( - 'Object', + 'Object', multiLine: true); await launcher.runStreamed(Platform.resolvedExecutable, [ '--enable-asserts', 'bin/dartdoc.dart', - '--link-to-remote', '--output', dartdocDocsDir.path ]); @@ -1033,8 +1032,8 @@ Future testDartdocFlutterPlugin() async { path.join( pluginPackageDocsDir.path, 'testlib', 'MyAwesomeWidget-class.html'), [ - 'Widget', - 'Object' + 'Widget', + 'Object' ]); }