Skip to content

Commit 44dfb15

Browse files
authored
Add support for a dartdoc_options.yaml. (#1638)
* Fix or disable miscellaneous lints in dartdoc * Clean up a few more lints. * Rename category to package in all remaining references * dartfmt * Review comments * Intermediate state * basic dartdoc options now working * Fix test failure (accidentally caching config info) * dartfmt * dartfmt * one last rename * Remove overly complicated config inheritance; we can add it back if we truly need this * dartfmt * Rename path/p import directive to pathLib everywhere. * dartfmt
1 parent 351142f commit 44dfb15

20 files changed

+435
-154
lines changed

bin/dartdoc.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import 'package:args/args.dart';
1616
import 'package:dartdoc/dartdoc.dart';
1717
import 'package:dartdoc/src/logging.dart';
1818
import 'package:logging/logging.dart' as logging;
19-
import 'package:path/path.dart' as path;
19+
import 'package:path/path.dart' as pathLib;
2020
import 'package:stack_trace/stack_trace.dart';
2121

2222
/// Analyzes Dart files and generates a representation of included libraries,
@@ -112,7 +112,7 @@ main(List<String> arguments) async {
112112
}
113113

114114
Directory outputDir =
115-
new Directory(path.join(Directory.current.path, defaultOutDir));
115+
new Directory(pathLib.join(Directory.current.path, defaultOutDir));
116116
if (args['output'] != null) {
117117
outputDir = new Directory(_resolveTildePath(args['output']));
118118
}
@@ -421,10 +421,10 @@ String _resolveTildePath(String originalPath) {
421421
String homeDir;
422422

423423
if (Platform.isWindows) {
424-
homeDir = path.absolute(Platform.environment['USERPROFILE']);
424+
homeDir = pathLib.absolute(Platform.environment['USERPROFILE']);
425425
} else {
426-
homeDir = path.absolute(Platform.environment['HOME']);
426+
homeDir = pathLib.absolute(Platform.environment['HOME']);
427427
}
428428

429-
return path.join(homeDir, originalPath.substring(2));
429+
return pathLib.join(homeDir, originalPath.substring(2));
430430
}

lib/dartdoc.dart

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import 'package:analyzer/src/generated/source.dart';
1616
import 'package:dartdoc/src/utils.dart';
1717
import 'package:html/dom.dart' show Element, Document;
1818
import 'package:html/parser.dart' show parse;
19-
import 'package:path/path.dart' as path;
19+
import 'package:path/path.dart' as pathLib;
2020

2121
import 'package:tuple/tuple.dart';
2222
import 'src/config.dart';
@@ -38,7 +38,7 @@ const String name = 'dartdoc';
3838
// Update when pubspec version changes.
3939
const String version = '0.17.1+1';
4040

41-
final String defaultOutDir = path.join('doc', 'api');
41+
final String defaultOutDir = pathLib.join('doc', 'api');
4242

4343
/// Initialize and setup the generators.
4444
Future<List<Generator>> initGenerators(String url, String relCanonicalPrefix,
@@ -169,7 +169,7 @@ class DartDoc extends PackageBuilder {
169169

170170
for (var generator in generators) {
171171
await generator.generate(packageGraph, outputDir.path);
172-
writtenFiles.addAll(generator.writtenFiles.map(path.normalize));
172+
writtenFiles.addAll(generator.writtenFiles.map(pathLib.normalize));
173173
}
174174
if (config.validateLinks) validateLinks(packageGraph, outputDir.path);
175175
int warnings = packageGraph.packageWarningCounter.warningCount;
@@ -209,12 +209,12 @@ class DartDoc extends PackageBuilder {
209209
Set<Warnable> warnOnElements;
210210

211211
// Make all paths relative to origin.
212-
if (path.isWithin(origin, warnOn)) {
213-
warnOn = path.relative(warnOn, from: origin);
212+
if (pathLib.isWithin(origin, warnOn)) {
213+
warnOn = pathLib.relative(warnOn, from: origin);
214214
}
215215
if (referredFrom != null) {
216-
if (path.isWithin(origin, referredFrom)) {
217-
referredFrom = path.relative(referredFrom, from: origin);
216+
if (pathLib.isWithin(origin, referredFrom)) {
217+
referredFrom = pathLib.relative(referredFrom, from: origin);
218218
}
219219
// Source paths are always relative.
220220
if (_hrefs[referredFrom] != null) {
@@ -245,13 +245,13 @@ class DartDoc extends PackageBuilder {
245245

246246
void _doOrphanCheck(
247247
PackageGraph packageGraph, String origin, Set<String> visited) {
248-
String normalOrigin = path.normalize(origin);
249-
String staticAssets = path.joinAll([normalOrigin, 'static-assets', '']);
250-
String indexJson = path.joinAll([normalOrigin, 'index.json']);
248+
String normalOrigin = pathLib.normalize(origin);
249+
String staticAssets = pathLib.joinAll([normalOrigin, 'static-assets', '']);
250+
String indexJson = pathLib.joinAll([normalOrigin, 'index.json']);
251251
bool foundIndexJson = false;
252252
for (FileSystemEntity f
253253
in new Directory(normalOrigin).listSync(recursive: true)) {
254-
var fullPath = path.normalize(f.path);
254+
var fullPath = pathLib.normalize(f.path);
255255
if (f is Directory) {
256256
continue;
257257
}
@@ -304,8 +304,8 @@ class DartDoc extends PackageBuilder {
304304

305305
void _doSearchIndexCheck(
306306
PackageGraph packageGraph, String origin, Set<String> visited) {
307-
String fullPath = path.joinAll([origin, 'index.json']);
308-
String indexPath = path.joinAll([origin, 'index.html']);
307+
String fullPath = pathLib.joinAll([origin, 'index.json']);
308+
String indexPath = pathLib.joinAll([origin, 'index.html']);
309309
File file = new File("$fullPath");
310310
if (!file.existsSync()) {
311311
return null;
@@ -320,10 +320,10 @@ class DartDoc extends PackageBuilder {
320320
found.add(indexPath);
321321
for (Map<String, String> entry in jsonData) {
322322
if (entry.containsKey('href')) {
323-
String entryPath = path.joinAll([origin, entry['href']]);
323+
String entryPath = pathLib.joinAll([origin, entry['href']]);
324324
if (!visited.contains(entryPath)) {
325325
_warn(packageGraph, PackageWarning.brokenLink, entryPath,
326-
path.normalize(origin),
326+
pathLib.normalize(origin),
327327
referredFrom: fullPath);
328328
}
329329
found.add(entryPath);
@@ -333,7 +333,7 @@ class DartDoc extends PackageBuilder {
333333
Set<String> missing_from_search = visited.difference(found);
334334
for (String s in missing_from_search) {
335335
_warn(packageGraph, PackageWarning.missingFromSearchIndex, s,
336-
path.normalize(origin),
336+
pathLib.normalize(origin),
337337
referredFrom: fullPath);
338338
}
339339
}
@@ -342,14 +342,14 @@ class DartDoc extends PackageBuilder {
342342
String pathToCheck,
343343
[String source, String fullPath]) {
344344
if (fullPath == null) {
345-
fullPath = path.joinAll([origin, pathToCheck]);
346-
fullPath = path.normalize(fullPath);
345+
fullPath = pathLib.joinAll([origin, pathToCheck]);
346+
fullPath = pathLib.normalize(fullPath);
347347
}
348348

349349
Tuple2 stringLinksAndHref = _getStringLinksAndHref(fullPath);
350350
if (stringLinksAndHref == null) {
351351
_warn(packageGraph, PackageWarning.brokenLink, pathToCheck,
352-
path.normalize(origin),
352+
pathLib.normalize(origin),
353353
referredFrom: source);
354354
_onCheckProgress.add(pathToCheck);
355355
// Remove so that we properly count that the file doesn't exist for
@@ -376,13 +376,13 @@ class DartDoc extends PackageBuilder {
376376
if (uri == null || !uri.hasAuthority && !uri.hasFragment) {
377377
var full;
378378
if (baseHref != null) {
379-
full = '${path.dirname(pathToCheck)}/$baseHref/$href';
379+
full = '${pathLib.dirname(pathToCheck)}/$baseHref/$href';
380380
} else {
381-
full = '${path.dirname(pathToCheck)}/$href';
381+
full = '${pathLib.dirname(pathToCheck)}/$href';
382382
}
383-
var newPathToCheck = path.normalize(full);
384-
String newFullPath = path.joinAll([origin, newPathToCheck]);
385-
newFullPath = path.normalize(newFullPath);
383+
var newPathToCheck = pathLib.normalize(full);
384+
String newFullPath = pathLib.joinAll([origin, newPathToCheck]);
385+
newFullPath = pathLib.normalize(newFullPath);
386386
if (!visited.contains(newFullPath)) {
387387
toVisit.add(new Tuple2(newPathToCheck, newFullPath));
388388
visited.add(newFullPath);

lib/src/config.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,38 @@ library dartdoc.config;
66

77
import 'dart:io';
88

9+
import 'package:analyzer/dart/element/element.dart';
10+
import 'package:dartdoc/dartdoc.dart';
11+
import 'package:path/path.dart' as pathLib;
12+
13+
import 'model.dart';
14+
15+
/// Class representing values possibly local to a particular [ModelElement].
16+
class LocalConfig {
17+
final Map<String, Set<String>> categoryMap;
18+
final PackageMeta packageMeta;
19+
20+
LocalConfig._(this.categoryMap, this.packageMeta);
21+
22+
factory LocalConfig.fromLibrary(LibraryElement element) {
23+
return new LocalConfig._({}, getPackageMeta(element));
24+
}
25+
26+
static PackageMeta getPackageMeta(LibraryElement element) {
27+
String sourcePath = element.source.fullName;
28+
File file = new File(pathLib.canonicalize(sourcePath));
29+
Directory dir = file.parent;
30+
while (dir.parent.path != dir.path && dir.existsSync()) {
31+
File pubspec = new File(pathLib.join(dir.path, 'pubspec.yaml'));
32+
if (pubspec.existsSync()) {
33+
return new PackageMeta.fromDir(dir);
34+
}
35+
dir = dir.parent;
36+
}
37+
return null;
38+
}
39+
}
40+
941
class Config {
1042
final Directory inputDir;
1143
final bool showWarnings;

lib/src/dartdoc_options.dart

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
///
6+
/// dartdoc's dartdoc_options.yaml configuration file follows similar loading
7+
/// semantics to that of analysis_options.yaml,
8+
/// [documented here](https://www.dartlang.org/guides/language/analysis-options).
9+
/// It searches parent directories until it finds an analysis_options.yaml file,
10+
/// and uses built-in defaults if one is not found.
11+
///
12+
library dartdoc.dartdoc_options;
13+
14+
import 'dart:io';
15+
16+
import 'package:path/path.dart' as pathLib;
17+
import 'package:yaml/yaml.dart';
18+
19+
import 'logging.dart';
20+
21+
final Map<String, DartdocOptions> _dartdocOptionsCache = {};
22+
23+
abstract class DartdocOptions {
24+
DartdocOptions();
25+
26+
/// Path to the dartdoc options file, or '<default>' if this object is the
27+
/// default setting. Intended for printing only.
28+
String get _path;
29+
30+
/// A list indicating the preferred subcategory sorting order.
31+
List<String> get categoryOrder;
32+
33+
factory DartdocOptions.fromDir(Directory dir) {
34+
if (!_dartdocOptionsCache.containsKey(dir.absolute.path)) {
35+
_dartdocOptionsCache[dir.absolute.path] =
36+
new DartdocOptions._fromDir(dir);
37+
}
38+
return _dartdocOptionsCache[dir.absolute.path];
39+
}
40+
41+
/// Search for a dartdoc_options file in this and parent directories.
42+
factory DartdocOptions._fromDir(Directory dir) {
43+
if (!dir.existsSync()) return new _DefaultDartdocOptions();
44+
45+
File f;
46+
dir = dir.absolute;
47+
48+
while (true) {
49+
f = new File(pathLib.join(dir.path, 'dartdoc_options.yaml'));
50+
if (f.existsSync() || dir.parent.path == dir.path) break;
51+
dir = dir.parent.absolute;
52+
}
53+
54+
DartdocOptions parent;
55+
if (dir.parent.path != dir.path) {
56+
parent = new DartdocOptions.fromDir(dir.parent);
57+
} else {
58+
parent = new _DefaultDartdocOptions();
59+
}
60+
if (f.existsSync()) {
61+
return new _FileDartdocOptions(f);
62+
}
63+
return parent;
64+
}
65+
}
66+
67+
class _DefaultDartdocOptions extends DartdocOptions {
68+
_DefaultDartdocOptions() : super();
69+
70+
@override
71+
String get _path => '<default>';
72+
73+
@override
74+
List<String> get categoryOrder => new List.unmodifiable([]);
75+
}
76+
77+
class _FileDartdocOptions extends DartdocOptions {
78+
File dartdocOptionsFile;
79+
Map _dartdocOptions;
80+
_FileDartdocOptions(this.dartdocOptionsFile) : super() {
81+
Map allDartdocOptions = loadYaml(dartdocOptionsFile.readAsStringSync());
82+
if (allDartdocOptions.containsKey('dartdoc')) {
83+
_dartdocOptions = allDartdocOptions['dartdoc'];
84+
} else {
85+
_dartdocOptions = {};
86+
logWarning("${_path}: must contain 'dartdoc' section");
87+
}
88+
}
89+
90+
@override
91+
String get _path => dartdocOptionsFile.path;
92+
93+
List<String> _categoryOrder;
94+
@override
95+
List<String> get categoryOrder {
96+
if (_categoryOrder == null) {
97+
_categoryOrder = [];
98+
if (_dartdocOptions.containsKey('categoryOrder')) {
99+
if (_dartdocOptions['categoryOrder'] is YamlList) {
100+
_categoryOrder.addAll(_dartdocOptions['categoryOrder']);
101+
} else {
102+
logWarning("${_path}: categoryOrder must be a list (ignoring)");
103+
}
104+
}
105+
_categoryOrder = new List.unmodifiable(_categoryOrder);
106+
}
107+
return _categoryOrder;
108+
}
109+
}

lib/src/html/html_generator.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ library dartdoc.html_generator;
77
import 'dart:async' show Future, StreamController, Stream;
88
import 'dart:io' show File;
99

10-
import 'package:path/path.dart' as p;
10+
import 'package:path/path.dart' as pathLib;
1111

1212
import '../generator.dart';
1313
import '../model.dart';
@@ -82,7 +82,7 @@ class HtmlGenerator extends Generator {
8282
// docs somehow. Check data.self.isCanonical and callers for bugs.
8383
assert(allowOverwrite || !writtenFiles.contains(filePath));
8484

85-
var file = new File(p.join(outputDirectoryPath, filePath));
85+
var file = new File(pathLib.join(outputDirectoryPath, filePath));
8686
var parent = file.parent;
8787
if (!parent.existsSync()) {
8888
parent.createSync(recursive: true);

0 commit comments

Comments
 (0)