Skip to content

Commit 99e2e24

Browse files
authored
Dartdoc customization (#1005)
* Customization skeleton. * Use html parsing in customization. * Rewrite breadcrumbs: always include a link to the pub package page. * Add pub logo in front of breadcrumbs. * Customize output directory.
1 parent dc0f5e8 commit 99e2e24

13 files changed

+1740
-0
lines changed

app/lib/dartdoc/customization.dart

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2018, 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+
import 'dart:async';
6+
import 'dart:io';
7+
8+
import 'package:html/dom.dart';
9+
import 'package:html/parser.dart' as html_parser;
10+
11+
class DartdocCustomizer {
12+
final String packageName;
13+
final String packageVersion;
14+
15+
DartdocCustomizer(this.packageName, this.packageVersion);
16+
17+
Future<bool> customizeDir(String path) async {
18+
bool changed = false;
19+
final dir = new Directory(path);
20+
await for (var fse in dir.list(recursive: true)) {
21+
if (fse is File && fse.path.endsWith('.html')) {
22+
final c = await customizeFile(fse);
23+
changed = changed || c;
24+
}
25+
}
26+
return changed;
27+
}
28+
29+
Future<bool> customizeFile(File file) async {
30+
final String oldContent = await file.readAsString();
31+
final String newContent = customizeHtml(oldContent);
32+
if (newContent != null && oldContent != newContent) {
33+
await file.writeAsString(newContent);
34+
return true;
35+
} else {
36+
return false;
37+
}
38+
}
39+
40+
String customizeHtml(String html) {
41+
final doc = html_parser.parse(html);
42+
final breadcrumbs = doc.body.querySelector('.breadcrumbs');
43+
if (breadcrumbs != null) {
44+
_addPubSiteLogo(breadcrumbs);
45+
_addPubPackageLink(breadcrumbs);
46+
}
47+
return doc.outerHtml;
48+
}
49+
50+
void _addPubSiteLogo(Element breadcrumbs) {
51+
final parent = breadcrumbs.parent;
52+
final logoLink = new Element.tag('a');
53+
logoLink.attributes['href'] = 'https://pub.dartlang.org/';
54+
final imgRef = new Element.tag('img');
55+
imgRef.attributes['src'] =
56+
'https://pub.dartlang.org/static/img/dart-logo.svg';
57+
imgRef.attributes['style'] = 'height: 30px; margin-right: 1em;';
58+
logoLink.append(imgRef);
59+
parent.insertBefore(logoLink, breadcrumbs);
60+
parent.insertBefore(new Text('\n '), breadcrumbs);
61+
}
62+
63+
void _addPubPackageLink(Element breadcrumbs) {
64+
final pubPackageLink =
65+
'https://pub.dartlang.org/packages/$packageName/versions/$packageVersion';
66+
final pubPackageText = '$packageName package';
67+
if (breadcrumbs.children.length == 1) {
68+
// we are on the index page
69+
final firstLink = breadcrumbs.querySelector('a');
70+
firstLink.attributes['href'] = pubPackageLink;
71+
firstLink.text = pubPackageText;
72+
} else if (breadcrumbs.children.isNotEmpty) {
73+
// we are inside
74+
final firstLink = breadcrumbs.querySelector('a');
75+
firstLink.text = 'documentation';
76+
77+
final lead = new Element.tag('li');
78+
final leadLink = new Element.tag('a');
79+
leadLink.attributes['href'] = pubPackageLink;
80+
leadLink.text = pubPackageText;
81+
lead.append(leadLink);
82+
83+
breadcrumbs.insertBefore(lead, breadcrumbs.firstChild);
84+
breadcrumbs.insertBefore(new Text('\n '), breadcrumbs.firstChild);
85+
}
86+
}
87+
}

app/lib/dartdoc/dartdoc_runner.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import '../shared/utils.dart' show redirectDartdocPages;
1717
import '../shared/versions.dart';
1818

1919
import 'backend.dart';
20+
import 'customization.dart';
2021
import 'models.dart';
2122

2223
final Logger _logger = new Logger('pub.dartdoc.runner');
@@ -66,6 +67,9 @@ class DartdocRunner implements TaskRunner {
6667
final dartdocEnv = {'PUB_CACHE': pubCacheDir};
6768
final entry = await _generateDocs(task, pkgPath, outputDir, dartdocEnv);
6869

70+
await new DartdocCustomizer(task.package, task.version)
71+
.customizeDir(outputDir);
72+
6973
if (entry.hasContent) {
7074
await dartdocBackend.uploadDir(entry, outputDir);
7175
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) 2018, 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+
import 'dart:io';
6+
7+
import 'package:html/parser.dart';
8+
import 'package:test/test.dart';
9+
10+
import 'package:pub_dartlang_org/dartdoc/customization.dart';
11+
12+
const String goldenDir = 'test/dartdoc/golden';
13+
14+
final _regenerateGoldens = false;
15+
16+
void main() {
17+
void expectGoldenFile(String content, String fileName) {
18+
// Making sure it is valid HTML
19+
final htmlParser = new HtmlParser(content, strict: true);
20+
htmlParser.parse();
21+
22+
if (_regenerateGoldens) {
23+
new File('$goldenDir/$fileName').writeAsStringSync(content);
24+
fail('Set `_regenerateGoldens` to `false` to run tests.');
25+
}
26+
final golden = new File('$goldenDir/$fileName').readAsStringSync();
27+
expect(content.split('\n'), golden.split('\n'));
28+
}
29+
30+
group('pana 0.10.2', () {
31+
final customization = new DartdocCustomizer('pana', '0.10.2');
32+
33+
void expectMatch(String name) {
34+
test(name, () {
35+
final inputName = 'pana_0.10.2_$name.html';
36+
final outputName = 'pana_0.10.2_$name.out.html';
37+
final html = new File('$goldenDir/$inputName').readAsStringSync();
38+
final result = customization.customizeHtml(html) ?? html;
39+
expectGoldenFile(result, outputName);
40+
});
41+
}
42+
43+
expectMatch('index');
44+
expectMatch('license_file_class');
45+
expectMatch('license_file_constructor');
46+
expectMatch('license_file_name_field');
47+
expectMatch('pretty_json');
48+
});
49+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<meta name="generator" content="made with love by dartdoc 0.16.0">
8+
<meta name="description" content="pana API docs, for the Dart programming language.">
9+
<title>pana - Dart API docs</title>
10+
<link rel="canonical" href="https://www.dartdocs.org/documentation/pana/0.10.2/index.html">
11+
12+
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500,400i,400,300|Source+Sans+Pro:400,300,700" rel="stylesheet">
13+
<link rel="stylesheet" href="static-assets/github.css">
14+
<link rel="stylesheet" href="static-assets/styles.css">
15+
<link rel="icon" href="static-assets/favicon.png">
16+
17+
</head>
18+
19+
<body>
20+
21+
<div id="overlay-under-drawer"></div>
22+
23+
<header id="title">
24+
<ol class="breadcrumbs gt-separated dark hidden-xs">
25+
<li><a href="https://github.com/dart-lang/pana">pana package</a></li>
26+
</ol>
27+
<div class="self-name">pana</div>
28+
<form class="search navbar-right" role="search">
29+
<input type="text" id="search-box" autocomplete="off" disabled class="form-control typeahead" placeholder="Loading search...">
30+
</form>
31+
</header>
32+
33+
<main>
34+
35+
<div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
36+
<h5>pana package</h5>
37+
38+
39+
<ol>
40+
<li class="section-title"><a href="index.html#libraries">Libraries</a></li>
41+
<li><a href="pana/pana-library.html">pana</a></li>
42+
</ol>
43+
</div>
44+
45+
<div class="col-xs-12 col-sm-9 col-md-8 main-content">
46+
<section class="desc markdown">
47+
<p><a href="https://travis-ci.org/dart-lang/pana"><img alt="Build Status" src="https://travis-ci.org/dart-lang/pana.svg?branch=master"></a></p>
48+
<p>A library for analyzing Dart packages.</p><ul><li>Validates the code using <a href="https://www.dartlang.org/tools/analyzer">Dart Analyzer</a>.</li><li>Checks code formatting.</li><li>Checks for outdated dependencies.</li><li>Infers supported platforms: Flutter, web, and/or server.</li></ul>
49+
<p>Used by the <a href="https://pub.dartlang.org/">Dart Package site</a>.</p>
50+
<h2>Use as an executable</h2>
51+
<h3>Installation</h3>
52+
<pre class="language-console"><code class="language-console">&gt; pub global activate pana
53+
</code></pre>
54+
<h3>Usage</h3>
55+
<p>You can specify either a package (+ version) or a local directory to analyze:</p>
56+
<pre class="language-dart"><code>Usage: pana [&lt;options&gt;] &lt;package&gt; [&lt;version&gt;]
57+
pana [&lt;options&gt;] --source path &lt;directory&gt;
58+
59+
Options:
60+
-j, --json Output log items as JSON.
61+
-s, --source The source used to find the package.
62+
[hosted (default), path]
63+
64+
--hosted-url The server that hosts &lt;package&gt;.
65+
(defaults to "https://pub.dartlang.org")
66+
67+
--[no-]warning Shows the warning message before potentially destructive operation.
68+
(defaults to on)
69+
</code></pre>
70+
</section>
71+
72+
73+
<section class="summary" id="libraries">
74+
<h2>Libraries</h2>
75+
<dl>
76+
<dt id="pana">
77+
<span class="name"><a href="pana/pana-library.html">pana</a></span>
78+
</dt>
79+
<dd>
80+
81+
</dd>
82+
</dl>
83+
</section>
84+
85+
</div> <!-- /.main-content -->
86+
87+
</main>
88+
89+
<footer>
90+
<span class="no-break">
91+
pana 0.10.2
92+
</span>
93+
94+
</footer>
95+
96+
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
97+
<script src="static-assets/typeahead.bundle.min.js"></script>
98+
<script src="static-assets/highlight.pack.js"></script>
99+
<script src="static-assets/URI.js"></script>
100+
<script src="static-assets/script.js"></script>
101+
102+
103+
</body>
104+
105+
</html>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<!DOCTYPE html><html lang="en"><head>
2+
<meta charset="utf-8">
3+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
4+
<meta name="viewport" content="width=device-width, initial-scale=1">
5+
<meta name="generator" content="made with love by dartdoc 0.16.0">
6+
<meta name="description" content="pana API docs, for the Dart programming language.">
7+
<title>pana - Dart API docs</title>
8+
<link rel="canonical" href="https://www.dartdocs.org/documentation/pana/0.10.2/index.html">
9+
10+
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500,400i,400,300|Source+Sans+Pro:400,300,700" rel="stylesheet">
11+
<link rel="stylesheet" href="static-assets/github.css">
12+
<link rel="stylesheet" href="static-assets/styles.css">
13+
<link rel="icon" href="static-assets/favicon.png">
14+
15+
</head>
16+
17+
<body>
18+
19+
<div id="overlay-under-drawer"></div>
20+
21+
<header id="title">
22+
<a href="https://pub.dartlang.org/"><img src="https://pub.dartlang.org/static/img/dart-logo.svg" style="height: 30px; margin-right: 1em;"></a>
23+
<ol class="breadcrumbs gt-separated dark hidden-xs">
24+
<li><a href="https://pub.dartlang.org/packages/pana/versions/0.10.2">pana package</a></li>
25+
</ol>
26+
<div class="self-name">pana</div>
27+
<form class="search navbar-right" role="search">
28+
<input type="text" id="search-box" autocomplete="off" disabled="" class="form-control typeahead" placeholder="Loading search...">
29+
</form>
30+
</header>
31+
32+
<main>
33+
34+
<div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
35+
<h5>pana package</h5>
36+
37+
38+
<ol>
39+
<li class="section-title"><a href="index.html#libraries">Libraries</a></li>
40+
<li><a href="pana/pana-library.html">pana</a></li>
41+
</ol>
42+
</div>
43+
44+
<div class="col-xs-12 col-sm-9 col-md-8 main-content">
45+
<section class="desc markdown">
46+
<p><a href="https://travis-ci.org/dart-lang/pana"><img alt="Build Status" src="https://travis-ci.org/dart-lang/pana.svg?branch=master"></a></p>
47+
<p>A library for analyzing Dart packages.</p><ul><li>Validates the code using <a href="https://www.dartlang.org/tools/analyzer">Dart Analyzer</a>.</li><li>Checks code formatting.</li><li>Checks for outdated dependencies.</li><li>Infers supported platforms: Flutter, web, and/or server.</li></ul>
48+
<p>Used by the <a href="https://pub.dartlang.org/">Dart Package site</a>.</p>
49+
<h2>Use as an executable</h2>
50+
<h3>Installation</h3>
51+
<pre class="language-console"><code class="language-console">&gt; pub global activate pana
52+
</code></pre>
53+
<h3>Usage</h3>
54+
<p>You can specify either a package (+ version) or a local directory to analyze:</p>
55+
<pre class="language-dart"><code>Usage: pana [&lt;options&gt;] &lt;package&gt; [&lt;version&gt;]
56+
pana [&lt;options&gt;] --source path &lt;directory&gt;
57+
58+
Options:
59+
-j, --json Output log items as JSON.
60+
-s, --source The source used to find the package.
61+
[hosted (default), path]
62+
63+
--hosted-url The server that hosts &lt;package&gt;.
64+
(defaults to "https://pub.dartlang.org")
65+
66+
--[no-]warning Shows the warning message before potentially destructive operation.
67+
(defaults to on)
68+
</code></pre>
69+
</section>
70+
71+
72+
<section class="summary" id="libraries">
73+
<h2>Libraries</h2>
74+
<dl>
75+
<dt id="pana">
76+
<span class="name"><a href="pana/pana-library.html">pana</a></span>
77+
</dt>
78+
<dd>
79+
80+
</dd>
81+
</dl>
82+
</section>
83+
84+
</div> <!-- /.main-content -->
85+
86+
</main>
87+
88+
<footer>
89+
<span class="no-break">
90+
pana 0.10.2
91+
</span>
92+
93+
</footer>
94+
95+
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
96+
<script src="static-assets/typeahead.bundle.min.js"></script>
97+
<script src="static-assets/highlight.pack.js"></script>
98+
<script src="static-assets/URI.js"></script>
99+
<script src="static-assets/script.js"></script>
100+
101+
102+
103+
104+
105+
</body></html>

0 commit comments

Comments
 (0)