From 0c654a2ab91aba9eee71b9afb1c505343d9e49f9 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 19 Apr 2018 09:33:20 -0700 Subject: [PATCH 1/4] squash changes --- bin/dartdoc.dart | 124 +++++++++----------- lib/dartdoc.dart | 18 +-- lib/src/config.dart | 3 +- lib/src/dartdoc_options.dart | 199 +++++++++++++++++++++++---------- lib/src/model.dart | 67 ++++++----- lib/src/package_meta.dart | 4 +- test/dartdoc_options_test.dart | 3 +- test/dartdoc_test.dart | 20 ++-- test/src/utils.dart | 27 +++-- 9 files changed, 267 insertions(+), 198 deletions(-) diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart index b0a4632206..b11a71d884 100644 --- a/bin/dartdoc.dart +++ b/bin/dartdoc.dart @@ -7,92 +7,67 @@ library dartdoc.bin; import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'dart:isolate' show Isolate; -import 'package:analyzer/file_system/physical_file_system.dart'; -import 'package:analyzer/src/dart/sdk/sdk.dart'; -import 'package:analyzer/src/generated/sdk.dart'; import 'package:args/args.dart'; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/logging.dart'; import 'package:logging/logging.dart' as logging; -import 'package:path/path.dart' as pathLib; import 'package:stack_trace/stack_trace.dart'; +class DartdocProgramOptionContext extends DartdocOptionContext { + DartdocProgramOptionContext(DartdocOptionSet optionSet, Directory dir) + : super(optionSet, dir); + + bool get help => optionSet['help'].valueAt(context); + bool get json => optionSet['json'].valueAt(context); + bool get showProgress => optionSet['showProgress'].valueAt(context); + bool get version => optionSet['version'].valueAt(context); +} + /// Analyzes Dart files and generates a representation of included libraries, /// classes, and members. Uses the current directory to look for libraries. main(List arguments) async { - var parser = _createArgsParser(); - ArgResults args; + DartdocOptionSet optionSet = await createDartdocOptions(); + optionSet.addAll([ + new DartdocOptionArgOnly('help', false, + abbr: 'h', help: 'Show command help.', negatable: false), + new DartdocOptionArgOnly('json', false, + help: 'Prints out progress JSON maps. One entry per line.', + negatable: true), + new DartdocOptionArgOnly('showProgress', false, + help: 'Display progress indications to console stdout', + negatable: false), + new DartdocOptionArgOnly('version', false, + help: 'Display the version for $name.', negatable: false), + ]); + + DartdocProgramOptionContext config = + new DartdocProgramOptionContext(optionSet, Directory.current); + try { - args = parser.parse(arguments); + optionSet.parseArguments(arguments); } on FormatException catch (e) { - stderr.writeln(e.message); + stderr.writeln(' fatal error: ${e.message}'); stderr.writeln(''); - // http://linux.die.net/include/sysexits.h - // #define EX_USAGE 64 /* command line usage error */ - _printUsageAndExit(parser, exitCode: 64); - } - - if (args['help']) { - _printHelpAndExit(parser); - } - - if (args['version']) { - print('$name version: $version'); - exit(0); - } - - Directory sdkDir = new Directory(args['sdk-dir']); - bool sdkDocs = args['sdk-docs']; - final bool showProgress = args['show-progress']; - - Directory inputDir; - if (sdkDocs) { - inputDir = sdkDir; - } else if (args['input'] == null) { - inputDir = Directory.current; - } else { - inputDir = args['input']; - } - - // If our input directory looks like the Dart SDK, then assume it is one, - // and is the one we want to document against. - PackageMeta packageMeta = new PackageMeta.fromDir(inputDir); - if (packageMeta.isSdk) { - sdkDir = inputDir; - sdkDocs = true; - } - - List footerTextFilePaths = []; - // If we're generating docs for the Dart SDK, we insert a copyright footer. - if (sdkDocs) { - Uri footerCopyrightUri = await Isolate.resolvePackageUri( - Uri.parse('package:dartdoc/resources/sdk_footer_text.html')); - footerTextFilePaths = [footerCopyrightUri.toFilePath()]; + _printUsageAndExit(optionSet.argParser, exitCode: 64); + } on DartdocOptionError catch (e) { + stderr.writeln(' fatal error: ${e.message}'); + stderr.writeln(''); + _printUsageAndExit(optionSet.argParser, exitCode: 64); } - footerTextFilePaths.addAll(args['footer-text']); - - Directory outputDir = - new Directory(pathLib.join(Directory.current.path, defaultOutDir)); - if (args['output'] != null) { - outputDir = new Directory(_resolveTildePath(args['output'])); + if (optionSet['help'].valueAt(Directory.current)) { + _printHelpAndExit(optionSet.argParser); } - if (args.rest.isNotEmpty) { - var unknownArgs = args.rest.join(' '); - stderr.writeln( - ' fatal error: detected unknown command-line argument(s): $unknownArgs'); - _printUsageAndExit(parser, exitCode: 1); + if (optionSet['version'].valueAt(Directory.current)) { + _printHelpAndExit(optionSet.argParser); } - final logJson = args['json'] as bool; - // By default, get all log output at `progressLevel` or greater. // This allows us to capture progress events and print `...`. logging.Logger.root.level = progressLevel; - if (logJson) { + if (config.json) { logging.Logger.root.onRecord.listen((record) { if (record.level == progressLevel) { return; @@ -117,7 +92,7 @@ main(List arguments) async { logging.Logger.root.onRecord.listen((record) { if (record.level == progressLevel) { - if (showProgress && stopwatch.elapsed.inMilliseconds > 250) { + if (config.showProgress && stopwatch.elapsed.inMilliseconds > 250) { writingProgress = true; stdout.write('.'); stopwatch.reset(); @@ -136,7 +111,7 @@ main(List arguments) async { assert(message.isNotEmpty); if (record.level < logging.Level.WARNING) { - if (showProgress && message.endsWith('...')) { + if (config.showProgress && message.endsWith('...')) { // Assume there may be more progress to print, so omit the trailing // newline writingProgress = true; @@ -149,7 +124,7 @@ main(List arguments) async { } }); } - + /* if (packageMeta == null) { stderr.writeln( ' fatal error: Unable to generate documentation: no pubspec.yaml found'); @@ -162,7 +137,8 @@ main(List arguments) async { ' fatal error: Unable to generate documentation: $firstError.'); exit(1); } - + */ + PackageMeta packageMeta = config.packageMeta; if (!packageMeta.isSdk && packageMeta.needsPubGet) { try { packageMeta.runPubGet(); @@ -172,11 +148,13 @@ main(List arguments) async { } } + Directory outputDir = new Directory(config.output); logInfo("Generating documentation for '${packageMeta}' into " "${outputDir.absolute.path}${Platform.pathSeparator}"); + /* DartSdk sdk = new FolderBasedDartSdk(PhysicalResourceProvider.INSTANCE, - PhysicalResourceProvider.INSTANCE.getFolder(sdkDir.path)); + PhysicalResourceProvider.INSTANCE.getFolder(config.sdkDir)); List dropTextFrom = []; if (args['hide-sdk-text']) { @@ -199,7 +177,6 @@ main(List arguments) async { 'dart.web_audio' ]); } - DartdocConfig config = new DartdocConfig.fromParameters( addCrossdart: args['add-crossdart'], autoIncludeDependencies: args['auto-include-dependencies'], @@ -229,7 +206,7 @@ main(List arguments) async { validateLinks: args['validate-links'], verboseWarnings: args['verbose-warnings'], ); - + */ Dartdoc dartdoc = await Dartdoc.withDefaultGenerators(config, outputDir, packageMeta); @@ -252,7 +229,7 @@ main(List arguments) async { } }); } - +/* ArgParser _createArgsParser() { var parser = new ArgParser(); parser.addFlag('add-crossdart', @@ -359,6 +336,7 @@ ArgParser _createArgsParser() { return parser; } +*/ /// Print help if we are passed the help option. void _printHelpAndExit(ArgParser parser, {int exitCode: 0}) { @@ -372,6 +350,7 @@ void _printUsageAndExit(ArgParser parser, {int exitCode: 0}) { exit(exitCode); } +/* String _resolveTildePath(String originalPath) { if (originalPath == null || !originalPath.startsWith('~/')) { return originalPath; @@ -387,3 +366,4 @@ String _resolveTildePath(String originalPath) { return pathLib.join(homeDir, originalPath.substring(2)); } +*/ diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart index b4c7cedfd6..1c40eec4a0 100644 --- a/lib/dartdoc.dart +++ b/lib/dartdoc.dart @@ -13,7 +13,7 @@ import 'package:analyzer/analyzer.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/src/generated/engine.dart'; import 'package:analyzer/src/generated/source.dart'; -import 'package:dartdoc/src/config.dart'; +import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/generator.dart'; import 'package:dartdoc/src/html/html_generator.dart'; import 'package:dartdoc/src/logging.dart'; @@ -74,20 +74,20 @@ class Dartdoc extends PackageBuilder { final StreamController _onCheckProgress = new StreamController(sync: true); - Dartdoc._(DartdocConfig config, this.generators, this.outputDir, + Dartdoc._(DartdocOptionContext config, this.generators, this.outputDir, PackageMeta packageMeta) : super(config, packageMeta); /// An asynchronous factory method that builds Dartdoc's file writers /// and returns a Dartdoc object with them. - static withDefaultGenerators(DartdocConfig config, Directory outputDir, + static withDefaultGenerators(DartdocOptionContext config, Directory outputDir, PackageMeta packageMeta) async { var generators = await _initGenerators( config.hostedUrl, config.relCanonicalPrefix, - headerFilePaths: config.headerFilePaths, - footerFilePaths: config.footerFilePaths, - footerTextFilePaths: config.footerTextFilePaths, - faviconPath: config.faviconPath, + headerFilePaths: config.header, + footerFilePaths: config.footer, + footerTextFilePaths: config.footerTextPaths, + faviconPath: config.favicon, prettyIndexJson: config.prettyIndexJson); for (var generator in generators) { generator.onFileCreated.listen(logProgress); @@ -95,8 +95,8 @@ class Dartdoc extends PackageBuilder { return new Dartdoc._(config, generators, outputDir, packageMeta); } - factory Dartdoc.withoutGenerators( - DartdocConfig config, Directory outputDir, PackageMeta packageMeta) { + factory Dartdoc.withoutGenerators(DartdocOptionContext config, + Directory outputDir, PackageMeta packageMeta) { return new Dartdoc._(config, [], outputDir, packageMeta); } diff --git a/lib/src/config.dart b/lib/src/config.dart index 6fd1e1e769..c57f24dd6b 100644 --- a/lib/src/config.dart +++ b/lib/src/config.dart @@ -9,7 +9,7 @@ import 'dart:io'; import 'package:dartdoc/dartdoc.dart'; import 'package:path/path.dart' as pathLib; - +/* String _resolveTildePath(String originalPath) { if (originalPath == null || !originalPath.startsWith('~/')) { return originalPath; @@ -166,3 +166,4 @@ class DartdocConfig { bool isPackageExcluded(String name) => excludePackages.any((pattern) => name == pattern); } +*/ diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index 2bc1c3a7a2..04117fd5d1 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -14,9 +14,13 @@ /// library dartdoc.dartdoc_options; +import 'dart:async'; import 'dart:io'; +import 'dart:isolate'; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/file_system/physical_file_system.dart'; +import 'package:analyzer/src/dart/sdk/sdk.dart'; import 'package:args/args.dart'; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/logging.dart'; @@ -32,6 +36,14 @@ const int _kIntVal = 0; const double _kDoubleVal = 0.0; const bool _kBoolVal = true; +Uri _sdkFooterCopyrightUri; +Future _setSdkFooterCopyrightUri() async { + if (_sdkFooterCopyrightUri == null) { + _sdkFooterCopyrightUri = await Isolate.resolvePackageUri( + Uri.parse('package:dartdoc/resources/sdk_footer_text.html')); + } +} + String _resolveTildePath(String originalPath) { if (originalPath == null || !originalPath.startsWith('~/')) { return originalPath; @@ -770,19 +782,22 @@ abstract class _DartdocArgOption implements DartdocOption { /// and so this can be made a member variable of those structures. class DartdocOptionContext { final DartdocOptionSet optionSet; - Directory _context; + Directory context; DartdocOptionContext(this.optionSet, FileSystemEntity entity) { - _context = new Directory(pathLib + context = new Directory(pathLib .canonicalize(entity is File ? entity.parent.path : entity.path)); } - /// Build a [DartdocOptionSet] and associate it with a [DartdocOptionContext] - /// based on the input directory. - factory DartdocOptionContext.fromArgv(List argv) { - DartdocOptionSet optionSet = _createDartdocOptions(argv); - String inputDir = optionSet['input'].valueAtCurrent(); - return new DartdocOptionContext(optionSet, new Directory(inputDir)); + // TODO(jcollins-g): Allow passing in structured data to initialize a + // [DartdocOptionContext]'s arguments + + /// Convenience factory to build a [DartdocOptionSet] and associate it with a + /// [DartdocOptionContext] based on the current working directory. + static fromArgv(List argv) async { + DartdocOptionSet optionSet = await createDartdocOptions(); + optionSet.parseArguments(argv); + return new DartdocOptionContext(optionSet, Directory.current); } /// Build a DartdocOptionContext from an analyzer element (using its source @@ -807,67 +822,102 @@ class DartdocOptionContext { } // All values defined in createDartdocOptions should be exposed here. - - bool get addCrossdart => optionSet['addCrossdart'].valueAt(_context); + bool get addCrossdart => optionSet['addCrossdart'].valueAt(context); double get ambiguousReexportScorerMinConfidence => - optionSet['ambiguousReexportScorerMinConfidence'].valueAt(_context); + optionSet['ambiguousReexportScorerMinConfidence'].valueAt(context); bool get autoIncludeDependencies => - optionSet['autoIncludeDependencies'].valueAt(_context); - List get categoryOrder => - optionSet['categoryOrder'].valueAt(_context); + optionSet['autoIncludeDependencies'].valueAt(context); + List get categoryOrder => optionSet['categoryOrder'].valueAt(context); + List get dropTextFrom => optionSet['dropTextFrom'].valueAt(context); String get examplePathPrefix => - optionSet['examplePathPrefix'].valueAt(_context); - List get exclude => optionSet['exclude'].valueAt(_context); + optionSet['examplePathPrefix'].valueAt(context); + List get exclude => optionSet['exclude'].valueAt(context); List get excludePackages => - optionSet['excludePackages'].valueAt(_context); - String get favicon => optionSet['favicon'].valueAt(_context); - List get footer => optionSet['footer'].valueAt(_context); - List get footerText => optionSet['footerText'].valueAt(_context); - List get header => optionSet['header'].valueAt(_context); - bool get help => optionSet['help'].valueAt(_context); - bool get hideSdkText => optionSet['hideSdkText'].valueAt(_context); - String get hostedUrl => optionSet['hostedUrl'].valueAt(_context); - List get include => optionSet['include'].valueAt(_context); + optionSet['excludePackages'].valueAt(context); + String get favicon => optionSet['favicon'].valueAt(context); + List get footer => optionSet['footer'].valueAt(context); + + /// _footerText is only used to construct synthetic options. + List get _footerText => + optionSet['footerText'].valueAt(context); // ignore: unused_element + List get footerTextPaths => + optionSet['footerTextPaths'].valueAt(context); + List get header => optionSet['header'].valueAt(context); + bool get hideSdkText => optionSet['hideSdkText'].valueAt(context); + String get hostedUrl => optionSet['hostedUrl'].valueAt(context); + List get include => optionSet['include'].valueAt(context); List get includeExternal => - optionSet['includeExternal'].valueAt(_context); - bool get includeSource => optionSet['includeSource'].valueAt(_context); - String get input => optionSet['input'].valueAt(_context); - bool get json => optionSet['json'].valueAt(_context); - String get output => optionSet['output'].valueAt(_context); - List get packageOrder => optionSet['packageOrder'].valueAt(_context); - bool get prettyIndexJson => optionSet['prettyIndexJson'].valueAt(_context); + optionSet['includeExternal'].valueAt(context); + bool get includeSource => optionSet['includeSource'].valueAt(context); + + /// _input is only used to construct synthetic options. + String get _input => + optionSet['input'].valueAt(context); // ignore: unused_element + String get inputDir => optionSet['inputDir'].valueAt(context); + String get output => optionSet['output'].valueAt(context); + List get packageOrder => optionSet['packageOrder'].valueAt(context); + PackageMeta get packageMeta => optionSet['packageMeta'].valueAt(context); + bool get prettyIndexJson => optionSet['prettyIndexJson'].valueAt(context); String get relCanonicalPrefix => - optionSet['relCanonicalPrefix'].valueAt(_context); - bool get sdkDocs => optionSet['sdkDocs'].valueAt(_context); - String get sdkDir => optionSet['sdkDir'].valueAt(_context); - bool get showProgress => optionSet['showProgress'].valueAt(_context); - bool get showWarnings => optionSet['showWarnings'].valueAt(_context); - bool get useCategories => optionSet['useCategories'].valueAt(_context); - bool get validateLinks => optionSet['validateLinks'].valueAt(_context); - bool get verboseWarnings => optionSet['verboseWarnings'].valueAt(_context); - bool get version => optionSet['version'].valueAt(_context); + optionSet['relCanonicalPrefix'].valueAt(context); + bool get sdkDocs => optionSet['sdkDocs'].valueAt(context); + String get sdkDir => optionSet['sdkDir'].valueAt(context); + bool get showWarnings => optionSet['showWarnings'].valueAt(context); + bool get useCategories => optionSet['useCategories'].valueAt(context); + bool get validateLinks => optionSet['validateLinks'].valueAt(context); + bool get verboseWarnings => optionSet['verboseWarnings'].valueAt(context); + + bool isLibraryExcluded(String name) => + exclude.any((pattern) => name == pattern); + bool isPackageExcluded(String name) => + excludePackages.any((pattern) => name == pattern); } /// Instantiate dartdoc's configuration file and options parser with the /// given command line arguments. -DartdocOptionSet _createDartdocOptions(List argv) { +Future createDartdocOptions() async { + await (_setSdkFooterCopyrightUri()); // Sync with DartdocOptionContext. return new DartdocOptionSet('dartdoc') ..addAll([ new DartdocOptionArgOnly('addCrossdart', false, help: 'Add Crossdart links to the source code pieces.', - negatable: false), + negatable: true), new DartdocOptionBoth('ambiguousReexportScorerMinConfidence', 0.1, help: 'Minimum scorer confidence to suppress warning on ambiguous reexport.'), new DartdocOptionArgOnly('autoIncludeDependencies', false, help: 'Include all the used libraries into the docs, even the ones not in the current package or "include-external"', - negatable: false), + negatable: true), new DartdocOptionBoth>('categoryOrder', [], help: "A list of categories (not package names) to place first when grouping symbols on dartdoc's sidebar. " 'Unmentioned categories are sorted after these.'), + new DartdocOptionSynthetic>('dropTextFrom', + (DartdocOptionSynthetic option, Directory dir) { + if (option.parent['hideSdkText'].valueAt(dir)) { + return [ + 'dart.async', + 'dart.collection', + 'dart.convert', + 'dart.core', + 'dart.developer', + 'dart.html', + 'dart.indexed_db', + 'dart.io', + 'dart.lisolate', + 'dart.js', + 'dart.js_util', + 'dart.math', + 'dart.mirrors', + 'dart.svg', + 'dart.typed_data', + 'dart.web_audio' + ]; + } + return []; + }, help: 'Remove text from libraries with the following names.'), new DartdocOptionBoth('examplePathPrefix', null, isDir: true, help: 'Prefix for @example paths.\n(defaults to the project root)', @@ -892,12 +942,20 @@ DartdocOptionSet _createDartdocOptions(List argv) { 'and version).', mustExist: true, splitCommas: true), + new DartdocOptionSynthetic>('footerTextPaths', + (DartdocOptionSynthetic option, Directory dir) { + List footerTextPaths = []; + // TODO(jcollins-g): Eliminate special casing for SDK and use config file. + if (new PackageMeta.fromDir(dir).isSdk) { + footerTextPaths.add(_sdkFooterCopyrightUri.toFilePath()); + } + footerTextPaths.addAll(option.parent['footerText'].valueAt(dir)); + return footerTextPaths; + }), new DartdocOptionBoth>('header', [], isFile: true, help: 'paths to header files containing HTML text.', splitCommas: true), - new DartdocOptionArgOnly('help', false, - abbr: 'h', help: 'Show command help.', negatable: false), new DartdocOptionArgOnly('hideSdkText', false, hide: true, help: @@ -906,7 +964,7 @@ DartdocOptionSet _createDartdocOptions(List argv) { new DartdocOptionArgOnly('hostedUrl', null, help: 'URL where the docs will be hosted (used to generate the sitemap).'), - new DartdocOptionBoth>('include', null, + new DartdocOptionBoth>('include', [], help: 'Library names to generate docs for.', splitCommas: true), new DartdocOptionBoth>('includeExternal', null, isFile: true, @@ -919,11 +977,32 @@ DartdocOptionSet _createDartdocOptions(List argv) { help: 'Show source code blocks.', negatable: true), new DartdocOptionArgOnly('input', Directory.current.path, isDir: true, help: 'Path to source directory', mustExist: true), - new DartdocOptionArgOnly('json', false, - help: 'Prints out progress JSON maps. One entry per line.', - negatable: true), + new DartdocOptionSynthetic('inputDir', + (DartdocOptionSynthetic option, Directory dir) { + if (option.parent['sdkDocs'].valueAt(dir)) { + return option.parent['sdkDir'].valueAt(dir); + } + return option.parent['input'].valueAt(dir); + }, + help: 'Path to source directory (with override if --sdk-dir)', + isDir: true, + mustExist: true), new DartdocOptionArgOnly('output', defaultOutDir, isDir: true, help: 'Path to output directory.'), + new DartdocOptionSynthetic('packageMeta', + (DartdocOptionSynthetic option, Directory dir) { + PackageMeta packageMeta = new PackageMeta.fromDir( + new Directory(option.parent['inputDir'].valueAt(dir))); + if (packageMeta == null) { + throw new DartdocOptionError( + 'Unable to generate documentation: no package found'); + } + if (!packageMeta.isValid) { + final String firstError = packageMeta.getInvalidReasons().first; + throw new DartdocOptionError('Package is invalid: $firstError'); + } + return packageMeta; + }, help: 'PackageMeta object for the default package.'), new DartdocOptionBoth>('packageOrder', [], help: 'A list of package names to place first when grouping libraries in packages. ' @@ -937,30 +1016,25 @@ DartdocOptionSet _createDartdocOptions(List argv) { 'If provided, add a rel="canonical" prefixed with provided value. ' 'Consider using if\nbuilding many versions of the docs for public ' 'SEO; learn more at https://goo.gl/gktN6F.'), - new DartdocOptionArgOnly('sdk-docs', false, + new DartdocOptionArgOnly('sdkDocs', false, help: 'Generate ONLY the docs for the Dart SDK.', negatable: false), - new DartdocOptionArgOnly('sdk-dir', defaultSdkDir.absolute.path, + new DartdocOptionArgOnly('sdkDir', defaultSdkDir.absolute.path, help: 'Path to the SDK directory', isDir: true, mustExist: true), - new DartdocOptionArgOnly('show-progress', false, - help: 'Display progress indications to console stdout', - negatable: false), - new DartdocOptionArgOnly('show-warnings', false, + new DartdocOptionArgOnly('showWarnings', false, help: 'Display all warnings.', negatable: false), - new DartdocOptionArgOnly('use-categories', true, + new DartdocOptionArgOnly('useCategories', true, help: 'Display categories in the sidebar of packages', negatable: false), - new DartdocOptionArgOnly('validate-links', true, + new DartdocOptionArgOnly('validateLinks', true, help: 'Runs the built-in link checker to display Dart context aware warnings for broken links (slow)', negatable: true), - new DartdocOptionArgOnly('verbose-warnings', true, + new DartdocOptionArgOnly('verboseWarnings', true, help: 'Display extra debugging information and help with warnings.', negatable: true), - new DartdocOptionArgOnly('version', false, - help: 'Display the version for $name.', negatable: false), ]); } - +/* final Map _dartdocOptionsCache = {}; /// Legacy dartdoc options class. TODO(jcollins-g): merge with [DartdocOption]. @@ -1053,3 +1127,4 @@ class _FileDartdocOptions extends DartdocOptions { return _categoryOrder; } } +*/ diff --git a/lib/src/model.dart b/lib/src/model.dart index 60f601f06a..0b5bf760e4 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -1158,7 +1158,7 @@ abstract class Documentable extends Nameable { String get oneLineDoc; PackageGraph get packageGraph; bool get isDocumented; - DartdocConfig get config; + DartdocOptionContext get config; } /// Mixin implementing dartdoc categorization for ModelElements. @@ -2766,8 +2766,15 @@ abstract class ModelElement extends Canonicalization return _isPublic; } + DartdocOptionContext _config; @override - DartdocConfig get config => packageGraph.config; + DartdocOptionContext get config { + if (_config == null) { + _config = new DartdocOptionContext.fromContextElement( + packageGraph.config, element); + } + return _config; + } @override Set get locationPieces { @@ -2947,7 +2954,7 @@ abstract class ModelElement extends Canonicalization List debugLines = []; debugLines.addAll(scoredCandidates.map((s) => '${s.toString()}')); - if (confidence < config.reexportMinConfidence) { + if (confidence < config.ambiguousReexportScorerMinConfidence) { warnable.warn(PackageWarning.ambiguousReexport, message: message, extendedDebug: debugLines); } @@ -3845,7 +3852,7 @@ class PackageGraph extends Canonicalization /// Dartdoc's configuration flags. @override - final DartdocConfig config; + final DartdocOptionContext config; Map> __crossdartJson; // TODO(jcollins-g): move to [Package] @@ -3853,7 +3860,7 @@ class PackageGraph extends Canonicalization if (__crossdartJson == null) { // TODO(jcollins-g): allow crossdart.json location to be configurable var crossdartFile = - new File(pathLib.join(config.inputDir.path, "crossdart.json")); + new File(pathLib.join(config.inputDir, "crossdart.json")); if (crossdartFile.existsSync()) { Map __crossdartJsonTmp = json.decode(crossdartFile.readAsStringSync()); @@ -4656,21 +4663,21 @@ abstract class LibraryContainer extends Nameable /// A category is a subcategory of a package, containing libraries tagged /// with a @category identifier. Comparable so it can be sorted according to -/// [dartdocOptions.categoryOrder]. +/// [config.categoryOrder]. class Category extends LibraryContainer { final String _name; /// All libraries in [libraries] must come from [package]. final Package package; - final DartdocOptions dartdocOptions; + final DartdocOptionContext config; - Category(this._name, this.package, this.dartdocOptions); + Category(this._name, this.package, this.config); @override String get name => _name; @override - List get containerOrder => dartdocOptions.categoryOrder; + List get containerOrder => config.categoryOrder; @override Package get enclosingContainer => package; @@ -4792,11 +4799,11 @@ class Package extends LibraryContainer /// A map of category name to the category itself. Map get nameToCategory { if (_nameToCategory.isEmpty) { - _nameToCategory[null] = new Category(null, this, dartdocOptions); + _nameToCategory[null] = new Category(null, this, config); for (Library lib in libraries) { String category = lib.categoryName; _nameToCategory.putIfAbsent( - category, () => new Category(category, this, dartdocOptions)); + category, () => new Category(category, this, config)); _nameToCategory[category]._libraries.add(lib); } } @@ -4812,12 +4819,13 @@ class Package extends LibraryContainer return _categories; } - DartdocOptions _dartdocOptions; - DartdocOptions get dartdocOptions { - if (_dartdocOptions == null) { - _dartdocOptions = new DartdocOptions.fromDir(new Directory(packagePath)); + DartdocOptionContext _config; + DartdocOptionContext get config { + if (_config == null) { + _config = new DartdocOptionContext.fromContext( + packageGraph.config, new Directory(packagePath)); } - return _dartdocOptions; + return _config; } /// Is this the package at the top of the list? We display the first @@ -4831,7 +4839,7 @@ class Package extends LibraryContainer String get packagePath { if (_packagePath == null) { if (isSdk) { - _packagePath = packageGraph.config.sdkDir.path; + _packagePath = packageGraph.config.sdkDir; } else { assert(libraries.isNotEmpty); File file = new File( @@ -4950,8 +4958,8 @@ abstract class SourceCodeMixin implements Documentable { String source = contents.substring(start, node.end); if (config.addCrossdart) { - source = crossdartifySource(config.inputDir.path, - packageGraph.crossdartJson, source, element, start); + source = crossdartifySource(config.inputDir, packageGraph.crossdartJson, + source, element, start); } else { source = const HtmlEscape().convert(source); } @@ -5000,7 +5008,7 @@ abstract class SourceCodeMixin implements Documentable { } } else if (uri.startsWith("dart:")) { var packageName = "sdk"; - var packageVersion = config.sdkVersion; + var packageVersion = packageGraph.sdk.sdkVersion; return "${packageName}/${packageVersion}/lib/${uri.replaceAll(new RegExp(r"^dart:"), "")}"; } else { return null; @@ -5238,7 +5246,7 @@ class TypeParameter extends ModelElement { /// Everything you need to instantiate a PackageGraph object for documenting. class PackageBuilder { final PackageMeta packageMeta; - final DartdocConfig config; + final DartdocOptionContext config; PackageBuilder(this.config, this.packageMeta); @@ -5254,7 +5262,7 @@ class PackageBuilder { DartSdk get sdk { if (_sdk == null) { _sdk = new FolderBasedDartSdk(PhysicalResourceProvider.INSTANCE, - PhysicalResourceProvider.INSTANCE.getFolder(config.sdkDir.path)); + PhysicalResourceProvider.INSTANCE.getFolder(config.sdkDir)); } return _sdk; } @@ -5289,7 +5297,7 @@ class PackageBuilder { Map> get packageMap { if (_packageMap == null) { fileSystem.Folder cwd = - PhysicalResourceProvider.INSTANCE.getResource(config.inputDir.path); + PhysicalResourceProvider.INSTANCE.getResource(config.inputDir); _packageMap = _calculatePackageMap(cwd); } return _packageMap; @@ -5492,7 +5500,7 @@ class PackageBuilder { new Uri.file(pathLib.join(basePackageDir, 'pubspec.yaml'))) .asMap(); for (String packageName in info.keys) { - if (!filterExcludes || !config.excludeLibraries.contains(packageName)) { + if (!filterExcludes || !config.exclude.contains(packageName)) { packageDirs.add(pathLib.dirname(info[packageName].toFilePath())); } } @@ -5532,7 +5540,7 @@ class PackageBuilder { files.addAll(packageMeta.isSdk ? new Set() : findFilesToDocumentInPackage( - config.inputDir.path, config.autoIncludeDependencies)); + config.inputDir, config.autoIncludeDependencies)); if (packageMeta.isSdk) { files.addAll(getSdkFilesToDocument()); } else if (embedderSdk.urlMappings.isNotEmpty && !packageMeta.isSdk) { @@ -5543,7 +5551,7 @@ class PackageBuilder { } // Use the includeExternals. for (String fullName in driver.knownFiles) { - if (config.includeExternals.any((string) => fullName.endsWith(string))) + if (config.includeExternal.any((string) => fullName.endsWith(string))) files.add(fullName); } return new Set.from(files.map((s) => new File(s).absolute.path)); @@ -5552,16 +5560,15 @@ class PackageBuilder { Future> getLibraries(Set files) async { Set libraries = new Set(); libraries.addAll(await _parseLibraries(files)); - if (config.includeLibraries.isNotEmpty) { + if (config.include.isNotEmpty) { Iterable knownLibraryNames = libraries.map((l) => l.name); - Set notFound = new Set.from(config.includeLibraries) + Set notFound = new Set.from(config.include) .difference(new Set.from(knownLibraryNames)); if (notFound.isNotEmpty) { throw 'Did not find: [${notFound.join(', ')}] in ' 'known libraries: [${knownLibraryNames.join(', ')}]'; } - libraries - .removeWhere((lib) => !config.includeLibraries.contains(lib.name)); + libraries.removeWhere((lib) => !config.include.contains(lib.name)); } return libraries; } diff --git a/lib/src/package_meta.dart b/lib/src/package_meta.dart index 4e5ca8c251..17e9351036 100644 --- a/lib/src/package_meta.dart +++ b/lib/src/package_meta.dart @@ -81,10 +81,10 @@ abstract class PackageMeta { /// Use this instead of fromDir where possible. factory PackageMeta.fromElement( - LibraryElement libraryElement, DartdocConfig config) { + LibraryElement libraryElement, DartdocOptionContext config) { // Workaround for dart-lang/sdk#32707. Replace with isInSdk once that works. if (libraryElement.source.uri.scheme == 'dart') - return new PackageMeta.fromDir(config.sdkDir); + return new PackageMeta.fromDir(new Directory(config.sdkDir)); return new PackageMeta.fromDir( new File(pathLib.canonicalize(libraryElement.source.fullName)).parent); } diff --git a/test/dartdoc_options_test.dart b/test/dartdoc_options_test.dart index f7fc3ed5b4..cd5d4f9e88 100644 --- a/test/dartdoc_options_test.dart +++ b/test/dartdoc_options_test.dart @@ -548,7 +548,7 @@ dartdoc: equals('parent')); }); }); - + /* group('dartdoc options', () { group('options file finding and loading', () { test('DartdocOptions loads defaults', () { @@ -572,4 +572,5 @@ dartdoc: }); }); }); + */ } diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart index a0f6237145..eba3e7b502 100644 --- a/test/dartdoc_test.dart +++ b/test/dartdoc_test.dart @@ -30,7 +30,7 @@ void main() { () async { PackageMeta meta = new PackageMeta.fromDir(testPackageDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - new DartdocConfig.fromParameters(inputDir: testPackageDir), + await DartdocOptionContext.fromArgv(['--input', testPackageDir.path]), tempDir, meta); @@ -48,7 +48,8 @@ void main() { () async { PackageMeta meta = new PackageMeta.fromDir(testPackageBadDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - new DartdocConfig.fromParameters(inputDir: testPackageBadDir), + await DartdocOptionContext + .fromArgv(['--input', testPackageBadDir.path]), tempDir, meta); @@ -63,7 +64,8 @@ void main() { test('generate docs for a package that does not have a readme', () async { PackageMeta meta = new PackageMeta.fromDir(testPackageWithNoReadme); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - new DartdocConfig.fromParameters(inputDir: testPackageWithNoReadme), + await DartdocOptionContext + .fromArgv(['--input', testPackageWithNoReadme.path]), tempDir, meta); @@ -80,8 +82,8 @@ void main() { test('generate docs including a single library', () async { PackageMeta meta = new PackageMeta.fromDir(testPackageDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - new DartdocConfig.fromParameters( - inputDir: testPackageDir, includeLibraries: ['fake']), + await DartdocOptionContext + .fromArgv(['--input', testPackageDir.path, '--include', 'fake']), tempDir, meta); @@ -98,8 +100,8 @@ void main() { test('generate docs excluding a single library', () async { PackageMeta meta = new PackageMeta.fromDir(testPackageDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - new DartdocConfig.fromParameters( - inputDir: testPackageDir, excludeLibraries: ['fake']), + await DartdocOptionContext + .fromArgv(['--input', testPackageDir.path, '--exclude', 'fake']), tempDir, meta); @@ -118,8 +120,8 @@ void main() { PackageMeta meta = new PackageMeta.fromDir(testPackageWithEmbedderYaml); if (meta.needsPubGet) meta.runPubGet(); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - new DartdocConfig.fromParameters( - inputDir: testPackageWithEmbedderYaml), + await DartdocOptionContext + .fromArgv(['--input', testPackageWithEmbedderYaml.path]), tempDir, meta); diff --git a/test/src/utils.dart b/test/src/utils.dart index 34593fb3db..11286eb4c7 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -46,28 +46,31 @@ init() async { testPackageGraphSdk = await bootSdkPackage(); } -Future bootSdkPackage() { +Future bootSdkPackage() async { Directory dir = new Directory(pathLib.current); return new PackageBuilder( - new DartdocConfig.fromParameters( - inputDir: dir, - sdkDir: sdkDir, - ), + await DartdocOptionContext + .fromArgv(['--input', dir.path, '--sdk-dir', sdkDir.path]), sdkPackageMeta) .buildPackageGraph(); } Future bootBasicPackage( String dirPath, List excludeLibraries, - {bool withAutoIncludedDependencies = false, bool withCrossdart = false}) { + {bool withAutoIncludedDependencies = false, + bool withCrossdart = false}) async { Directory dir = new Directory(dirPath); return new PackageBuilder( - new DartdocConfig.fromParameters( - inputDir: dir, - sdkDir: sdkDir, - excludeLibraries: excludeLibraries, - addCrossdart: withCrossdart, - autoIncludeDependencies: withAutoIncludedDependencies), + await DartdocOptionContext.fromArgv([ + '--input', + dir.path, + '--sdk-dir', + sdkDir.path, + '--exclude', + excludeLibraries.join(','), + '--${withCrossdart ? "" : "no-"}add-crossdart', + '--${withAutoIncludedDependencies ? "" : "no-"}auto-include-dependencies' + ]), new PackageMeta.fromDir(new Directory(dirPath))) .buildPackageGraph(); } From 72e439d52e8314ebd61709887293a41b318a6a1f Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 19 Apr 2018 12:47:05 -0700 Subject: [PATCH 2/4] Refactors complete, linkups integrated, tests pass --- README.md | 22 +- bin/dartdoc.dart | 305 ++--------------- lib/dartdoc.dart | 73 ++-- lib/src/config.dart | 169 ---------- lib/src/dartdoc_options.dart | 424 ++++++++---------------- lib/src/html/html_generator.dart | 97 +++++- lib/src/logging.dart | 84 +++++ lib/src/model.dart | 29 +- lib/src/package_meta.dart | 2 +- test/dartdoc_test.dart | 42 +-- test/src/utils.dart | 38 ++- testing/test_package_bad/pubspec.lock | 5 + testing/test_package_small/pubspec.lock | 2 +- 13 files changed, 432 insertions(+), 860 deletions(-) delete mode 100644 lib/src/config.dart create mode 100644 testing/test_package_bad/pubspec.lock diff --git a/README.md b/README.md index 4dd7677f59..3dcd5f7002 100644 --- a/README.md +++ b/README.md @@ -103,13 +103,29 @@ generates docs. ```yaml dartdoc: categoryOrder: ["First Category", "Second Category"] - ``` -For now, there's only one option: + +Unrecognized options will be ignored. For now, there's only one supported option: * **categoryOrder**: Specify the order of categories, below, for display in the sidebar and the package page. - + +The following are experimental options whose semantics are in flux and may be buggy. If you +use one, please keep a close eye on the changing semantics. In general, paths are relative +to the directory the dartdoc_options.yaml the option is defined in and should be specified +as POSIX paths. Dartdoc will convert POSIX paths automatically on Windows. + + * **ambiguousReexportScorerMinConfidence**: The ambiguous reexport scorer will emit a warning if + it is not at least this confident. Default: 0.1 + * **examplePathPrefix**: Specify the prefix for the example paths, defaulting to the project root. + * **exclude**: Specify a list of library names to avoid generating docs for, ignoring all others. + * **favicon**: A path to a favicon for the generated docs. + * **footer**: A list of paths to footer files containing HTML text. + * **footerText**: A list of paths to text files for optional text next to the package name and version + * **header**: A list of paths to header files containing HTML text. + * **include**: Specify a list of library names to generate docs for, ignoring all others. + * **includeExternal**: Specify a list of library filenames to add to the list of documented libraries. + ### Categories You can tag libraries in their documentation with the string `{@category YourCategory}`, and diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart index b11a71d884..d8a9b3c23e 100644 --- a/bin/dartdoc.dart +++ b/bin/dartdoc.dart @@ -5,40 +5,41 @@ library dartdoc.bin; import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:args/args.dart'; import 'package:dartdoc/dartdoc.dart'; +import 'package:dartdoc/src/html/html_generator.dart'; import 'package:dartdoc/src/logging.dart'; -import 'package:logging/logging.dart' as logging; import 'package:stack_trace/stack_trace.dart'; -class DartdocProgramOptionContext extends DartdocOptionContext { +class DartdocProgramOptionContext extends DartdocOptionContext + with LoggingContext, GeneratorContext { DartdocProgramOptionContext(DartdocOptionSet optionSet, Directory dir) : super(optionSet, dir); bool get help => optionSet['help'].valueAt(context); - bool get json => optionSet['json'].valueAt(context); - bool get showProgress => optionSet['showProgress'].valueAt(context); bool get version => optionSet['version'].valueAt(context); } -/// Analyzes Dart files and generates a representation of included libraries, -/// classes, and members. Uses the current directory to look for libraries. -main(List arguments) async { - DartdocOptionSet optionSet = await createDartdocOptions(); - optionSet.addAll([ +Future> createDartdocProgramOptions() async { + return [ new DartdocOptionArgOnly('help', false, abbr: 'h', help: 'Show command help.', negatable: false), - new DartdocOptionArgOnly('json', false, - help: 'Prints out progress JSON maps. One entry per line.', - negatable: true), - new DartdocOptionArgOnly('showProgress', false, - help: 'Display progress indications to console stdout', - negatable: false), new DartdocOptionArgOnly('version', false, help: 'Display the version for $name.', negatable: false), + ]; +} + +/// Analyzes Dart files and generates a representation of included libraries, +/// classes, and members. Uses the current directory to look for libraries. +main(List arguments) async { + DartdocOptionSet optionSet = + await DartdocOptionSet.fromOptionGenerators('dartdoc', [ + createDartdocOptions, + createDartdocProgramOptions, + createLoggingOptions, + createGeneratorOptions, ]); DartdocProgramOptionContext config = @@ -58,157 +59,17 @@ main(List arguments) async { if (optionSet['help'].valueAt(Directory.current)) { _printHelpAndExit(optionSet.argParser); } - if (optionSet['version'].valueAt(Directory.current)) { _printHelpAndExit(optionSet.argParser); } - // By default, get all log output at `progressLevel` or greater. - // This allows us to capture progress events and print `...`. - logging.Logger.root.level = progressLevel; - - if (config.json) { - logging.Logger.root.onRecord.listen((record) { - if (record.level == progressLevel) { - return; - } - - var output = {'level': record.level.name}; - - if (record.object is Jsonable) { - output['data'] = record.object; - } else { - output['message'] = record.message; - } - - print(json.encode(output)); - }); - } else { - final stopwatch = new Stopwatch()..start(); - - // Used to track if we're printing `...` to show progress. - // Allows unified new-line tracking - var writingProgress = false; - - logging.Logger.root.onRecord.listen((record) { - if (record.level == progressLevel) { - if (config.showProgress && stopwatch.elapsed.inMilliseconds > 250) { - writingProgress = true; - stdout.write('.'); - stopwatch.reset(); - } - return; - } - - stopwatch.reset(); - if (writingProgress) { - // print a new line after progress dots... - print(''); - writingProgress = false; - } - var message = record.message; - assert(message == message.trimRight()); - assert(message.isNotEmpty); - - if (record.level < logging.Level.WARNING) { - 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); - } - } else { - stderr.writeln(message); - } - }); - } - /* - if (packageMeta == null) { - stderr.writeln( - ' fatal error: Unable to generate documentation: no pubspec.yaml found'); - exit(1); - } - - if (!packageMeta.isValid) { - final String firstError = packageMeta.getInvalidReasons().first; - stderr.writeln( - ' fatal error: Unable to generate documentation: $firstError.'); - exit(1); - } - */ - PackageMeta packageMeta = config.packageMeta; - if (!packageMeta.isSdk && packageMeta.needsPubGet) { - try { - packageMeta.runPubGet(); - } catch (e) { - stderr.writeln('$e'); - exit(1); - } - } + startLogging(config); Directory outputDir = new Directory(config.output); - logInfo("Generating documentation for '${packageMeta}' into " + logInfo("Generating documentation for '${config.packageMeta}' into " "${outputDir.absolute.path}${Platform.pathSeparator}"); - /* - DartSdk sdk = new FolderBasedDartSdk(PhysicalResourceProvider.INSTANCE, - PhysicalResourceProvider.INSTANCE.getFolder(config.sdkDir)); - - List dropTextFrom = []; - if (args['hide-sdk-text']) { - dropTextFrom.addAll([ - 'dart.async', - 'dart.collection', - 'dart.convert', - 'dart.core', - 'dart.developer', - 'dart.html', - 'dart.indexed_db', - 'dart.io', - 'dart.lisolate', - 'dart.js', - 'dart.js_util', - 'dart.math', - 'dart.mirrors', - 'dart.svg', - 'dart.typed_data', - 'dart.web_audio' - ]); - } - DartdocConfig config = new DartdocConfig.fromParameters( - addCrossdart: args['add-crossdart'], - autoIncludeDependencies: args['auto-include-dependencies'], - dropTextFrom: dropTextFrom, - examplePathPrefix: args['example-path-prefix'], - excludeLibraries: args['exclude'], - excludePackages: args['exclude-packages'], - faviconPath: args['favicon'], - footerFilePaths: args['footer'], - footerTextFilePaths: footerTextFilePaths, - headerFilePaths: args['header'], - hostedUrl: args['hosted-url'], - includeExternals: args['include-external'], - includeLibraries: args['include'], - includeSource: args['include-source'], - inputDir: inputDir, - packageOrder: args['package-order'].isEmpty - ? args['category-order'] - : args['package-order'], - prettyIndexJson: args['pretty-index-json'], - reexportMinConfidence: - double.parse(args['ambiguous-reexport-scorer-min-confidence']), - relCanonicalPrefix: args['rel-canonical-prefix'], - sdkDir: sdkDir, - sdkVersion: sdk.sdkVersion, - showWarnings: args['show-warnings'], - validateLinks: args['validate-links'], - verboseWarnings: args['verbose-warnings'], - ); - */ - Dartdoc dartdoc = - await Dartdoc.withDefaultGenerators(config, outputDir, packageMeta); + Dartdoc dartdoc = await Dartdoc.withDefaultGenerators(config, outputDir); dartdoc.onCheckProgress.listen(logProgress); await Chain.capture(() async { @@ -229,114 +90,6 @@ main(List arguments) async { } }); } -/* -ArgParser _createArgsParser() { - var parser = new ArgParser(); - parser.addFlag('add-crossdart', - help: 'Add Crossdart links to the source code pieces.', - negatable: false, - defaultsTo: false); - parser.addOption('ambiguous-reexport-scorer-min-confidence', - help: - 'Minimum scorer confidence to suppress warning on ambiguous reexport.', - defaultsTo: '0.1', - hide: true); - parser.addFlag('auto-include-dependencies', - help: - 'Include all the used libraries into the docs, even the ones not in the current package or "include-external"', - negatable: false, - defaultsTo: false); - parser.addMultiOption('category-order', - help: - 'A list of package names to place first when grouping libraries in packages. ' - 'Unmentioned categories are sorted after these. (deprecated, replaced by package-order)', - splitCommas: true); - parser.addOption('example-path-prefix', - help: 'Prefix for @example paths.\n(defaults to the project root)'); - parser.addMultiOption('exclude', - splitCommas: true, help: 'Library names to ignore.'); - parser.addMultiOption('exclude-packages', - splitCommas: true, help: 'Package names to ignore.'); - parser.addOption('favicon', - help: 'A path to a favicon for the generated docs.'); - parser.addMultiOption('footer', - splitCommas: true, help: 'paths to footer files containing HTML text.'); - parser.addMultiOption('footer-text', - splitCommas: true, - help: 'paths to footer-text files ' - '(optional text next to the package name and version).'); - parser.addMultiOption('header', - splitCommas: true, help: 'paths to header files containing HTML text.'); - parser.addFlag('help', - abbr: 'h', negatable: false, help: 'Show command help.'); - parser.addFlag('hide-sdk-text', - help: - 'Drop all text for SDK components. Helpful for integration tests for dartdoc, probably not useful for anything else.', - negatable: true, - defaultsTo: false, - hide: true); - parser.addOption('hosted-url', - help: - 'URL where the docs will be hosted (used to generate the sitemap).'); - parser.addMultiOption('include', - splitCommas: true, help: 'Library names to generate docs for.'); - parser.addMultiOption('include-external', - help: 'Additional (external) dart files to include; use "dir/fileName", ' - 'as in lib/material.dart.'); - parser.addFlag('include-source', - help: 'Show source code blocks.', negatable: true, defaultsTo: true); - parser.addOption('input', help: 'Path to source directory.'); - parser.addFlag('json', - help: 'Prints out progress JSON maps. One entry per line.', - defaultsTo: false, - negatable: true); - parser.addOption('output', - help: 'Path to output directory.', defaultsTo: defaultOutDir); - parser.addMultiOption('package-order', - help: - 'A list of package names to place first when grouping libraries in packages. ' - 'Unmentioned categories are sorted after these.', - splitCommas: true); - parser.addFlag('pretty-index-json', - help: - "Generates `index.json` with indentation and newlines. The file is larger, but it's also easier to diff.", - negatable: false, - defaultsTo: false); - parser.addOption('rel-canonical-prefix', - help: 'If provided, add a rel="canonical" prefixed with provided value. ' - 'Consider using if\nbuilding many versions of the docs for public ' - 'SEO; learn more at https://goo.gl/gktN6F.'); - parser.addFlag('sdk-docs', - help: 'Generate ONLY the docs for the Dart SDK.', negatable: false); - parser.addOption('sdk-readme', - help: 'Path to the SDK description file. Deprecated (ignored)'); - parser.addOption('sdk-dir', - help: 'Path to the SDK directory', - defaultsTo: defaultSdkDir.absolute.path); - parser.addFlag('show-warnings', - help: 'Display warnings.', negatable: false, defaultsTo: false); - parser.addFlag('show-progress', - help: 'Display progress indications to console stdout', negatable: false); - parser.addFlag('use-categories', - help: - 'Group libraries from the same package in the libraries sidebar. (deprecated, ignored)', - negatable: false, - defaultsTo: false); - parser.addFlag('validate-links', - help: - 'Runs the built-in link checker to display Dart context aware warnings for broken links (slow)', - negatable: true, - defaultsTo: true); - parser.addFlag('verbose-warnings', - help: 'Display extra debugging information and help with warnings.', - negatable: true, - defaultsTo: true); - parser.addFlag('version', - help: 'Display the version for $name.', negatable: false); - - return parser; -} -*/ /// Print help if we are passed the help option. void _printHelpAndExit(ArgParser parser, {int exitCode: 0}) { @@ -349,21 +102,3 @@ void _printUsageAndExit(ArgParser parser, {int exitCode: 0}) { print(parser.usage); exit(exitCode); } - -/* -String _resolveTildePath(String originalPath) { - if (originalPath == null || !originalPath.startsWith('~/')) { - return originalPath; - } - - String homeDir; - - if (Platform.isWindows) { - homeDir = pathLib.absolute(Platform.environment['USERPROFILE']); - } else { - homeDir = pathLib.absolute(Platform.environment['HOME']); - } - - return pathLib.join(homeDir, originalPath.substring(2)); -} -*/ diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart index 1c40eec4a0..c6dc24e034 100644 --- a/lib/dartdoc.dart +++ b/lib/dartdoc.dart @@ -3,6 +3,9 @@ // BSD-style license that can be found in the LICENSE file. /// A documentation generator for Dart. +/// +/// Library interface is currently under heavy construction and may change +/// drastically between minor revisions. library dartdoc; import 'dart:async'; @@ -26,7 +29,6 @@ import 'package:html/parser.dart' show parse; import 'package:path/path.dart' as pathLib; import 'package:tuple/tuple.dart'; -export 'package:dartdoc/src/config.dart'; export 'package:dartdoc/src/dartdoc_options.dart'; export 'package:dartdoc/src/element_type.dart'; export 'package:dartdoc/src/generator.dart'; @@ -35,33 +37,7 @@ export 'package:dartdoc/src/package_meta.dart'; const String name = 'dartdoc'; // Update when pubspec version changes. -const String version = '0.18.1'; - -final String defaultOutDir = pathLib.join('doc', 'api'); - -/// Initialize and setup the generators. -Future> _initGenerators(String url, String relCanonicalPrefix, - {List headerFilePaths, - List footerFilePaths, - List footerTextFilePaths, - String faviconPath, - bool prettyIndexJson: false}) async { - var options = new HtmlGeneratorOptions( - url: url, - relCanonicalPrefix: relCanonicalPrefix, - toolVersion: version, - faviconPath: faviconPath, - prettyIndexJson: prettyIndexJson); - - return [ - await HtmlGenerator.create( - options: options, - headers: headerFilePaths, - footers: footerFilePaths, - footerTexts: footerTextFilePaths, - ) - ]; -} +const String dartdocVersion = '0.18.1'; /// Generates Dart documentation for all public Dart libraries in the given /// directory. @@ -74,36 +50,31 @@ class Dartdoc extends PackageBuilder { final StreamController _onCheckProgress = new StreamController(sync: true); - Dartdoc._(DartdocOptionContext config, this.generators, this.outputDir, - PackageMeta packageMeta) - : super(config, packageMeta); + Dartdoc._(DartdocOptionContext config, this.generators, this.outputDir) + : super(config) { + generators.forEach((g) => g.onFileCreated.listen(logProgress)); + } /// An asynchronous factory method that builds Dartdoc's file writers /// and returns a Dartdoc object with them. - static withDefaultGenerators(DartdocOptionContext config, Directory outputDir, - PackageMeta packageMeta) async { - var generators = await _initGenerators( - config.hostedUrl, config.relCanonicalPrefix, - headerFilePaths: config.header, - footerFilePaths: config.footer, - footerTextFilePaths: config.footerTextPaths, - faviconPath: config.favicon, - prettyIndexJson: config.prettyIndexJson); - for (var generator in generators) { - generator.onFileCreated.listen(logProgress); - } - return new Dartdoc._(config, generators, outputDir, packageMeta); + static withDefaultGenerators( + DartdocOptionContext config, Directory outputDir) async { + List generators = + await initGenerators(config as GeneratorContext); + return new Dartdoc._(config, generators, outputDir); } - factory Dartdoc.withoutGenerators(DartdocOptionContext config, - Directory outputDir, PackageMeta packageMeta) { - return new Dartdoc._(config, [], outputDir, packageMeta); + /// Basic synchronous factory that gives a stripped down Dartdoc that won't + /// use generators. Useful for testing. + factory Dartdoc.withoutGenerators( + DartdocOptionContext config, Directory outputDir) { + return new Dartdoc._(config, [], outputDir); } Stream get onCheckProgress => _onCheckProgress.stream; @override - logAnalysisErrors(Set sources) async { + void logAnalysisErrors(Set sources) async { List errorInfos = []; // TODO(jcollins-g): figure out why sources can't contain includeExternals // or embedded SDK components without having spurious(?) analysis errors. @@ -115,7 +86,7 @@ class Dartdoc extends PackageBuilder { List<_Error> errors = [info] .expand((AnalysisErrorInfo info) { return info.errors.map((error) => - new _Error(error, info.lineInfo, packageMeta.dir.path)); + new _Error(error, info.lineInfo, config.packageMeta.dir.path)); }) .where((_Error error) => error.isError) .toList() @@ -133,7 +104,7 @@ class Dartdoc extends PackageBuilder { List<_Error> errors = errorInfos .expand((AnalysisErrorInfo info) { return info.errors.map((error) => - new _Error(error, info.lineInfo, packageMeta.dir.path)); + new _Error(error, info.lineInfo, config.packageMeta.dir.path)); }) .where((_Error error) => error.isError) // TODO(jcollins-g): remove after conversion to analysis driver @@ -201,7 +172,7 @@ class Dartdoc extends PackageBuilder { throw new DartdocFailure("dartdoc encountered errors while processing"); } - return new DartdocResults(packageMeta, packageGraph, outputDir); + return new DartdocResults(config.packageMeta, packageGraph, outputDir); } /// Warn on file paths. diff --git a/lib/src/config.dart b/lib/src/config.dart deleted file mode 100644 index c57f24dd6b..0000000000 --- a/lib/src/config.dart +++ /dev/null @@ -1,169 +0,0 @@ -// 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. - -/// Legacy dartdoc configuration library. TODO(jcollins-g): merge with [DartdocOption]. -library dartdoc.config; - -import 'dart:io'; - -import 'package:dartdoc/dartdoc.dart'; -import 'package:path/path.dart' as pathLib; -/* -String _resolveTildePath(String originalPath) { - if (originalPath == null || !originalPath.startsWith('~/')) { - return originalPath; - } - - String homeDir; - - if (Platform.isWindows) { - homeDir = pathLib.absolute(Platform.environment['USERPROFILE']); - } else { - homeDir = pathLib.absolute(Platform.environment['HOME']); - } - - return pathLib.join(homeDir, originalPath.substring(2)); -} - -class DartdocConfig { - final bool addCrossdart; - final bool autoIncludeDependencies; - final List dropTextFrom; - final List excludeLibraries; - final List excludePackages; - final String examplePathPrefix; - List footerFilePaths; - List footerTextFilePaths; - List headerFilePaths; - final String faviconPath; - final List includeExternals; - final List includeLibraries; - final String hostedUrl; - final bool includeSource; - final Directory inputDir; - final List packageOrder; - final bool prettyIndexJson; - final double reexportMinConfidence; - final String relCanonicalPrefix; - final Directory sdkDir; - final String sdkVersion; - final bool showWarnings; - final bool validateLinks; - final bool verboseWarnings; - DartdocConfig._( - this.addCrossdart, - this.autoIncludeDependencies, - this.dropTextFrom, - this.examplePathPrefix, - this.excludeLibraries, - this.excludePackages, - this.faviconPath, - this.footerFilePaths, - this.footerTextFilePaths, - this.headerFilePaths, - this.hostedUrl, - this.includeExternals, - this.includeLibraries, - this.includeSource, - this.inputDir, - this.packageOrder, - this.prettyIndexJson, - this.reexportMinConfidence, - this.relCanonicalPrefix, - this.sdkDir, - this.sdkVersion, - this.showWarnings, - this.validateLinks, - this.verboseWarnings, - ) { - if (sdkDir == null || !sdkDir.existsSync()) { - throw new DartdocFailure("Error: unable to locate the Dart SDK."); - } - - footerFilePaths = footerFilePaths.map((p) => _resolveTildePath(p)).toList(); - for (String footerFilePath in footerFilePaths) { - if (!new File(footerFilePath).existsSync()) { - throw new DartdocFailure( - "fatal error: unable to locate footer file: ${footerFilePath}."); - } - } - - footerTextFilePaths = - footerTextFilePaths.map((p) => _resolveTildePath(p)).toList(); - for (String footerTextFilePath in footerTextFilePaths) { - if (!new File(footerTextFilePath).existsSync()) { - throw new DartdocFailure( - "fatal error: unable to locate footer-text file: ${footerTextFilePath}."); - } - } - - headerFilePaths = headerFilePaths.map((p) => _resolveTildePath(p)).toList(); - for (String headerFilePath in headerFilePaths) { - if (!new File(headerFilePath).existsSync()) { - throw new DartdocFailure( - "fatal error: unable to locate header file: ${headerFilePath}."); - } - } - } - - factory DartdocConfig.fromParameters({ - bool addCrossdart: false, - bool autoIncludeDependencies: false, - List dropTextFrom, - String examplePathPrefix, - List excludeLibraries, - List excludePackages, - String faviconPath, - List footerFilePaths, - List footerTextFilePaths, - List headerFilePaths, - String hostedUrl, - List includeExternals, - List includeLibraries, - bool includeSource: true, - Directory inputDir, - List packageOrder, - bool prettyIndexJson: false, - double reexportMinConfidence: 0.1, - String relCanonicalPrefix, - Directory sdkDir, - String sdkVersion, - bool showWarnings: false, - bool validateLinks: true, - bool verboseWarnings: true, - }) { - return new DartdocConfig._( - addCrossdart, - autoIncludeDependencies, - dropTextFrom ?? const [], - examplePathPrefix, - excludeLibraries ?? const [], - excludePackages ?? const [], - faviconPath, - footerFilePaths ?? const [], - footerTextFilePaths ?? const [], - headerFilePaths ?? const [], - hostedUrl, - includeExternals ?? const [], - includeLibraries ?? const [], - includeSource, - inputDir, - packageOrder ?? const [], - prettyIndexJson, - reexportMinConfidence, - relCanonicalPrefix, - sdkDir ?? defaultSdkDir, - sdkVersion, - showWarnings, - validateLinks, - verboseWarnings, - ); - } - - bool isLibraryExcluded(String name) => - excludeLibraries.any((pattern) => name == pattern); - bool isPackageExcluded(String name) => - excludePackages.any((pattern) => name == pattern); -} -*/ diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart index 04117fd5d1..91a5a1f087 100644 --- a/lib/src/dartdoc_options.dart +++ b/lib/src/dartdoc_options.dart @@ -16,14 +16,10 @@ library dartdoc.dartdoc_options; import 'dart:async'; import 'dart:io'; -import 'dart:isolate'; import 'package:analyzer/dart/element/element.dart'; -import 'package:analyzer/file_system/physical_file_system.dart'; -import 'package:analyzer/src/dart/sdk/sdk.dart'; import 'package:args/args.dart'; import 'package:dartdoc/dartdoc.dart'; -import 'package:dartdoc/src/logging.dart'; import 'package:path/path.dart' as pathLib; import 'package:yaml/yaml.dart'; @@ -36,14 +32,6 @@ const int _kIntVal = 0; const double _kDoubleVal = 0.0; const bool _kBoolVal = true; -Uri _sdkFooterCopyrightUri; -Future _setSdkFooterCopyrightUri() async { - if (_sdkFooterCopyrightUri == null) { - _sdkFooterCopyrightUri = await Isolate.resolvePackageUri( - Uri.parse('package:dartdoc/resources/sdk_footer_text.html')); - } -} - String _resolveTildePath(String originalPath) { if (originalPath == null || !originalPath.startsWith('~/')) { return originalPath; @@ -347,11 +335,28 @@ class DartdocOptionSynthetic extends DartdocOption { } } +typedef Future> OptionGenerator(); + /// A [DartdocOption] that only contains other [DartdocOption]s and is not an option itself. class DartdocOptionSet extends DartdocOption { DartdocOptionSet(String name) : super._(name, null, null, false, false, false); + /// Asynchronous factory that is the main entry point to initialize Dartdoc + /// options for use. + /// + /// [name] is the top level key for the option set. + /// [optionGenerators] is a sequence of asynchronous functions that return + /// [DartdocOption]s that will be added to the new option set. + static Future fromOptionGenerators( + String name, Iterable optionGenerators) async { + DartdocOptionSet optionSet = new DartdocOptionSet(name); + for (OptionGenerator generator in optionGenerators) { + optionSet.addAll(await generator()); + } + return optionSet; + } + /// [DartdocOptionSet] always has the null value. @override Null valueAt(Directory dir) => null; @@ -784,22 +789,14 @@ class DartdocOptionContext { final DartdocOptionSet optionSet; Directory context; + // TODO(jcollins-g): Allow passing in structured data to initialize a + // [DartdocOptionContext]'s arguments instead of having to parse strings + // via optionSet. DartdocOptionContext(this.optionSet, FileSystemEntity entity) { context = new Directory(pathLib .canonicalize(entity is File ? entity.parent.path : entity.path)); } - // TODO(jcollins-g): Allow passing in structured data to initialize a - // [DartdocOptionContext]'s arguments - - /// Convenience factory to build a [DartdocOptionSet] and associate it with a - /// [DartdocOptionContext] based on the current working directory. - static fromArgv(List argv) async { - DartdocOptionSet optionSet = await createDartdocOptions(); - optionSet.parseArguments(argv); - return new DartdocOptionContext(optionSet, Directory.current); - } - /// Build a DartdocOptionContext from an analyzer element (using its source /// location). factory DartdocOptionContext.fromElement( @@ -834,32 +831,20 @@ class DartdocOptionContext { List get exclude => optionSet['exclude'].valueAt(context); List get excludePackages => optionSet['excludePackages'].valueAt(context); - String get favicon => optionSet['favicon'].valueAt(context); - List get footer => optionSet['footer'].valueAt(context); - - /// _footerText is only used to construct synthetic options. - List get _footerText => - optionSet['footerText'].valueAt(context); // ignore: unused_element - List get footerTextPaths => - optionSet['footerTextPaths'].valueAt(context); - List get header => optionSet['header'].valueAt(context); + bool get hideSdkText => optionSet['hideSdkText'].valueAt(context); - String get hostedUrl => optionSet['hostedUrl'].valueAt(context); List get include => optionSet['include'].valueAt(context); List get includeExternal => optionSet['includeExternal'].valueAt(context); bool get includeSource => optionSet['includeSource'].valueAt(context); /// _input is only used to construct synthetic options. - String get _input => - optionSet['input'].valueAt(context); // ignore: unused_element + // ignore: unused_element + String get _input => optionSet['input'].valueAt(context); String get inputDir => optionSet['inputDir'].valueAt(context); String get output => optionSet['output'].valueAt(context); List get packageOrder => optionSet['packageOrder'].valueAt(context); PackageMeta get packageMeta => optionSet['packageMeta'].valueAt(context); - bool get prettyIndexJson => optionSet['prettyIndexJson'].valueAt(context); - String get relCanonicalPrefix => - optionSet['relCanonicalPrefix'].valueAt(context); bool get sdkDocs => optionSet['sdkDocs'].valueAt(context); String get sdkDir => optionSet['sdkDir'].valueAt(context); bool get showWarnings => optionSet['showWarnings'].valueAt(context); @@ -875,256 +860,117 @@ class DartdocOptionContext { /// Instantiate dartdoc's configuration file and options parser with the /// given command line arguments. -Future createDartdocOptions() async { - await (_setSdkFooterCopyrightUri()); - // Sync with DartdocOptionContext. - return new DartdocOptionSet('dartdoc') - ..addAll([ - new DartdocOptionArgOnly('addCrossdart', false, - help: 'Add Crossdart links to the source code pieces.', - negatable: true), - new DartdocOptionBoth('ambiguousReexportScorerMinConfidence', 0.1, - help: - 'Minimum scorer confidence to suppress warning on ambiguous reexport.'), - new DartdocOptionArgOnly('autoIncludeDependencies', false, - help: - 'Include all the used libraries into the docs, even the ones not in the current package or "include-external"', - negatable: true), - new DartdocOptionBoth>('categoryOrder', [], - help: - "A list of categories (not package names) to place first when grouping symbols on dartdoc's sidebar. " - 'Unmentioned categories are sorted after these.'), - new DartdocOptionSynthetic>('dropTextFrom', - (DartdocOptionSynthetic option, Directory dir) { - if (option.parent['hideSdkText'].valueAt(dir)) { - return [ - 'dart.async', - 'dart.collection', - 'dart.convert', - 'dart.core', - 'dart.developer', - 'dart.html', - 'dart.indexed_db', - 'dart.io', - 'dart.lisolate', - 'dart.js', - 'dart.js_util', - 'dart.math', - 'dart.mirrors', - 'dart.svg', - 'dart.typed_data', - 'dart.web_audio' - ]; - } - return []; - }, help: 'Remove text from libraries with the following names.'), - new DartdocOptionBoth('examplePathPrefix', null, - isDir: true, - help: 'Prefix for @example paths.\n(defaults to the project root)', - mustExist: true), - new DartdocOptionBoth>('exclude', [], - help: 'Library names to ignore.', splitCommas: true), - new DartdocOptionBoth>('excludePackages', [], - help: 'Package names to ignore.', splitCommas: true), - new DartdocOptionBoth('favicon', null, - isFile: true, - help: 'A path to a favicon for the generated docs.', - mustExist: true), - new DartdocOptionBoth>('footer', [], - isFile: true, - help: 'paths to footer files containing HTML text.', - mustExist: true, - splitCommas: true), - new DartdocOptionBoth>('footerText', [], - isFile: true, - help: - 'paths to footer-text files (optional text next to the package name ' - 'and version).', - mustExist: true, - splitCommas: true), - new DartdocOptionSynthetic>('footerTextPaths', - (DartdocOptionSynthetic option, Directory dir) { - List footerTextPaths = []; - // TODO(jcollins-g): Eliminate special casing for SDK and use config file. - if (new PackageMeta.fromDir(dir).isSdk) { - footerTextPaths.add(_sdkFooterCopyrightUri.toFilePath()); - } - footerTextPaths.addAll(option.parent['footerText'].valueAt(dir)); - return footerTextPaths; - }), - new DartdocOptionBoth>('header', [], - isFile: true, - help: 'paths to header files containing HTML text.', - splitCommas: true), - new DartdocOptionArgOnly('hideSdkText', false, - hide: true, - help: - 'Drop all text for SDK components. Helpful for integration tests for dartdoc, probably not useful for anything else.', - negatable: true), - new DartdocOptionArgOnly('hostedUrl', null, - help: - 'URL where the docs will be hosted (used to generate the sitemap).'), - new DartdocOptionBoth>('include', [], - help: 'Library names to generate docs for.', splitCommas: true), - new DartdocOptionBoth>('includeExternal', null, - isFile: true, - help: - 'Additional (external) dart files to include; use "dir/fileName", ' - 'as in lib/material.dart.', - mustExist: true, - splitCommas: true), - new DartdocOptionBoth('includeSource', true, - help: 'Show source code blocks.', negatable: true), - new DartdocOptionArgOnly('input', Directory.current.path, - isDir: true, help: 'Path to source directory', mustExist: true), - new DartdocOptionSynthetic('inputDir', - (DartdocOptionSynthetic option, Directory dir) { - if (option.parent['sdkDocs'].valueAt(dir)) { - return option.parent['sdkDir'].valueAt(dir); - } - return option.parent['input'].valueAt(dir); - }, - help: 'Path to source directory (with override if --sdk-dir)', - isDir: true, - mustExist: true), - new DartdocOptionArgOnly('output', defaultOutDir, - isDir: true, help: 'Path to output directory.'), - new DartdocOptionSynthetic('packageMeta', - (DartdocOptionSynthetic option, Directory dir) { - PackageMeta packageMeta = new PackageMeta.fromDir( - new Directory(option.parent['inputDir'].valueAt(dir))); - if (packageMeta == null) { - throw new DartdocOptionError( - 'Unable to generate documentation: no package found'); - } - if (!packageMeta.isValid) { - final String firstError = packageMeta.getInvalidReasons().first; - throw new DartdocOptionError('Package is invalid: $firstError'); - } - return packageMeta; - }, help: 'PackageMeta object for the default package.'), - new DartdocOptionBoth>('packageOrder', [], - help: - 'A list of package names to place first when grouping libraries in packages. ' - 'Unmentioned categories are sorted after these.'), - new DartdocOptionArgOnly('prettyIndexJson', false, - help: - "Generates `index.json` with indentation and newlines. The file is larger, but it's also easier to diff.", - negatable: false), - new DartdocOptionArgOnly('relCanonicalPrefix', null, - help: - 'If provided, add a rel="canonical" prefixed with provided value. ' - 'Consider using if\nbuilding many versions of the docs for public ' - 'SEO; learn more at https://goo.gl/gktN6F.'), - new DartdocOptionArgOnly('sdkDocs', false, - help: 'Generate ONLY the docs for the Dart SDK.', negatable: false), - new DartdocOptionArgOnly('sdkDir', defaultSdkDir.absolute.path, - help: 'Path to the SDK directory', isDir: true, mustExist: true), - new DartdocOptionArgOnly('showWarnings', false, - help: 'Display all warnings.', negatable: false), - new DartdocOptionArgOnly('useCategories', true, - help: 'Display categories in the sidebar of packages', - negatable: false), - new DartdocOptionArgOnly('validateLinks', true, - help: - 'Runs the built-in link checker to display Dart context aware warnings for broken links (slow)', - negatable: true), - new DartdocOptionArgOnly('verboseWarnings', true, - help: 'Display extra debugging information and help with warnings.', - negatable: true), - ]); -} -/* -final Map _dartdocOptionsCache = {}; - -/// Legacy dartdoc options class. TODO(jcollins-g): merge with [DartdocOption]. -abstract class DartdocOptions { - DartdocOptions(); - - /// Path to the dartdoc options file, or '' if this object is the - /// default setting. Intended for printing only. - String get _path; - - /// A list indicating the preferred subcategory sorting order. - List get categoryOrder; - - factory DartdocOptions.fromDir(Directory dir) { - if (!_dartdocOptionsCache.containsKey(dir.absolute.path)) { - _dartdocOptionsCache[dir.absolute.path] = - new DartdocOptions._fromDir(dir); - } - return _dartdocOptionsCache[dir.absolute.path]; - } - - /// Search for a dartdoc_options file in this and parent directories. - factory DartdocOptions._fromDir(Directory dir) { - if (!dir.existsSync()) return new _DefaultDartdocOptions(); - - File f; - dir = dir.absolute; - - while (true) { - f = new File(pathLib.join(dir.path, 'dartdoc_options.yaml')); - if (f.existsSync() || dir.parent.path == dir.path) break; - dir = dir.parent.absolute; - } - - DartdocOptions parent; - if (dir.parent.path != dir.path) { - parent = new DartdocOptions.fromDir(dir.parent); - } else { - parent = new _DefaultDartdocOptions(); - } - if (f.existsSync()) { - return new _FileDartdocOptions(f); - } - return parent; - } -} - -class _DefaultDartdocOptions extends DartdocOptions { - _DefaultDartdocOptions() : super(); - - @override - String get _path => ''; - - @override - List get categoryOrder => new List.unmodifiable([]); -} - -class _FileDartdocOptions extends DartdocOptions { - File dartdocOptionsFile; - Map _dartdocOptions; - _FileDartdocOptions(this.dartdocOptionsFile) : super() { - Map allDartdocOptions = loadYaml(dartdocOptionsFile.readAsStringSync()); - if (allDartdocOptions.containsKey('dartdoc')) { - _dartdocOptions = allDartdocOptions['dartdoc']; - } else { - _dartdocOptions = {}; - logWarning("${_path}: must contain 'dartdoc' section"); - } - } - - @override - String get _path => dartdocOptionsFile.path; - - List _categoryOrder; - @override - List get categoryOrder { - if (_categoryOrder == null) { - _categoryOrder = []; - if (_dartdocOptions.containsKey('categoryOrder')) { - if (_dartdocOptions['categoryOrder'] is YamlList) { - _categoryOrder.addAll(_dartdocOptions['categoryOrder'] - .map((c) => c.toString()) - .cast()); - } else { - logWarning('${_path}: categoryOrder must be a list (ignoring)'); - } +Future> createDartdocOptions() async { + return [ + new DartdocOptionArgOnly('addCrossdart', false, + help: 'Add Crossdart links to the source code pieces.', + negatable: true), + new DartdocOptionBoth('ambiguousReexportScorerMinConfidence', 0.1, + help: + 'Minimum scorer confidence to suppress warning on ambiguous reexport.'), + new DartdocOptionArgOnly('autoIncludeDependencies', false, + help: + 'Include all the used libraries into the docs, even the ones not in the current package or "include-external"', + negatable: true), + new DartdocOptionBoth>('categoryOrder', [], + help: + "A list of categories (not package names) to place first when grouping symbols on dartdoc's sidebar. " + 'Unmentioned categories are sorted after these.'), + new DartdocOptionSynthetic>('dropTextFrom', + (DartdocOptionSynthetic option, Directory dir) { + if (option.parent['hideSdkText'].valueAt(dir)) { + return [ + 'dart.async', + 'dart.collection', + 'dart.convert', + 'dart.core', + 'dart.developer', + 'dart.html', + 'dart.indexed_db', + 'dart.io', + 'dart.lisolate', + 'dart.js', + 'dart.js_util', + 'dart.math', + 'dart.mirrors', + 'dart.svg', + 'dart.typed_data', + 'dart.web_audio' + ]; } - _categoryOrder = new List.unmodifiable(_categoryOrder); - } - return _categoryOrder; - } + return []; + }, help: 'Remove text from libraries with the following names.'), + new DartdocOptionBoth('examplePathPrefix', null, + isDir: true, + help: 'Prefix for @example paths.\n(defaults to the project root)', + mustExist: true), + new DartdocOptionBoth>('exclude', [], + help: 'Library names to ignore.', splitCommas: true), + new DartdocOptionArgOnly>('excludePackages', [], + help: 'Package names to ignore.', splitCommas: true), + new DartdocOptionArgOnly('hideSdkText', false, + hide: true, + help: + 'Drop all text for SDK components. Helpful for integration tests for dartdoc, probably not useful for anything else.', + negatable: true), + new DartdocOptionBoth>('include', [], + help: 'Library names to generate docs for.', splitCommas: true), + new DartdocOptionBoth>('includeExternal', null, + isFile: true, + help: + 'Additional (external) dart files to include; use "dir/fileName", ' + 'as in lib/material.dart.', + mustExist: true, + splitCommas: true), + new DartdocOptionArgOnly('includeSource', true, + help: 'Show source code blocks.', negatable: true), + new DartdocOptionArgOnly('input', Directory.current.path, + isDir: true, help: 'Path to source directory', mustExist: true), + new DartdocOptionSynthetic('inputDir', + (DartdocOptionSynthetic option, Directory dir) { + if (option.parent['sdkDocs'].valueAt(dir)) { + return option.parent['sdkDir'].valueAt(dir); + } + return option.parent['input'].valueAt(dir); + }, + help: 'Path to source directory (with override if --sdk-docs)', + isDir: true, + mustExist: true), + new DartdocOptionArgOnly('output', pathLib.join('doc', 'api'), + isDir: true, help: 'Path to output directory.'), + new DartdocOptionSynthetic('packageMeta', + (DartdocOptionSynthetic option, Directory dir) { + PackageMeta packageMeta = new PackageMeta.fromDir( + new Directory(option.parent['inputDir'].valueAt(dir))); + if (packageMeta == null) { + throw new DartdocOptionError( + 'Unable to generate documentation: no package found'); + } + if (!packageMeta.isValid) { + final String firstError = packageMeta.getInvalidReasons().first; + throw new DartdocOptionError('Package is invalid: $firstError'); + } + return packageMeta; + }, help: 'PackageMeta object for the default package.'), + new DartdocOptionArgOnly>('packageOrder', [], + help: + 'A list of package names to place first when grouping libraries in packages. ' + 'Unmentioned categories are sorted after these.'), + new DartdocOptionArgOnly('sdkDocs', false, + help: 'Generate ONLY the docs for the Dart SDK.', negatable: false), + new DartdocOptionArgOnly('sdkDir', defaultSdkDir.absolute.path, + help: 'Path to the SDK directory', isDir: true, mustExist: true), + new DartdocOptionArgOnly('showWarnings', false, + help: 'Display all warnings.', negatable: false), + new DartdocOptionArgOnly('useCategories', true, + help: 'Display categories in the sidebar of packages', + negatable: false), + new DartdocOptionArgOnly('validateLinks', true, + help: + 'Runs the built-in link checker to display Dart context aware warnings for broken links (slow)', + negatable: true), + new DartdocOptionArgOnly('verboseWarnings', true, + help: 'Display extra debugging information and help with warnings.', + negatable: true), + ]; } -*/ diff --git a/lib/src/html/html_generator.dart b/lib/src/html/html_generator.dart index 2e3de78738..1210cf4da6 100644 --- a/lib/src/html/html_generator.dart +++ b/lib/src/html/html_generator.dart @@ -5,8 +5,10 @@ library dartdoc.html_generator; import 'dart:async' show Future, StreamController, Stream; -import 'dart:io' show File; +import 'dart:io' show Directory, File; +import 'dart:isolate'; +import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/generator.dart'; import 'package:dartdoc/src/html/html_generator_instance.dart'; import 'package:dartdoc/src/html/template_data.dart'; @@ -128,3 +130,96 @@ class HtmlGeneratorOptions implements HtmlOptions { this.prettyIndexJson: false}) : this.toolVersion = toolVersion ?? 'unknown'; } + +/// Initialize and setup the generators. +Future> initGenerators(GeneratorContext config) async { + // TODO(jcollins-g): Rationalize based on GeneratorContext all the way down + // through the generators. + HtmlGeneratorOptions options = new HtmlGeneratorOptions( + url: config.hostedUrl, + relCanonicalPrefix: config.relCanonicalPrefix, + toolVersion: dartdocVersion, + faviconPath: config.favicon, + prettyIndexJson: config.prettyIndexJson); + + return [ + await HtmlGenerator.create( + options: options, + headers: config.header, + footers: config.footer, + footerTexts: config.footerTextPaths, + ) + ]; +} + +Uri _sdkFooterCopyrightUri; +Future _setSdkFooterCopyrightUri() async { + if (_sdkFooterCopyrightUri == null) { + _sdkFooterCopyrightUri = await Isolate.resolvePackageUri( + Uri.parse('package:dartdoc/resources/sdk_footer_text.html')); + } +} + +abstract class GeneratorContext implements DartdocOptionContext { + String get favicon => optionSet['favicon'].valueAt(context); + List get footer => optionSet['footer'].valueAt(context); + + /// _footerText is only used to construct synthetic options. + // ignore: unused_element + List get _footerText => optionSet['footerText'].valueAt(context); + List get footerTextPaths => + optionSet['footerTextPaths'].valueAt(context); + List get header => optionSet['header'].valueAt(context); + String get hostedUrl => optionSet['hostedUrl'].valueAt(context); + bool get prettyIndexJson => optionSet['prettyIndexJson'].valueAt(context); + String get relCanonicalPrefix => + optionSet['relCanonicalPrefix'].valueAt(context); +} + +Future> createGeneratorOptions() async { + await _setSdkFooterCopyrightUri(); + return [ + new DartdocOptionBoth('favicon', null, + isFile: true, + help: 'A path to a favicon for the generated docs.', + mustExist: true), + new DartdocOptionBoth>('footer', [], + isFile: true, + help: 'paths to footer files containing HTML text.', + mustExist: true, + splitCommas: true), + new DartdocOptionBoth>('footerText', [], + isFile: true, + help: + 'paths to footer-text files (optional text next to the package name ' + 'and version).', + mustExist: true, + splitCommas: true), + new DartdocOptionSynthetic>('footerTextPaths', + (DartdocOptionSynthetic option, Directory dir) { + List footerTextPaths = []; + // TODO(jcollins-g): Eliminate special casing for SDK and use config file. + if (new PackageMeta.fromDir(dir).isSdk) { + footerTextPaths.add(_sdkFooterCopyrightUri.toFilePath()); + } + footerTextPaths.addAll(option.parent['footerText'].valueAt(dir)); + return footerTextPaths; + }), + new DartdocOptionBoth>('header', [], + isFile: true, + help: 'paths to header files containing HTML text.', + splitCommas: true), + new DartdocOptionArgOnly('hostedUrl', null, + help: + 'URL where the docs will be hosted (used to generate the sitemap).'), + new DartdocOptionArgOnly('prettyIndexJson', false, + help: + "Generates `index.json` with indentation and newlines. The file is larger, but it's also easier to diff.", + negatable: false), + new DartdocOptionArgOnly('relCanonicalPrefix', null, + help: + 'If provided, add a rel="canonical" prefixed with provided value. ' + 'Consider using if\nbuilding many versions of the docs for public ' + 'SEO; learn more at https://goo.gl/gktN6F.'), + ]; +} diff --git a/lib/src/logging.dart b/lib/src/logging.dart index 3f9b39a121..103be7e85c 100644 --- a/lib/src/logging.dart +++ b/lib/src/logging.dart @@ -1,3 +1,8 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +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 // BSD-style license that can be found in the LICENSE file. @@ -42,3 +47,82 @@ abstract class Jsonable { @override String toString() => text; } + +void startLogging(LoggingContext config) { + // By default, get all log output at `progressLevel` or greater. + // This allows us to capture progress events and print `...`. + Logger.root.level = progressLevel; + if (config.json) { + Logger.root.onRecord.listen((record) { + if (record.level == progressLevel) { + return; + } + + var output = {'level': record.level.name}; + + if (record.object is Jsonable) { + output['data'] = record.object; + } else { + output['message'] = record.message; + } + + print(json.encode(output)); + }); + } else { + final stopwatch = new Stopwatch()..start(); + + // Used to track if we're printing `...` to show progress. + // Allows unified new-line tracking + var writingProgress = false; + + Logger.root.onRecord.listen((record) { + if (record.level == progressLevel) { + if (config.showProgress && stopwatch.elapsed.inMilliseconds > 250) { + writingProgress = true; + stdout.write('.'); + stopwatch.reset(); + } + return; + } + + stopwatch.reset(); + if (writingProgress) { + // print a new line after progress dots... + print(''); + writingProgress = false; + } + var message = record.message; + assert(message == message.trimRight()); + assert(message.isNotEmpty); + + if (record.level < Level.WARNING) { + 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); + } + } else { + stderr.writeln(message); + } + }); + } +} + +abstract class LoggingContext implements DartdocOptionContext { + bool get json => optionSet['json'].valueAt(context); + bool get showProgress => optionSet['showProgress'].valueAt(context); +} + +Future> createLoggingOptions() async { + return [ + new DartdocOptionArgOnly('json', false, + help: 'Prints out progress JSON maps. One entry per line.', + negatable: true), + new DartdocOptionArgOnly('showProgress', false, + help: 'Display progress indications to console stdout', + negatable: false), + ]; +} diff --git a/lib/src/model.dart b/lib/src/model.dart index 0b5bf760e4..726caf590a 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -35,7 +35,6 @@ import 'package:analyzer/src/dart/element/member.dart' show ExecutableMember, Member, ParameterMember; import 'package:analyzer/src/dart/analysis/driver.dart'; import 'package:collection/collection.dart'; -import 'package:dartdoc/src/config.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/element_type.dart'; import 'package:dartdoc/src/io_utils.dart'; @@ -921,10 +920,10 @@ class Class extends ModelElement List get _inheritedElements { if (__inheritedElements == null) { __inheritedElements = []; - Map cmap = - definingLibrary.inheritanceManager.getMembersInheritedFromClasses(element); - Map imap = - definingLibrary.inheritanceManager.getMembersInheritedFromInterfaces(element); + Map cmap = definingLibrary.inheritanceManager + .getMembersInheritedFromClasses(element); + Map imap = definingLibrary.inheritanceManager + .getMembersInheritedFromInterfaces(element); __inheritedElements.addAll(cmap.values); __inheritedElements .addAll(imap.values.where((e) => !cmap.containsKey(e.name))); @@ -5245,17 +5244,20 @@ class TypeParameter extends ModelElement { /// Everything you need to instantiate a PackageGraph object for documenting. class PackageBuilder { - final PackageMeta packageMeta; final DartdocOptionContext config; - PackageBuilder(this.config, this.packageMeta); + PackageBuilder(this.config); void logAnalysisErrors(Set sources) {} Future buildPackageGraph() async { + PackageMeta packageMeta = config.packageMeta; + if (packageMeta.needsPubGet) { + packageMeta.runPubGet(); + } Set libraries = await getLibraries(getFiles); - return new PackageGraph( - libraries, config, packageMeta, getWarningOptions(), driver, sdk); + return new PackageGraph(libraries, config, config.packageMeta, + getWarningOptions(), driver, sdk); } DartSdk _sdk; @@ -5269,7 +5271,7 @@ class PackageBuilder { EmbedderSdk _embedderSdk; EmbedderSdk get embedderSdk { - if (_embedderSdk == null && packageMeta.isSdk == false) { + if (_embedderSdk == null && config.packageMeta.isSdk == false) { _embedderSdk = new EmbedderSdk(PhysicalResourceProvider.INSTANCE, new EmbedderYamlLocator(packageMap).embedderYamls); } @@ -5537,13 +5539,14 @@ class PackageBuilder { Set get getFiles { Set files = new Set(); - files.addAll(packageMeta.isSdk + files.addAll(config.packageMeta.isSdk ? new Set() : findFilesToDocumentInPackage( config.inputDir, config.autoIncludeDependencies)); - if (packageMeta.isSdk) { + if (config.packageMeta.isSdk) { files.addAll(getSdkFilesToDocument()); - } else if (embedderSdk.urlMappings.isNotEmpty && !packageMeta.isSdk) { + } else if (embedderSdk.urlMappings.isNotEmpty && + !config.packageMeta.isSdk) { embedderSdk.urlMappings.keys.forEach((String dartUri) { Source source = embedderSdk.mapDartUri(dartUri); files.add(source.fullName); diff --git a/lib/src/package_meta.dart b/lib/src/package_meta.dart index 17e9351036..0d749afe55 100644 --- a/lib/src/package_meta.dart +++ b/lib/src/package_meta.dart @@ -220,7 +220,7 @@ class _FilePackageMeta extends PackageMeta { StringBuffer buf = new StringBuffer(); buf.writeln('${result.stdout}'); buf.writeln('${result.stderr}'); - throw buf.toString().trim(); + throw DartdocFailure('pub get failed: ${buf.toString().trim()}'); } } diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart index eba3e7b502..48d69bb7c2 100644 --- a/test/dartdoc_test.dart +++ b/test/dartdoc_test.dart @@ -15,7 +15,7 @@ import 'package:test/test.dart'; import 'src/utils.dart'; void main() { - group('dartdoc', () { + group('dartdoc without generators', () { Directory tempDir; setUp(() { @@ -28,11 +28,8 @@ void main() { test('generate docs for ${pathLib.basename(testPackageDir.path)} works', () async { - PackageMeta meta = new PackageMeta.fromDir(testPackageDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - await DartdocOptionContext.fromArgv(['--input', testPackageDir.path]), - tempDir, - meta); + await contextFromArgv(['--input', testPackageDir.path]), tempDir); DartdocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); @@ -46,12 +43,8 @@ void main() { test('generate docs for ${pathLib.basename(testPackageBadDir.path)} fails', () async { - PackageMeta meta = new PackageMeta.fromDir(testPackageBadDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - await DartdocOptionContext - .fromArgv(['--input', testPackageBadDir.path]), - tempDir, - meta); + await contextFromArgv(['--input', testPackageBadDir.path]), tempDir); try { await dartdoc.generateDocs(); @@ -62,12 +55,9 @@ void main() { }); test('generate docs for a package that does not have a readme', () async { - PackageMeta meta = new PackageMeta.fromDir(testPackageWithNoReadme); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - await DartdocOptionContext - .fromArgv(['--input', testPackageWithNoReadme.path]), - tempDir, - meta); + await contextFromArgv(['--input', testPackageWithNoReadme.path]), + tempDir); DartdocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); @@ -80,12 +70,10 @@ void main() { }); test('generate docs including a single library', () async { - PackageMeta meta = new PackageMeta.fromDir(testPackageDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - await DartdocOptionContext - .fromArgv(['--input', testPackageDir.path, '--include', 'fake']), - tempDir, - meta); + await contextFromArgv( + ['--input', testPackageDir.path, '--include', 'fake']), + tempDir); DartdocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); @@ -98,12 +86,10 @@ void main() { }); test('generate docs excluding a single library', () async { - PackageMeta meta = new PackageMeta.fromDir(testPackageDir); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - await DartdocOptionContext - .fromArgv(['--input', testPackageDir.path, '--exclude', 'fake']), - tempDir, - meta); + await contextFromArgv( + ['--input', testPackageDir.path, '--exclude', 'fake']), + tempDir); DartdocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); @@ -120,10 +106,8 @@ void main() { PackageMeta meta = new PackageMeta.fromDir(testPackageWithEmbedderYaml); if (meta.needsPubGet) meta.runPubGet(); Dartdoc dartdoc = new Dartdoc.withoutGenerators( - await DartdocOptionContext - .fromArgv(['--input', testPackageWithEmbedderYaml.path]), - tempDir, - meta); + await contextFromArgv(['--input', testPackageWithEmbedderYaml.path]), + tempDir); DartdocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); diff --git a/test/src/utils.dart b/test/src/utils.dart index 11286eb4c7..e66c1e4ac1 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -8,7 +8,6 @@ import 'dart:async'; import 'dart:io'; import 'package:dartdoc/dartdoc.dart'; -import 'package:dartdoc/src/config.dart'; import 'package:dartdoc/src/model.dart'; import 'package:dartdoc/src/package_meta.dart'; import 'package:path/path.dart' as pathLib; @@ -27,6 +26,15 @@ final Directory testPackageWithEmbedderYaml = final Directory testPackageWithNoReadme = new Directory('testing/test_package_small'); +/// Convenience factory to build a [DartdocOptionContext] and associate it with a +/// [DartdocOptionSet] based on the current working directory. +Future contextFromArgv(List argv) async { + DartdocOptionSet optionSet = await DartdocOptionSet + .fromOptionGenerators('dartdoc', [createDartdocOptions]); + optionSet.parseArguments(argv); + return new DartdocOptionContext(optionSet, Directory.current); +} + void delete(Directory dir) { if (dir.existsSync()) dir.deleteSync(recursive: true); } @@ -47,11 +55,7 @@ init() async { } Future bootSdkPackage() async { - Directory dir = new Directory(pathLib.current); - return new PackageBuilder( - await DartdocOptionContext - .fromArgv(['--input', dir.path, '--sdk-dir', sdkDir.path]), - sdkPackageMeta) + return new PackageBuilder(await contextFromArgv(['--input', sdkDir.path])) .buildPackageGraph(); } @@ -60,17 +64,15 @@ Future bootBasicPackage( {bool withAutoIncludedDependencies = false, bool withCrossdart = false}) async { Directory dir = new Directory(dirPath); - return new PackageBuilder( - await DartdocOptionContext.fromArgv([ - '--input', - dir.path, - '--sdk-dir', - sdkDir.path, - '--exclude', - excludeLibraries.join(','), - '--${withCrossdart ? "" : "no-"}add-crossdart', - '--${withAutoIncludedDependencies ? "" : "no-"}auto-include-dependencies' - ]), - new PackageMeta.fromDir(new Directory(dirPath))) + return new PackageBuilder(await contextFromArgv([ + '--input', + dir.path, + '--sdk-dir', + sdkDir.path, + '--exclude', + excludeLibraries.join(','), + '--${withCrossdart ? "" : "no-"}add-crossdart', + '--${withAutoIncludedDependencies ? "" : "no-"}auto-include-dependencies' + ])) .buildPackageGraph(); } diff --git a/testing/test_package_bad/pubspec.lock b/testing/test_package_bad/pubspec.lock new file mode 100644 index 0000000000..802445c793 --- /dev/null +++ b/testing/test_package_bad/pubspec.lock @@ -0,0 +1,5 @@ +# Generated by pub +# See https://www.dartlang.org/tools/pub/glossary#lockfile +packages: {} +sdks: + dart: any diff --git a/testing/test_package_small/pubspec.lock b/testing/test_package_small/pubspec.lock index c427295339..802445c793 100644 --- a/testing/test_package_small/pubspec.lock +++ b/testing/test_package_small/pubspec.lock @@ -1,5 +1,5 @@ # Generated by pub -# See http://pub.dartlang.org/doc/glossary.html#lockfile +# See https://www.dartlang.org/tools/pub/glossary#lockfile packages: {} sdks: dart: any From fa77e1a124fa15e89c043c6ac7b9c5781d514010 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 19 Apr 2018 12:50:30 -0700 Subject: [PATCH 3/4] Delete old tests --- test/dartdoc_options_test.dart | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/test/dartdoc_options_test.dart b/test/dartdoc_options_test.dart index cd5d4f9e88..0390ca2d61 100644 --- a/test/dartdoc_options_test.dart +++ b/test/dartdoc_options_test.dart @@ -548,29 +548,4 @@ dartdoc: equals('parent')); }); }); - /* - group('dartdoc options', () { - group('options file finding and loading', () { - test('DartdocOptions loads defaults', () { - DartdocOptions options = new DartdocOptions.fromDir(tempDir); - expect(options.categoryOrder, isEmpty); - }); - - test('DartdocOptions loads a file', () { - DartdocOptions options = new DartdocOptions.fromDir(firstDir); - expect(options.categoryOrder, orderedEquals(['options_one'])); - }); - - test('DartdocOptions loads a file in parent directories', () { - DartdocOptions options = new DartdocOptions.fromDir(secondDirSecondSub); - expect(options.categoryOrder, orderedEquals(['options_two'])); - }); - - test('DartdocOptions loads the override file instead of parents', () { - DartdocOptions options = new DartdocOptions.fromDir(secondDirFirstSub); - expect(options.categoryOrder, orderedEquals(['options_two_first_sub'])); - }); - }); - }); - */ } From af0cae1cff613f6ab9a4a3ec761a3b26779920b9 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 19 Apr 2018 14:17:29 -0700 Subject: [PATCH 4/4] Review comments --- lib/src/model.dart | 22 +++++++++++----------- pubspec.lock | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/src/model.dart b/lib/src/model.dart index 726caf590a..3d70384764 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -3859,7 +3859,7 @@ class PackageGraph extends Canonicalization if (__crossdartJson == null) { // TODO(jcollins-g): allow crossdart.json location to be configurable var crossdartFile = - new File(pathLib.join(config.inputDir, "crossdart.json")); + new File(pathLib.join(config.inputDir, 'crossdart.json')); if (crossdartFile.existsSync()) { Map __crossdartJsonTmp = json.decode(crossdartFile.readAsStringSync()); @@ -4985,30 +4985,30 @@ abstract class SourceCodeMixin implements Documentable { var filePath = source.fullName; var uri = source.uri.toString(); var packageMeta = library.packageGraph.packageMeta; - if (uri.startsWith("package:")) { + if (uri.startsWith('package:')) { var splittedUri = - uri.replaceAll(new RegExp(r"^package:"), "").split("/"); + uri.replaceAll(new RegExp(r'^package:'), '').split('/'); var packageName = splittedUri.first; var packageVersion; if (packageName == packageMeta.name) { packageVersion = packageMeta.version; } else { var match = new RegExp( - ".pub-cache/(hosted/pub.dartlang.org|git)/${packageName}-([^/]+)") + '.pub-cache/(hosted/pub.dartlang.org|git)/${packageName}-([^/]+)') .firstMatch(filePath); if (match != null) { packageVersion = match[2]; } } if (packageVersion != null) { - return "${packageName}/${packageVersion}/${splittedUri.skip(1).join("/")}"; + return '${packageName}/${packageVersion}/${splittedUri.skip(1).join("/")}'; } else { return null; } - } else if (uri.startsWith("dart:")) { - var packageName = "sdk"; + } else if (uri.startsWith('dart:')) { + var packageName = 'sdk'; var packageVersion = packageGraph.sdk.sdkVersion; - return "${packageName}/${packageVersion}/lib/${uri.replaceAll(new RegExp(r"^dart:"), "")}"; + return '${packageName}/${packageVersion}/lib/${uri.replaceAll(new RegExp(r"^dart:"), "")}'; } else { return null; } @@ -5019,8 +5019,8 @@ abstract class SourceCodeMixin implements Documentable { String get _crossdartUrl { if (lineAndColumn != null && _crossdartPath != null) { - String url = "//www.crossdart.info/p/${_crossdartPath}.html"; - return "${url}#line-${lineAndColumn.item1}"; + String url = '//www.crossdart.info/p/${_crossdartPath}.html'; + return '${url}#line-${lineAndColumn.item1}'; } else { return null; } @@ -5271,7 +5271,7 @@ class PackageBuilder { EmbedderSdk _embedderSdk; EmbedderSdk get embedderSdk { - if (_embedderSdk == null && config.packageMeta.isSdk == false) { + if (_embedderSdk == null && !config.packageMeta.isSdk) { _embedderSdk = new EmbedderSdk(PhysicalResourceProvider.INSTANCE, new EmbedderYamlLocator(packageMap).embedderYamls); } diff --git a/pubspec.lock b/pubspec.lock index 7ffbfa109f..0d280687d2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -408,4 +408,4 @@ packages: source: hosted version: "2.1.13" sdks: - dart: ">=2.0.0-dev.23.0 <=2.0.0-dev.48.0" + dart: ">=2.0.0-dev.23.0 <=2.0.0-dev.49.0"