diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart index 459049f0dd..9824affa8a 100644 --- a/bin/dartdoc.dart +++ b/bin/dartdoc.dart @@ -68,10 +68,6 @@ main(List arguments) async { exit(1); } - List excludeLibraries = args['exclude'] as List; - List includeLibraries = args['include'] as List; - List includeExternals = args['include-external'] as List; - String url = args['hosted-url']; List headerFilePaths = @@ -252,26 +248,30 @@ main(List arguments) async { ]); } - setConfig( - addCrossdart: args['add-crossdart'], - examplePathPrefix: args['example-path-prefix'], - showWarnings: args['show-warnings'], - includeSource: args['include-source'], - inputDir: inputDir, - sdkVersion: sdk.sdkVersion, - autoIncludeDependencies: args['auto-include-dependencies'], - packageOrder: args['package-order'].isEmpty - ? args['category-order'] - : args['package-order'], - reexportMinConfidence: - double.parse(args['ambiguous-reexport-scorer-min-confidence']), - verboseWarnings: args['verbose-warnings'], - excludePackages: args['exclude-packages'], - dropTextFrom: dropTextFrom, - validateLinks: args['validate-links']); - - DartDoc dartdoc = new DartDoc(inputDir, excludeLibraries, sdkDir, generators, - outputDir, packageMeta, includeLibraries, includeExternals); + 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'], + includeExternals: args['include-external'], + includeLibraries: args['include'], + includeSource: args['include-source'], + inputDir: inputDir, + packageOrder: args['package-order'].isEmpty + ? args['category-order'] + : args['package-order'], + reexportMinConfidence: + double.parse(args['ambiguous-reexport-scorer-min-confidence']), + sdkDir: sdkDir, + sdkVersion: sdk.sdkVersion, + showWarnings: args['show-warnings'], + validateLinks: args['validate-links'], + verboseWarnings: args['verbose-warnings'], + ); + + DartDoc dartdoc = new DartDoc(config, generators, outputDir, packageMeta); dartdoc.onCheckProgress.listen(logProgress); await Chain.capture(() async { diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart index 850d596ea3..3968d84bca 100644 --- a/lib/dartdoc.dart +++ b/lib/dartdoc.dart @@ -75,25 +75,9 @@ class DartDoc extends PackageBuilder { final StreamController _onCheckProgress = new StreamController(sync: true); - DartDoc( - Directory rootDir, - List excludes, - Directory sdkDir, - this.generators, - this.outputDir, - PackageMeta packageMeta, - List includes, - List includeExternals) - : super( - rootDir, - excludes, - config.excludePackages, - sdkDir, - packageMeta, - includes, - includeExternals, - config.showWarnings, - config.autoIncludeDependencies); + DartDoc(DartDocConfig config, this.generators, this.outputDir, + PackageMeta packageMeta) + : super(config, packageMeta); Stream get onCheckProgress => _onCheckProgress.stream; diff --git a/lib/src/config.dart b/lib/src/config.dart index 70c732e520..628e49ce79 100644 --- a/lib/src/config.dart +++ b/lib/src/config.dart @@ -23,65 +23,86 @@ class LocalConfig { } } -class Config { - final Directory inputDir; - final bool showWarnings; +class DartDocConfig { final bool addCrossdart; + final bool autoIncludeDependencies; + final List dropTextFrom; + final List excludeLibraries; + final List excludePackages; final String examplePathPrefix; + final List includeExternals; + final List includeLibraries; final bool includeSource; - final String sdkVersion; - final bool autoIncludeDependencies; + final Directory inputDir; final List packageOrder; final double reexportMinConfidence; - final bool verboseWarnings; - final List dropTextFrom; - final List excludePackages; + final Directory sdkDir; + final String sdkVersion; + final bool showWarnings; final bool validateLinks; - Config._( - this.inputDir, - this.showWarnings, - this.addCrossdart, - this.examplePathPrefix, - this.includeSource, - this.sdkVersion, - this.autoIncludeDependencies, - this.packageOrder, - this.reexportMinConfidence, - this.verboseWarnings, - this.dropTextFrom, - this.excludePackages, - this.validateLinks); -} - -Config _config; -Config get config => _config; + final bool verboseWarnings; + DartDocConfig._( + this.addCrossdart, + this.autoIncludeDependencies, + this.dropTextFrom, + this.examplePathPrefix, + this.excludeLibraries, + this.excludePackages, + this.includeExternals, + this.includeLibraries, + this.includeSource, + this.inputDir, + this.packageOrder, + this.reexportMinConfidence, + this.sdkDir, + this.sdkVersion, + this.showWarnings, + this.validateLinks, + this.verboseWarnings, + ); -void setConfig( - {Directory inputDir, - bool showWarnings: false, + factory DartDocConfig.fromParameters({ bool addCrossdart: false, + bool autoIncludeDependencies: false, + List dropTextFrom, String examplePathPrefix, + List excludeLibraries, + List excludePackages, + List includeExternals, + List includeLibraries, bool includeSource: true, - String sdkVersion, - bool autoIncludeDependencies: false, + Directory inputDir, List packageOrder, double reexportMinConfidence: 0.1, + Directory sdkDir, + String sdkVersion, + bool showWarnings: false, + bool validateLinks: true, bool verboseWarnings: true, - List dropTextFrom, - List excludePackages, - bool validateLinks: true}) { - _config = new Config._( - inputDir, - showWarnings, + }) { + return new DartDocConfig._( addCrossdart, + autoIncludeDependencies, + dropTextFrom ?? const [], examplePathPrefix, + excludeLibraries ?? const [], + excludePackages ?? const [], + includeExternals ?? const [], + includeLibraries ?? const [], includeSource, - sdkVersion, - autoIncludeDependencies, + inputDir, packageOrder ?? const [], reexportMinConfidence, + sdkDir ?? getSdkDir(), + sdkVersion, + showWarnings, + validateLinks, verboseWarnings, - dropTextFrom ?? const [], - excludePackages ?? const [], - validateLinks); + ); + } + + bool isLibraryExcluded(String name) => + excludeLibraries.any((pattern) => name == pattern); + bool isPackageExcluded(String name) => + excludePackages.any((pattern) => name == pattern); } diff --git a/lib/src/model.dart b/lib/src/model.dart index 3b9b1d93e8..c67101225a 100644 --- a/lib/src/model.dart +++ b/lib/src/model.dart @@ -37,7 +37,6 @@ import 'package:analyzer/src/dart/analysis/driver.dart'; import 'package:collection/collection.dart'; import 'package:dartdoc/src/dartdoc_options.dart'; import 'package:dartdoc/src/io_utils.dart'; -import 'package:dartdoc/src/sdk.dart'; import 'package:front_end/src/byte_store/byte_store.dart'; import 'package:front_end/src/base/performance_logger.dart'; import 'package:path/path.dart' as pathLib; @@ -54,26 +53,6 @@ import 'package_meta.dart' show PackageMeta, FileContents; import 'utils.dart'; import 'warnings.dart'; -Map>>> __crossdartJson; - -Map>>> get _crossdartJson { - if (__crossdartJson == null) { - if (config != null) { - var crossdartFile = - new File(pathLib.join(config.inputDir.path, "crossdart.json")); - if (crossdartFile.existsSync()) { - __crossdartJson = json.decode(crossdartFile.readAsStringSync()) - as Map>>>; - } else { - __crossdartJson = {}; - } - } else { - __crossdartJson = {}; - } - } - return __crossdartJson; -} - int byName(Nameable a, Nameable b) => compareAsciiLowerCaseNatural(a.name, b.name); @@ -1176,6 +1155,7 @@ abstract class Documentable extends Nameable { String get oneLineDoc; PackageGraph get packageGraph; bool get isDocumented; + DartDocConfig get config; } /// Mixin implementing dartdoc categorization for ModelElements. @@ -1821,8 +1801,8 @@ class Library extends ModelElement with Categorization { if (sdkLib != null && (sdkLib.isInternal || !sdkLib.isDocumented)) { return false; } - if (packageGraph.isLibraryExcluded(name) || - packageGraph.isLibraryExcluded(element.librarySource.uri.toString())) + if (config.isLibraryExcluded(name) || + config.isLibraryExcluded(element.librarySource.uri.toString())) return false; return true; } @@ -2778,6 +2758,9 @@ abstract class ModelElement extends Canonicalization return _isPublic; } + @override + DartDocConfig get config => packageGraph.config; + @override Set get locationPieces { return new Set.from(element.location @@ -2953,7 +2936,7 @@ abstract class ModelElement extends Canonicalization List debugLines = []; debugLines.addAll(scoredCandidates.map((s) => '${s.toString()}')); - if (config == null || confidence < config.reexportMinConfidence) { + if (confidence < config.reexportMinConfidence) { warnable.warn(PackageWarning.ambiguousReexport, message: message, extendedDebug: debugLines); } @@ -3588,7 +3571,7 @@ abstract class ModelElement extends Canonicalization var ext = pathLib.extension(src); file = pathLib.join(dir, '$basename-$region$ext$fragExtension'); } - args['file'] = config?.examplePathPrefix == null + args['file'] = config.examplePathPrefix == null ? file : pathLib.join(config.examplePathPrefix, file); return args; @@ -3769,19 +3752,13 @@ class Operator extends Method { String get typeName => 'operator'; } -class PackageGraph extends Canonicalization with Nameable, Warnable { +class PackageGraph extends Canonicalization + with Nameable, Warnable, LibraryContainer { // TODO(jcollins-g): This constructor is convoluted. Clean this up by // building Libraries and adding them to Packages, then adding Packages // to this graph. - PackageGraph( - Iterable libraryElements, - this.packageMeta, - this._packageWarningOptions, - this.driver, - this.sdk, - this.autoIncludeDependencies, - this.excludes, - this.excludePackages) { + PackageGraph(Iterable libraryElements, this.config, + this.packageMeta, this._packageWarningOptions, this.driver, this.sdk) { assert(_allConstructedModelElements.isEmpty); assert(allLibraries.isEmpty); _packageWarningCounter = new PackageWarningCounter(_packageWarningOptions); @@ -3818,25 +3795,15 @@ class PackageGraph extends Canonicalization with Nameable, Warnable { allImplementorsAdded = true; } - /// Write files for packages outside the default. - final bool autoIncludeDependencies; - /// It is safe to cache values derived from the _implementors table if this /// is true. bool allImplementorsAdded = false; - /// A list of library names to treat as private. - final List excludes; - - /// A list of package names to exclude from local documentation. - final List excludePackages; + @override + List get containerOrder => []; - // TODO(jcollins-g): refactor to eliminate the duplication with PackageBuilder - // (currently necessary for better use of the analyzer). - bool isLibraryExcluded(String name) => - excludes.any((pattern) => name == pattern); - bool isPackageExcluded(String name) => - excludePackages.any((pattern) => name == pattern); + @override + LibraryContainer get enclosingContainer => null; Map> get implementors { assert(allImplementorsAdded); @@ -3864,6 +3831,31 @@ class PackageGraph extends Canonicalization with Nameable, Warnable { /// PackageMeta for the default package. final PackageMeta packageMeta; + /// Dartdoc's configuration flags. + @override + final DartDocConfig config; + + Map>>> __crossdartJson; + // TODO(jcollins-g): move to [Package] + Map>>> get crossdartJson { + if (__crossdartJson == null) { + // TODO(jcollins-g): allow crossdart.json location to be configurable + var crossdartFile = + new File(pathLib.join(config.inputDir.path, "crossdart.json")); + if (crossdartFile.existsSync()) { + var __crossdartJsonTmp = json.decode(crossdartFile.readAsStringSync()) + as Map>>>; + __crossdartJson = {}; + for (String key in __crossdartJsonTmp.keys) { + __crossdartJson[pathLib.canonicalize(key)] = __crossdartJsonTmp[key]; + } + } else { + __crossdartJson = {}; + } + } + return __crossdartJson; + } + @override Set get locationPieces => new Set(); @@ -4156,10 +4148,8 @@ class PackageGraph extends Canonicalization with Nameable, Warnable { publicPackages.where((p) => p.isLocal).toList(); /// Documented packages are documented somewhere (local or remote). - Iterable get documentedPackages => packages.where((p) => p.documentedWhere != DocumentLocation.missing); - - // Use only in testing. - void resetPublicPackages() => _publicPackages = null; + Iterable get documentedPackages => + packages.where((p) => p.documentedWhere != DocumentLocation.missing); Map> _libraryElementReexportedBy = new Map(); void _tagReexportsFor( @@ -4244,7 +4234,7 @@ class PackageGraph extends Canonicalization with Nameable, Warnable { @override String get href => 'index.html'; - /// Does this package represent the SDK? + @override bool get isSdk => packageMeta.isSdk; void _addToImplementors(Class c) { @@ -4274,10 +4264,12 @@ class PackageGraph extends Canonicalization with Nameable, Warnable { } } + @override List get libraries => packages.expand((p) => p.libraries).toList()..sort(); List _publicLibraries; + @override Iterable get publicLibraries { if (_publicLibraries == null) { assert(allLibrariesAdded); @@ -4596,59 +4588,79 @@ class PackageGraph extends Canonicalization with Nameable, Warnable { } /// A set of libraries, initialized after construction by accessing [_libraries]. -/// Do not call any methods or members excepting [_libraries] and [name] before -/// finishing initialization of a [LibraryContainer]. -abstract class LibraryContainer extends Nameable { +/// Do not cache return values of any methods or members excepting [_libraries] +/// and [name] before finishing initialization of a [LibraryContainer]. +abstract class LibraryContainer extends Nameable + implements Comparable { final List _libraries = []; - PackageGraph get packageGraph; + + /// An enclosing container's [libraries] must be a superset of this object's + /// [libraries]. + LibraryContainer get enclosingContainer; List get libraries => _libraries; Iterable get publicLibraries => filterNonPublic(libraries); @override String toString() => name; -} - -/// 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]. -class Category extends LibraryContainer implements Comparable { - /// All libraries in [libraries] must come from [package]. - Package package; - DartdocOptions dartdocOptions; - String _name; - Category(this._name, this.package, this.dartdocOptions); + /// Does this container represent the SDK? This can be false for containers + /// that only represent a part of the SDK. + bool get isSdk => false; - @override - String get name => _name; + /// Order by which this container should be sorted. + List get containerOrder; /// Returns: - /// -1 if this category is listed in categoryOrder. - /// 0 if this category is named the same as the package. - /// 1 if this group has a name that contains the name of the package. - /// 2 otherwise. + /// -1 if this container is listed in [containerOrder]. + /// 0 if this container is named the same as the [enclosingContainer]. + /// 1 if this container represents the SDK. + /// 2 if this group has a name that contains the name of the [enclosingContainer]. + /// 3 otherwise. int get _group { - if (dartdocOptions.categoryOrder.contains(name)) return -1; - if (name.toLowerCase() == package.name.toLowerCase()) return 0; - if (name.toLowerCase().contains(package.name.toLowerCase())) return 1; - return 2; + if (containerOrder.contains(name)) return -1; + if (equalsIgnoreAsciiCase(name, enclosingContainer.name)) return 0; + if (isSdk) return 1; + if (name.toLowerCase().contains(enclosingContainer.name.toLowerCase())) + return 2; + return 3; } @override - int compareTo(Category other) { + int compareTo(LibraryContainer other) { if (_group == other._group) { if (_group == -1) { - return Comparable.compare(dartdocOptions.categoryOrder.indexOf(name), - dartdocOptions.categoryOrder.indexOf(other.name)); + return Comparable.compare( + containerOrder.indexOf(name), containerOrder.indexOf(other.name)); } else { return name.toLowerCase().compareTo(other.name.toLowerCase()); } } return Comparable.compare(_group, other._group); } +} + +/// 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]. +class Category extends LibraryContainer { + final String _name; + + /// All libraries in [libraries] must come from [package]. + final Package package; + final DartdocOptions dartdocOptions; + + Category(this._name, this.package, this.dartdocOptions); + + @override + String get name => _name; + + @override + List get containerOrder => dartdocOptions.categoryOrder; @override + Package get enclosingContainer => package; + PackageGraph get packageGraph => package.packageGraph; } @@ -4665,8 +4677,11 @@ enum DocumentLocation { /// A [LibraryContainer] that contains [Library] objects related to a particular /// package. class Package extends LibraryContainer - with Locatable - implements Comparable, Privacy { + with + Locatable + // TODO(jcollins-g): implements Documentable + implements + Privacy { String _name; PackageGraph _packageGraph; final _isLocal; @@ -4678,8 +4693,8 @@ class Package extends LibraryContainer PackageMeta packageMeta, PackageGraph packageGraph) { String packageName = packageMeta.name; bool isLocal = packageMeta == packageGraph.packageMeta || - packageGraph.autoIncludeDependencies; - isLocal = isLocal && !packageGraph.isPackageExcluded(packageName); + packageGraph.config.autoIncludeDependencies; + isLocal = isLocal && !packageGraph.config.isPackageExcluded(packageName); bool expectNonLocal = false; if (!packageGraph.packageMap.containsKey(packageName) && @@ -4710,6 +4725,9 @@ class Package extends LibraryContainer /// in this package. bool get hasCategories => categories.isNotEmpty; + @override + List get containerOrder => packageGraph.config.packageOrder; + LibraryContainer get defaultCategory => nameToCategory[null]; @override @@ -4732,6 +4750,9 @@ class Package extends LibraryContainer return DocumentLocation.local; } + @override + PackageGraph get enclosingContainer => packageGraph; + @override String get fullyQualifiedName => 'package:$name'; @@ -4744,7 +4765,6 @@ class Package extends LibraryContainer @override String get name => _name; - @override PackageGraph get packageGraph => _packageGraph; // Workaround for mustache4dart issue where templates do not recognize @@ -4790,13 +4810,14 @@ class Package extends LibraryContainer /// package specially (with "Libraries" rather than the package name). bool get isFirstPackage => identical(packageGraph.localPackages.first, this); + @override bool get isSdk => packageMeta.isSdk; String _packagePath; String get packagePath { if (_packagePath == null) { if (isSdk) { - _packagePath = getSdkDir().path; + _packagePath = packageGraph.config.sdkDir.path; } else { assert(libraries.isNotEmpty); File file = new File( @@ -4820,34 +4841,6 @@ class Package extends LibraryContainer @override String toString() => name; - - /// Returns: - /// -1 if this package is listed in --package-order. - /// 0 if this package is the original package we are documenting. - /// 1 if this package represents the Dart SDK. - /// 2 if this package has a name that contains the name of the original - /// package we are documenting. - /// 3 otherwise. - int get _group { - if (config.packageOrder.contains(name)) return -1; - if (name.toLowerCase() == packageGraph.name.toLowerCase()) return 0; - if (isSdk) return 1; - if (name.toLowerCase().contains(packageGraph.name.toLowerCase())) return 2; - return 3; - } - - @override - int compareTo(Package other) { - if (_group == other._group) { - if (_group == -1) { - return Comparable.compare(config.packageOrder.indexOf(name), - config.packageOrder.indexOf(other.name)); - } else { - return name.toLowerCase().compareTo(other.name.toLowerCase()); - } - } - return Comparable.compare(_group, other._group); - } } class Parameter extends ModelElement implements EnclosedElement { @@ -4906,10 +4899,10 @@ class Parameter extends ModelElement implements EnclosedElement { String toString() => element.name; } -abstract class SourceCodeMixin { +abstract class SourceCodeMixin implements Documentable { String _sourceCodeCache; String get crossdartHtmlTag { - if (config != null && config.addCrossdart && _crossdartUrl != null) { + if (config.addCrossdart && _crossdartUrl != null) { return "Link to Crossdart"; } else { return ""; @@ -4942,8 +4935,9 @@ abstract class SourceCodeMixin { var start = node.offset - (node.offset - i); String source = contents.substring(start, node.end); - if (config != null && config.addCrossdart) { - source = crossdartifySource(_crossdartJson, source, element, start); + if (config.addCrossdart) { + source = crossdartifySource(config.inputDir.path, + packageGraph.crossdartJson, source, element, start); } else { source = const HtmlEscape().convert(source); } @@ -4960,7 +4954,6 @@ abstract class SourceCodeMixin { if (_sourceCodeCache == null) { _sourceCodeCache = sourceCodeFor(element); } - return _sourceCodeCache; } @@ -5011,10 +5004,6 @@ abstract class SourceCodeMixin { return null; } } - - void clearSourceCodeCache() { - _sourceCodeCache = null; - } } abstract class TypeParameters implements ModelElement { @@ -5234,40 +5223,24 @@ class TypeParameter extends ModelElement { /// Everything you need to instantiate a PackageGraph object for documenting. class PackageBuilder { - final bool autoIncludeDependencies; - final List excludes; - final List excludePackages; - final List includes; - final List includeExternals; final PackageMeta packageMeta; - final Directory rootDir; - final Directory sdkDir; - final bool showWarnings; - - PackageBuilder( - this.rootDir, - this.excludes, - this.excludePackages, - this.sdkDir, - this.packageMeta, - this.includes, - this.includeExternals, - this.showWarnings, - this.autoIncludeDependencies); + final DartDocConfig config; + + PackageBuilder(this.config, this.packageMeta); void logAnalysisErrors(Set sources) {} Future buildPackageGraph() async { Set libraries = await getLibraries(getFiles); - return new PackageGraph(libraries, packageMeta, getWarningOptions(), driver, - sdk, autoIncludeDependencies, excludes, excludePackages); + return new PackageGraph( + libraries, config, packageMeta, getWarningOptions(), driver, sdk); } DartSdk _sdk; DartSdk get sdk { if (_sdk == null) { _sdk = new FolderBasedDartSdk(PhysicalResourceProvider.INSTANCE, - PhysicalResourceProvider.INSTANCE.getFolder(sdkDir.path)); + PhysicalResourceProvider.INSTANCE.getFolder(config.sdkDir.path)); } return _sdk; } @@ -5302,7 +5275,7 @@ class PackageBuilder { Map> get packageMap { if (_packageMap == null) { fileSystem.Folder cwd = - PhysicalResourceProvider.INSTANCE.getResource(rootDir.path); + PhysicalResourceProvider.INSTANCE.getResource(config.inputDir.path); _packageMap = _calculatePackageMap(cwd); } return _packageMap; @@ -5378,9 +5351,10 @@ class PackageBuilder { } PackageWarningOptions getWarningOptions() { - PackageWarningOptions warningOptions = new PackageWarningOptions(); + PackageWarningOptions warningOptions = + new PackageWarningOptions(config.verboseWarnings); // TODO(jcollins-g): explode this into detailed command line options. - if (config != null && showWarnings) { + if (config.showWarnings) { for (PackageWarning kind in PackageWarning.values) { warningOptions.warn(kind); } @@ -5400,8 +5374,6 @@ class PackageBuilder { } } - bool isExcluded(String name) => excludes.any((pattern) => name == pattern); - /// Parse a single library at [filePath] using the current analysis driver. /// Note: [libraries] and [sources] are output parameters. Adds a libraryElement /// only if it has a non-private name. @@ -5429,12 +5401,12 @@ class PackageBuilder { } } // TODO(jcollins-g): Excludes can match on uri or on name. Fix that. - if (!isExcluded(source.uri.toString())) { + if (!config.isLibraryExcluded(source.uri.toString())) { LibraryElement library = await driver.getLibraryByUri(source.uri.toString()); if (library != null) { - if (!isExcluded(Library.getLibraryName(library)) && - !excludePackages + if (!config.isLibraryExcluded(Library.getLibraryName(library)) && + !config.excludePackages .contains(new PackageMeta.fromElement(library)?.name)) { libraries.add(library); sources.add(source); @@ -5506,7 +5478,7 @@ class PackageBuilder { new Uri.file(pathLib.join(basePackageDir, 'pubspec.yaml'))) .asMap(); for (String packageName in info.keys) { - if (!filterExcludes || !excludes.contains(packageName)) { + if (!filterExcludes || !config.excludeLibraries.contains(packageName)) { packageDirs.add(pathLib.dirname(info[packageName].toFilePath())); } } @@ -5545,7 +5517,8 @@ class PackageBuilder { Set files = new Set(); files.addAll(packageMeta.isSdk ? new Set() - : findFilesToDocumentInPackage(rootDir.path, autoIncludeDependencies)); + : findFilesToDocumentInPackage( + config.inputDir.path, config.autoIncludeDependencies)); if (packageMeta.isSdk) { files.addAll(getSdkFilesToDocument()); } else if (embedderSdk.urlMappings.isNotEmpty && !packageMeta.isSdk) { @@ -5556,7 +5529,7 @@ class PackageBuilder { } // Use the includeExternals. for (String fullName in driver.knownFiles) { - if (includeExternals.any((string) => fullName.endsWith(string))) + if (config.includeExternals.any((string) => fullName.endsWith(string))) files.add(fullName); } return new Set.from(files.map((s) => new File(s).absolute.path)); @@ -5565,15 +5538,16 @@ class PackageBuilder { Future> getLibraries(Set files) async { Set libraries = new Set(); libraries.addAll(await _parseLibraries(files)); - if (includes != null && includes.isNotEmpty) { + if (config.includeLibraries.isNotEmpty) { Iterable knownLibraryNames = libraries.map((l) => l.name); - Set notFound = - new Set.from(includes).difference(new Set.from(knownLibraryNames)); + Set notFound = new Set.from(config.includeLibraries) + .difference(new Set.from(knownLibraryNames)); if (notFound.isNotEmpty) { throw 'Did not find: [${notFound.join(', ')}] in ' 'known libraries: [${knownLibraryNames.join(', ')}]'; } - libraries.removeWhere((lib) => !includes.contains(lib.name)); + libraries + .removeWhere((lib) => !config.includeLibraries.contains(lib.name)); } return libraries; } diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 28c55cec88..df24a7a9cc 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -14,10 +14,9 @@ import 'package:analyzer/src/generated/sdk.dart'; import 'package:analyzer/src/generated/source_io.dart'; import 'package:collection/collection.dart'; import 'package:dartdoc/src/model.dart'; +import 'package:path/path.dart' as pathLib; import 'package:quiver/core.dart'; -import 'config.dart'; - final Map _fileContents = {}; /// Remove elements that aren't documented. @@ -140,16 +139,17 @@ String stripIndentFromSource(String source) { /// Add links to crossdart.info to the given source fragment String crossdartifySource( + String inputPath, Map>>> json, String source, Element element, int start) { + inputPath = pathLib.canonicalize(inputPath); var sanitizer = const HtmlEscape(); String newSource; if (json.isNotEmpty) { var node = element.computeNode(); - var file = element.source.fullName - .replaceAll("${config.inputDir.path}${Platform.pathSeparator}", ""); + var file = pathLib.canonicalize(element.source.fullName); var filesData = json[file]; if (filesData != null) { var data = filesData["references"] diff --git a/lib/src/sdk.dart b/lib/src/sdk.dart index 1630001241..91a709e599 100644 --- a/lib/src/sdk.dart +++ b/lib/src/sdk.dart @@ -4,6 +4,7 @@ import 'dart:io'; +/// Use config.sdkDir instead outside of initialization. Directory getSdkDir() { File vmExecutable = new File(Platform.resolvedExecutable); return vmExecutable.parent.parent; diff --git a/lib/src/warnings.dart b/lib/src/warnings.dart index f8987dc223..5fc5d2fccf 100644 --- a/lib/src/warnings.dart +++ b/lib/src/warnings.dart @@ -6,7 +6,6 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:dartdoc/src/model.dart'; import 'package:tuple/tuple.dart'; -import 'config.dart'; import 'logging.dart'; class PackageWarningHelpText { @@ -137,10 +136,12 @@ class PackageWarningOptions { // PackageWarnings can be in both asWarnings and asErrors, latter takes precedence final Set asWarnings = new Set(); final Set asErrors = new Set(); + // Display verbose warnings. + final bool verboseWarnings; bool autoFlush = true; - PackageWarningOptions() { + PackageWarningOptions(this.verboseWarnings) { asWarnings.addAll(PackageWarning.values); ignore(PackageWarning.typeAsHtml); } @@ -215,7 +216,7 @@ class PackageWarningCounter { if (type != null) { var entry = " $type: $fullMessage"; if (_warningCounts[kind] == 1 && - config.verboseWarnings && + options.verboseWarnings && packageWarningText[kind].longHelp.isNotEmpty) { // First time we've seen this warning. Give a little extra info. final String separator = '\n '; diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart index df6ff73555..cb0855146e 100644 --- a/test/dartdoc_test.dart +++ b/test/dartdoc_test.dart @@ -9,7 +9,6 @@ import 'dart:io'; import 'package:dartdoc/dartdoc.dart'; import 'package:dartdoc/src/model.dart'; import 'package:dartdoc/src/package_meta.dart'; -import 'package:dartdoc/src/sdk.dart'; import 'package:path/path.dart' as pathLib; import 'package:test/test.dart'; @@ -21,7 +20,6 @@ void main() { setUp(() { tempDir = Directory.systemTemp.createTempSync('dartdoc.test.'); - setConfig(); }); tearDown(() { @@ -32,7 +30,10 @@ void main() { () async { PackageMeta meta = new PackageMeta.fromDir(testPackageDir); DartDoc dartdoc = new DartDoc( - testPackageDir, [], getSdkDir(), [], tempDir, meta, [], []); + new DartDocConfig.fromParameters(inputDir: testPackageDir), + [], + tempDir, + meta); DartDocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); @@ -48,7 +49,10 @@ void main() { () async { PackageMeta meta = new PackageMeta.fromDir(testPackageBadDir); DartDoc dartdoc = new DartDoc( - testPackageBadDir, [], getSdkDir(), [], tempDir, meta, [], []); + new DartDocConfig.fromParameters(inputDir: testPackageBadDir), + [], + tempDir, + meta); try { await dartdoc.generateDocs(); @@ -61,7 +65,10 @@ 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( - testPackageWithNoReadme, [], getSdkDir(), [], tempDir, meta, [], []); + new DartDocConfig.fromParameters(inputDir: testPackageWithNoReadme), + [], + tempDir, + meta); DartDocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); @@ -76,7 +83,11 @@ void main() { test('generate docs including a single library', () async { PackageMeta meta = new PackageMeta.fromDir(testPackageDir); DartDoc dartdoc = new DartDoc( - testPackageDir, [], getSdkDir(), [], tempDir, meta, ['fake'], []); + new DartDocConfig.fromParameters( + inputDir: testPackageDir, includeLibraries: ['fake']), + [], + tempDir, + meta); DartDocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); @@ -87,30 +98,36 @@ void main() { expect(p.libraries, hasLength(1)); expect(p.libraries.map((lib) => lib.name), contains('fake')); }); - /* - FIXME test('generate docs excluding a single library', () async { PackageMeta meta = new PackageMeta.fromDir(testPackageDir); DartDoc dartdoc = new DartDoc( - testPackageDir, ['fake'], getSdkDir(), [], tempDir, meta, []); + new DartDocConfig.fromParameters( + inputDir: testPackageDir, excludeLibraries: ['fake']), + [], + tempDir, + meta); DartDocResults results = await dartdoc.generateDocs(); - expect(results.package, isNotNull); + expect(results.packageGraph, isNotNull); - Package p = results.package; + PackageGraph p = results.packageGraph; expect(p.name, 'test_package'); expect(p.hasDocumentationFile, isTrue); - expect(p.publicLibraries, hasLength(9)); - expect(p.publicLibraries.map((lib) => lib.name).contains('fake'), isFalse); + expect(p.localPublicLibraries, hasLength(9)); + expect(p.localPublicLibraries.map((lib) => lib.name).contains('fake'), + isFalse); }); - */ test('generate docs for package with embedder yaml', () async { PackageMeta meta = new PackageMeta.fromDir(testPackageWithEmbedderYaml); if (meta.needsPubGet) meta.runPubGet(); - DartDoc dartdoc = new DartDoc(testPackageWithEmbedderYaml, [], - getSdkDir(), [], tempDir, meta, [], []); + DartDoc dartdoc = new DartDoc( + new DartDocConfig.fromParameters( + inputDir: testPackageWithEmbedderYaml), + [], + tempDir, + meta); DartDocResults results = await dartdoc.generateDocs(); expect(results.packageGraph, isNotNull); diff --git a/test/model_test.dart b/test/model_test.dart index c228f5f931..0b53bd8628 100644 --- a/test/model_test.dart +++ b/test/model_test.dart @@ -15,6 +15,29 @@ import 'package:test/test.dart'; import 'src/utils.dart' as utils; +/// For testing sort behavior. +class TestLibraryContainer extends LibraryContainer { + @override + final List containerOrder; + @override + final LibraryContainer enclosingContainer; + @override + final String name; + @override + bool get isSdk => false; + + TestLibraryContainer(this.name, this.containerOrder, this.enclosingContainer); +} + +class TestLibraryContainerSdk extends TestLibraryContainer { + TestLibraryContainerSdk(String name, List containerOrder, + LibraryContainer enclosingContainer) + : super(name, containerOrder, enclosingContainer); + + @override + bool get isSdk => true; +} + void main() { Directory sdkDir = getSdkDir(); @@ -116,19 +139,67 @@ void main() { }); }); + group('LibraryContainer', () { + TestLibraryContainer topLevel; + List sortOrderBasic; + List containerNames; + + setUpAll(() { + topLevel = new TestLibraryContainer('topLevel', [], null); + sortOrderBasic = ['theFirst', 'second', 'fruit']; + containerNames = [ + 'moo', + 'woot', + 'theFirst', + 'topLevel Things', + 'toplevel', + 'fruit' + ]; + }); + + test('multiple containers with specified sort order', () { + List containers = []; + for (String name in containerNames) + containers + .add(new TestLibraryContainer(name, sortOrderBasic, topLevel)); + containers + .add(new TestLibraryContainerSdk('SDK', sortOrderBasic, topLevel)); + containers.sort(); + expect( + containers.map((c) => c.name), + orderedEquals([ + 'theFirst', + 'fruit', + 'toplevel', + 'SDK', + 'topLevel Things', + 'moo', + 'woot' + ])); + }); + + test('multiple containers, no specified sort order', () { + List containers = []; + for (String name in containerNames) + containers.add(new TestLibraryContainer(name, [], topLevel)); + containers.add(new TestLibraryContainerSdk('SDK', [], topLevel)); + containers.sort(); + expect( + containers.map((c) => c.name), + orderedEquals([ + 'toplevel', + 'SDK', + 'topLevel Things', + 'fruit', + 'moo', + 'theFirst', + 'woot' + ])); + }); + }); + group('Package', () { group('test package', () { - setUp(() { - setConfig(); - ginormousPackageGraph.resetPublicPackages(); - packageGraph.resetPublicPackages(); - }); - tearDown(() { - setConfig(); - ginormousPackageGraph.resetPublicPackages(); - packageGraph.resetPublicPackages(); - }); - test('name', () { expect(packageGraph.name, 'test_package'); }); @@ -157,12 +228,6 @@ void main() { equals('test_package')); }); - test('multiple packages, specified sort order', () { - setConfig(packageOrder: ['meta', 'test_package']); - expect(ginormousPackageGraph.localPackages, hasLength(4)); - expect(ginormousPackageGraph.localPackages.first.name, equals('meta')); - }); - test('is documented in library', () { expect(exLibrary.isDocumented, isTrue); }); @@ -1263,7 +1328,6 @@ void main() { }); test('has source code', () { - setConfig(addCrossdart: false); expect(topLevelFunction.sourceCode, startsWith('@deprecated')); expect(topLevelFunction.sourceCode, endsWith(''' String topLevelFunction(int param1, bool param2, Cool coolBeans, @@ -1417,6 +1481,47 @@ String topLevelFunction(int param1, bool param2, Cool coolBeans, test('', () {}); }); + group('Crossdart', () { + PackageGraph crossdartPackageGraph; + Library crossdartFakeLibrary; + Class HasGenerics; + Method convertToMap; + + setUpAll(() async { + var fakePath = "testing/test_package/lib/fake.dart"; + var offset = new File(fakePath) + .readAsStringSync() + .indexOf('Map convertToMap'); + expect(offset, isNonNegative, + reason: "Can't find convertToMap function in ${fakePath}"); + if (Platform.isWindows) fakePath = fakePath.replaceAll('/', r'\\'); + + crossdartPackageGraph = await utils + .bootBasicPackage(utils.testPackageDir.path, [], withCrossdart: true); + crossdartFakeLibrary = + crossdartPackageGraph.libraries.firstWhere((l) => l.name == 'fake'); + HasGenerics = crossdartFakeLibrary.classes + .singleWhere((c) => c.name == 'HasGenerics'); + convertToMap = HasGenerics.instanceMethods + .singleWhere((m) => m.name == 'convertToMap'); + var crossDartFile = + new File(pathLib.join(utils.testPackageDir.path, "crossdart.json")); + crossDartFile.writeAsStringSync(""" + {"$fakePath": + {"references":[{"offset":${offset},"end":${offset+3},"remotePath":"http://www.example.com/fake.dart"}]}} + """); + // Indirectly load the file. + crossdartPackageGraph.crossdartJson; + if (crossDartFile.existsSync()) crossDartFile.deleteSync(); + }); + + test('Source code crossdartifies correctly end to end', () { + crossdartPackageGraph; + expect(convertToMap.sourceCode, + "Map<X, Y> convertToMap() => null;"); + }); + }); + group('Method', () { Class classB, klass, @@ -1466,14 +1571,6 @@ String topLevelFunction(int param1, bool param2, Cool coolBeans, .singleWhere((m) => m.name == 'getAFunctionReturningBool'); }); - tearDown(() { - var file = - new File(pathLib.join(Directory.current.path, "crossdart.json")); - if (file.existsSync()) { - file.deleteSync(); - } - }); - test('verify parameter types are correctly displayed', () { expect( getAFunctionReturningVoid.linkedReturnType, @@ -1582,37 +1679,14 @@ String topLevelFunction(int param1, bool param2, Cool coolBeans, }); test('method source code indents correctly', () { - setConfig(addCrossdart: false); expect(convertToMap.sourceCode, 'Map<X, Y> convertToMap() => null;'); }); - test('method source code crossdartifies correctly', () { - convertToMap.clearSourceCodeCache(); - var fakePath = "testing/test_package/lib/fake.dart"; - var offset = new File(fakePath) - .readAsStringSync() - .indexOf('Map convertToMap'); - expect(offset, isNonNegative, - reason: "Can't find convertToMap function in ${fakePath}"); - if (Platform.isWindows) fakePath = fakePath.replaceAll('/', r'\\'); - new File(pathLib.join(Directory.current.path, "crossdart.json")) - .writeAsStringSync(""" - {"$fakePath": - {"references":[{"offset":${offset},"end":${offset+3},"remotePath":"http://www.example.com/fake.dart"}]}} - """); - - setConfig(addCrossdart: true, inputDir: Directory.current); - - expect(convertToMap.sourceCode, - "Map<X, Y> convertToMap() => null;"); - }); - - group(".crossdartHtmlTag()", () { - test('it returns an empty string when Crossdart support is disabled', () { - setConfig(addCrossdart: false); - expect(m1.crossdartHtmlTag, ""); - }); + test( + 'crossdartHtmlTag returns an empty string when Crossdart support is disabled', + () { + expect(m1.crossdartHtmlTag, ""); }); }); diff --git a/test/src/utils.dart b/test/src/utils.dart index 4097287159..b381e8361c 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -35,37 +35,40 @@ void delete(Directory dir) { init() async { sdkDir = getSdkDir(); sdkPackageMeta = new PackageMeta.fromDir(sdkDir); - setConfig(); testPackageGraph = await bootBasicPackage( - 'testing/test_package', ['css', 'code_in_comments', 'excluded'], false); + 'testing/test_package', ['css', 'code_in_comments', 'excluded']); testPackageGraphGinormous = await bootBasicPackage( - 'testing/test_package', ['css', 'code_in_commnets', 'excluded'], true); + 'testing/test_package', ['css', 'code_in_commnets', 'excluded'], + withAutoIncludedDependencies: true); testPackageGraphSmall = - await bootBasicPackage('testing/test_package_small', [], false); + await bootBasicPackage('testing/test_package_small', []); testPackageGraphSdk = await bootSdkPackage(); } Future bootSdkPackage() { Directory dir = new Directory(pathLib.current); return new PackageBuilder( - dir, [], [], sdkDir, sdkPackageMeta, [], [], true, false) + new DartDocConfig.fromParameters( + inputDir: dir, + sdkDir: sdkDir, + ), + sdkPackageMeta) .buildPackageGraph(); } Future bootBasicPackage( - String dirPath, List excludes, bool withAutoIncludedDependencies) { + String dirPath, List excludeLibraries, + {bool withAutoIncludedDependencies = false, bool withCrossdart = false}) { Directory dir = new Directory(dirPath); return new PackageBuilder( - dir, - excludes, - [], - sdkDir, - new PackageMeta.fromDir(new Directory(dirPath)), - [], - [], - true, - withAutoIncludedDependencies) + new DartDocConfig.fromParameters( + inputDir: dir, + sdkDir: sdkDir, + excludeLibraries: excludeLibraries, + addCrossdart: withCrossdart, + autoIncludeDependencies: withAutoIncludedDependencies), + new PackageMeta.fromDir(new Directory(dirPath))) .buildPackageGraph(); }