Implement basic categorization for libraries in dartdoc (#1641)

* Squash changes

* Update README with usage for categories.

* review comments
diff --git a/README.md b/README.md
index 2291413..4dd7677 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,34 @@
 
 ## Advanced features
 
+### dartdoc_options.yaml
+
+Creating a file named dartdoc_options.yaml at the top of your package can change how Dartdoc
+generates docs.  
+
+```yaml
+dartdoc:
+  categoryOrder: ["First Category", "Second Category"]
+
+```
+For now, there's only one option:
+
+  * **categoryOrder**:  Specify the order of categories, below, for display in the sidebar and
+    the package page.
+  
+### Categories
+
+You can tag libraries in their documentation with the string `{@category YourCategory}`, and
+that will cause the library to appear in a category when showing the sidebar on the Package
+and Library pages.
+
+```dart
+/// Here is my library.
+/// 
+/// {@category Amazing}
+library my_library;
+```
+
 ### Macros
 
 You can specify "macros", i.e. reusable pieces of documentation. For that, first specify a template
diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart
index b8d06d5..459049f 100644
--- a/bin/dartdoc.dart
+++ b/bin/dartdoc.dart
@@ -192,7 +192,8 @@
   PackageMeta packageMeta = new PackageMeta.fromDir(inputDir);
 
   if (packageMeta == null) {
-    stderr.writeln(' fatal error: Unable to generate documentation: no pubspec.yaml found');
+    stderr.writeln(
+        ' fatal error: Unable to generate documentation: no pubspec.yaml found');
     exit(1);
   }
 
@@ -212,7 +213,6 @@
     }
   }
 
-
   logInfo("Generating documentation for '${packageMeta}' into "
       "${outputDir.absolute.path}${Platform.pathSeparator}");
 
@@ -221,7 +221,6 @@
       footerFilePaths: footerFilePaths,
       footerTextFilePaths: footerTextFilePaths,
       faviconPath: args['favicon'],
-      displayAsPackages: args['use-categories'],
       prettyIndexJson: args['pretty-index-json']);
 
   for (var generator in generators) {
@@ -311,10 +310,8 @@
   parser.addFlag('show-progress',
       help: 'Display progress indications to console stdout', negatable: false);
   parser.addOption('sdk-readme',
-      help:
-          'Path to the SDK description file.  Deprecated (ignored)');
-  parser.addOption('input',
-      help: 'Path to source directory.');
+      help: 'Path to the SDK description file.  Deprecated (ignored)');
+  parser.addOption('input', help: 'Path to source directory.');
   parser.addOption('output',
       help: 'Path to output directory.', defaultsTo: defaultOutDir);
   parser.addMultiOption('header',
@@ -349,22 +346,18 @@
       help: 'A path to a favicon for the generated docs.');
   parser.addFlag('use-categories',
       help:
-          'Group libraries from the same package in the libraries sidebar. (deprecated, replaced by display-as-packages)',
-      negatable: false,
-      defaultsTo: false);
-  parser.addFlag('display-as-packages',
-      help: 'Group libraries from the same package in the libraries sidebar.',
+          'Group libraries from the same package in the libraries sidebar. (deprecated, ignored)',
       negatable: false,
       defaultsTo: false);
   parser.addMultiOption('category-order',
       help:
-          'A list of package names to place first when --display-as-packages is '
-          'set.  Unmentioned categories are sorted after these. (deprecated, replaced by package-order)',
+          '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.addMultiOption('package-order',
       help:
-          'A list of package names to place first when --display-as-packages is '
-          'set.  Unmentioned categories are sorted after these.',
+          'A list of package names to place first when grouping libraries in packages. '
+          'Unmentioned categories are sorted after these.',
       splitCommas: true);
   parser.addFlag('auto-include-dependencies',
       help:
diff --git a/lib/dartdoc.dart b/lib/dartdoc.dart
index 6c169c6..bdacf91 100644
--- a/lib/dartdoc.dart
+++ b/lib/dartdoc.dart
@@ -46,14 +46,12 @@
     List<String> footerFilePaths,
     List<String> footerTextFilePaths,
     String faviconPath,
-    bool displayAsPackages: false,
     bool prettyIndexJson: false}) async {
   var options = new HtmlGeneratorOptions(
       url: url,
       relCanonicalPrefix: relCanonicalPrefix,
       toolVersion: version,
       faviconPath: faviconPath,
-      displayAsPackages: displayAsPackages,
       prettyIndexJson: prettyIndexJson);
 
   return [
diff --git a/lib/resources/styles.css b/lib/resources/styles.css
index bd1fc4e..ade56f4 100644
--- a/lib/resources/styles.css
+++ b/lib/resources/styles.css
@@ -630,6 +630,19 @@
   padding-top: 25px;
 }
 
+.sidebar ol li.section-subtitle a {
+  color: inherit;
+}
+
+.sidebar ol li.section-subtitle {
+  font-weight: 400;
+  text-transform: uppercase;
+}
+
+.sidebar ol li.section-subitem {
+  margin-left: 12px;
+}
+
 .sidebar ol li:first-child {
   padding-top: 0;
   margin-top: 0;
diff --git a/lib/src/html/html_generator.dart b/lib/src/html/html_generator.dart
index 012eda0..4febcc2 100644
--- a/lib/src/html/html_generator.dart
+++ b/lib/src/html/html_generator.dart
@@ -116,9 +116,6 @@
   final bool prettyIndexJson;
 
   @override
-  final bool displayAsPackages;
-
-  @override
   final String relCanonicalPrefix;
 
   @override
@@ -129,7 +126,6 @@
       this.relCanonicalPrefix,
       this.faviconPath,
       String toolVersion,
-      this.displayAsPackages: false,
       this.prettyIndexJson: false})
       : this.toolVersion = toolVersion ?? 'unknown';
 }
diff --git a/lib/src/html/template_data.dart b/lib/src/html/template_data.dart
index badb39a..02134f0 100644
--- a/lib/src/html/template_data.dart
+++ b/lib/src/html/template_data.dart
@@ -7,7 +7,6 @@
 abstract class HtmlOptions {
   String get relCanonicalPrefix;
   String get toolVersion;
-  bool get displayAsPackages;
 }
 
 class Subnav {
@@ -63,7 +62,6 @@
   T get self;
   String get version => htmlOptions.toolVersion;
   String get relCanonicalPrefix => htmlOptions.relCanonicalPrefix;
-  bool get displayAsPackages => htmlOptions.displayAsPackages;
 
   Iterable<Subnav> getSubNavItems() => <Subnav>[];
 
@@ -113,7 +111,7 @@
   String get homepage => packageGraph.homepage;
 
   @override
-  String get kind => (displayAsPackages || packageGraph.isSdk) ? '' : 'package';
+  String get kind => packageGraph.kind;
 
   /// `null` for packages because they are at the root – not needed
   @override
diff --git a/lib/src/html/templates.dart b/lib/src/html/templates.dart
index d84e4d6..446edcf 100644
--- a/lib/src/html/templates.dart
+++ b/lib/src/html/templates.dart
@@ -20,6 +20,8 @@
   'constant',
   'footer',
   'head',
+  'library',
+  'packages',
   'property',
   'features',
   'documentation',
diff --git a/lib/src/model.dart b/lib/src/model.dart
index a1d0279..1be1c5e 100644
--- a/lib/src/model.dart
+++ b/lib/src/model.dart
@@ -1172,6 +1172,34 @@
   bool get isDocumented;
 }
 
+/// Mixin implementing dartdoc categorization for ModelElements.
+abstract class Categorization implements ModelElement {
+  @override
+  String _buildDocumentationLocal() {
+    _rawDocs = super._buildDocumentationLocal();
+    _rawDocs = _stripAndSetDartdocCategory(_rawDocs);
+    return _rawDocs;
+  }
+
+  /// Parse {@category ...} in API comments and store the category in
+  /// the [_categoryName] variable.
+  String _stripAndSetDartdocCategory(String rawDocs) {
+    final categoryRegexp =
+        new RegExp(r'[ ]*{@category (.+?)}[ ]*\n?', multiLine: true);
+    return rawDocs.replaceAllMapped(categoryRegexp, (match) {
+      _categoryName = match[1].trim();
+      return '';
+    });
+  }
+
+  String _categoryName;
+  String get categoryName {
+    // TODO(jcollins-g): avoid side-effect dependency
+    if (_categoryName == null) documentationLocal;
+    return _categoryName;
+  }
+}
+
 /// Classes extending this class have canonicalization support in Dartdoc.
 abstract class Canonicalization extends Object
     with Locatable
@@ -1698,7 +1726,7 @@
   Accessor get setter;
 }
 
-class Library extends ModelElement {
+class Library extends ModelElement with Categorization {
   @override
   final PackageGraph packageGraph;
 
@@ -2174,9 +2202,10 @@
     return name;
   }
 
-  static PackageMeta getPackageMeta(LibraryElement element) {
+  static PackageMeta getPackageMeta(Element element) {
     String sourcePath = element.source.fullName;
-    return new PackageMeta.fromDir(new File(pathLib.canonicalize(sourcePath)).parent);
+    return new PackageMeta.fromDir(
+        new File(pathLib.canonicalize(sourcePath)).parent);
   }
 
   static String getLibraryName(LibraryElement element) {
@@ -3728,8 +3757,6 @@
   String get typeName => 'operator';
 }
 
-// TODO(jcollins-g): Break [Package] out into a real single-package only
-// class, and a container class for a set of packages.
 class PackageGraph extends Canonicalization with Nameable, Warnable {
   // All library objects related to this package; a superset of _libraries.
   final Map<LibraryElement, Library> allLibraries = new Map();
@@ -4046,20 +4073,27 @@
     return locatable.fullyQualifiedName.replaceFirst(':', '-');
   }
 
+  bool get hasMultiplePackages => publicPackages.length > 1;
+
+  List<Package> _publicPackages;
   List<Package> get publicPackages {
-    List<Package> _publicPackages;
-    // Help the user if they pass us a package that doesn't exist.
-    for (String packageName in config.packageOrder) {
-      if (!packages.containsKey(packageName))
-        warnOnElement(null, PackageWarning.packageOrderGivesMissingPackageName,
-            message: "${packageName}, packages: ${packages.keys.join(',')}");
+    if (_publicPackages == null) {
+      // Help the user if they pass us a package that doesn't exist.
+      for (String packageName in config.packageOrder) {
+        if (!packages.containsKey(packageName))
+          warnOnElement(
+              null, PackageWarning.packageOrderGivesMissingPackageName,
+              message: "${packageName}, packages: ${packages.keys.join(',')}");
+      }
+      _publicPackages = packages.values.where((p) => p.isPublic).toList()
+        ..sort();
     }
-    _publicPackages = packages.values
-        .where((p) => p.libraries.any((l) => l.isPublic))
-        .toList();
-    return _publicPackages..sort();
+    return _publicPackages;
   }
 
+  // Use only in testing.
+  void resetPublicPackages() => _publicPackages = null;
+
   Map<LibraryElement, Set<Library>> _libraryElementReexportedBy = new Map();
   void _tagReexportsFor(
       final Library tll, final LibraryElement libraryElement) {
@@ -4183,8 +4217,7 @@
   @override
   String get name => packageMeta.name;
 
-  String get kind =>
-      (packageGraph.isSdk) ? 'SDK' : 'package';
+  String get kind => (packageGraph.isSdk) ? 'SDK' : 'package';
 
   @override
   String get oneLineDoc => '';
@@ -4461,14 +4494,118 @@
   }
 }
 
-class Package implements Comparable<Package> {
-  final String name;
-
-  // Initialized by [PackageGraph.PackageGraph].
+/// 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 {
   final List<Library> _libraries = [];
-  PackageGraph packageGraph;
+  PackageGraph get packageGraph;
 
-  Package(this.name, this.packageGraph);
+  List<Library> get libraries => _libraries;
+  Iterable<Library> 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<Category> {
+  /// All libraries in [libraries] must come from [package].
+  Package package;
+  DartdocOptions dartdocOptions;
+  String _name;
+
+  Category(this._name, this.package, this.dartdocOptions);
+
+  @override
+  String get name => _name;
+
+  /// 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.
+  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;
+  }
+
+  @override
+  int compareTo(Category other) {
+    if (_group == other._group) {
+      if (_group == -1) {
+        return Comparable.compare(dartdocOptions.categoryOrder.indexOf(name),
+            dartdocOptions.categoryOrder.indexOf(other.name));
+      } else {
+        return name.toLowerCase().compareTo(other.name.toLowerCase());
+      }
+    }
+    return Comparable.compare(_group, other._group);
+  }
+
+  @override
+  PackageGraph get packageGraph => package.packageGraph;
+}
+
+/// A [LibraryContainer] that contains [Library] objects related to a particular
+/// package.
+class Package extends LibraryContainer implements Comparable<Package>, Privacy {
+  String _name;
+  PackageGraph _packageGraph;
+
+  final Map<String, Category> _nameToCategory = {};
+  Package(this._name, this._packageGraph);
+
+  /// Return true if the code has defined non-default categories for libraries
+  /// in this package.
+  bool get hasCategories => categories.isNotEmpty;
+
+  LibraryContainer get defaultCategory => nameToCategory[null];
+
+  bool _isPublic;
+  @override
+  bool get isPublic {
+    if (_isPublic == null) _isPublic = libraries.any((l) => l.isPublic);
+    return _isPublic;
+  }
+
+  @override
+  String get name => _name;
+
+  @override
+  PackageGraph get packageGraph => _packageGraph;
+
+  // Workaround for mustache4dart issue where templates do not recognize
+  // inherited properties as being in-context.
+  @override
+  List<Library> get publicLibraries => super.publicLibraries;
+
+  /// A map of category name to the category itself.
+  Map<String, Category> get nameToCategory {
+    if (_nameToCategory.isEmpty) {
+      _nameToCategory[null] = new Category(null, this, dartdocOptions);
+      for (Library lib in libraries) {
+        String category = lib.categoryName;
+        _nameToCategory.putIfAbsent(
+            category, () => new Category(category, this, dartdocOptions));
+        _nameToCategory[category]._libraries.add(lib);
+      }
+    }
+    return _nameToCategory;
+  }
+
+  List<LibraryContainer> _categories;
+  List<LibraryContainer> get categories {
+    if (_categories == null) {
+      _categories = nameToCategory.values.where((c) => c.name != null).toList()
+        ..sort();
+    }
+    return _categories;
+  }
 
   DartdocOptions _dartdocOptions;
   DartdocOptions get dartdocOptions {
@@ -4478,6 +4615,10 @@
     return _dartdocOptions;
   }
 
+  /// Is this the package at the top of the list?  We display the first
+  /// package specially (with "Libraries" rather than the package name).
+  bool get isFirstPackage => identical(packageGraph.publicPackages.first, this);
+
   bool get isSdk => packageMeta.isSdk;
 
   String _packagePath;
@@ -4503,10 +4644,6 @@
     return _packagePath;
   }
 
-  List<Library> get libraries => _libraries;
-
-  Iterable<Library> get publicLibraries => filterNonPublic(libraries);
-
   PackageMeta _packageMeta;
   // TODO(jcollins-g): packageMeta should be passed in with the object rather
   // than calculated indirectly from libraries.
diff --git a/lib/src/package_meta.dart b/lib/src/package_meta.dart
index 12562e4..d85bf26 100644
--- a/lib/src/package_meta.dart
+++ b/lib/src/package_meta.dart
@@ -12,7 +12,6 @@
 
 import 'logging.dart';
 
-
 Map<String, PackageMeta> _packageMetaCache = {};
 
 abstract class PackageMeta {
@@ -30,7 +29,8 @@
     if (!_packageMetaCache.containsKey(dir.path)) {
       PackageMeta packageMeta;
       // There are pubspec.yaml files inside the SDK.  Ignore them.
-      if (pathLib.isWithin(getSdkDir().absolute.path, dir.path) || getSdkDir().path == dir.path) {
+      if (pathLib.isWithin(getSdkDir().absolute.path, dir.path) ||
+          getSdkDir().path == dir.path) {
         packageMeta = new _SdkMeta(getSdkDir());
       } else {
         while (dir.existsSync()) {
@@ -178,7 +178,6 @@
     return _changelog;
   }
 
-
   /// Returns a list of reasons this package is invalid, or an
   /// empty list if no reasons found.
   @override
@@ -211,8 +210,7 @@
 class _SdkMeta extends PackageMeta {
   String sdkReadmePath;
 
-  _SdkMeta(Directory dir)
-      : super(dir) {
+  _SdkMeta(Directory dir) : super(dir) {
     sdkReadmePath = pathLib.join(dir.path, 'lib', 'api_readme.md');
   }
 
diff --git a/lib/templates/_library.html b/lib/templates/_library.html
new file mode 100644
index 0000000..6ef3a26
--- /dev/null
+++ b/lib/templates/_library.html
@@ -0,0 +1,6 @@
+<dt id="{{htmlId}}">
+  <span class="name">{{{ linkedName }}}</span>
+</dt>
+<dd>
+  {{#isDocumented}}{{{ oneLineDoc }}}{{/isDocumented}}
+</dd>
\ No newline at end of file
diff --git a/lib/templates/_packages.html b/lib/templates/_packages.html
new file mode 100644
index 0000000..7cc22a4
--- /dev/null
+++ b/lib/templates/_packages.html
@@ -0,0 +1,19 @@
+<ol>
+  {{#packageGraph.publicPackages}}
+    {{#isFirstPackage}}
+      <li class="section-title">Libraries</li>
+    {{/isFirstPackage}}
+    {{^isFirstPackage}}
+      <li class="section-title">{{name}}</li>
+    {{/isFirstPackage}}
+    {{#defaultCategory.publicLibraries}}
+      <li>{{{linkedName}}}</li>
+    {{/defaultCategory.publicLibraries}}
+    {{#categories}}
+      <li class="section-subtitle">{{name}}</li>
+      {{#publicLibraries}}
+        <li class="section-subitem">{{{linkedName}}}</li>
+      {{/publicLibraries}}
+    {{/categories}}
+  {{/packageGraph.publicPackages}}
+</ol>
diff --git a/lib/templates/index.html b/lib/templates/index.html
index 0b7ec93..326ff68 100644
--- a/lib/templates/index.html
+++ b/lib/templates/index.html
@@ -2,67 +2,35 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">{{self.name}}</span> <span class="package-kind">{{self.kind}}</span></h5>
-
-    {{#displayAsPackages}}
-    <ol>
-      {{#packageGraph.publicPackages}}
-        <li class="section-title">{{name}}</li>
-        {{#publicLibraries}}
-        <li>{{{linkedName}}}</li>
-        {{/publicLibraries}}
-      {{/packageGraph.publicPackages}}
-    </ol>
-    {{/displayAsPackages}}
-
-    {{^displayAsPackages}}
-    <ol>
-      <li class="section-title"><a href="{{packageGraph.href}}#libraries">Libraries</a></li>
-      {{#packageGraph.publicLibraries}}
-      <li>{{{linkedName}}}</li>
-      {{/packageGraph.publicLibraries}}
-    </ol>
-    {{/displayAsPackages}}
+    {{>packages}}
   </div>
 
   <div class="col-xs-12 col-sm-9 col-md-8 main-content">
     {{#packageGraph}}
       {{>documentation}}
-    {{/packageGraph}}
 
-    {{#displayAsPackages}}
-      {{#packageGraph.publicPackages}}
+      {{#publicPackages}}
         <section class="summary">
-          <h2>{{name}}</h2>
+          {{#isFirstPackage}}
+            <h2>Libraries</h2>
+          {{/isFirstPackage}}
+          {{^isFirstPackage}}
+            <h2>{{name}}</h2>
+          {{/isFirstPackage}}
           <dl>
-            {{#libraries}}
-              <dt id="{{htmlId}}">
-                <span class="name">{{{ linkedName }}}</span>
-              </dt>
-              <dd>
-                {{#isDocumented}}{{{ oneLineDoc }}}{{/isDocumented}}
-              </dd>
-            {{/libraries}}
+          {{#defaultCategory.publicLibraries}}
+            {{>library}}
+          {{/defaultCategory.publicLibraries}}
+          {{#categories}}
+            <h3>{{name}}</h3>
+            {{#publicLibraries}}
+              {{>library}}
+            {{/publicLibraries}}
+          {{/categories}}
           </dl>
         </section>
-      {{/packageGraph.publicPackages}}
-
-    {{/displayAsPackages}}
-
-    {{^displayAsPackages}}
-      <section class="summary" id="libraries">
-        <h2>Libraries</h2>
-        <dl>
-          {{#packageGraph.publicLibraries}}
-            <dt id="{{htmlId}}">
-              <span class="name">{{{ linkedName }}}</span>
-            </dt>
-            <dd>
-              {{{ oneLineDoc }}}
-            </dd>
-          {{/packageGraph.publicLibraries}}
-        </dl>
-      </section>
-    {{/displayAsPackages}}
+      {{/publicPackages}}
+    {{/packageGraph}}
 
   </div> <!-- /.main-content -->
 
diff --git a/lib/templates/library.html b/lib/templates/library.html
index ff4c02f..89e3eee 100644
--- a/lib/templates/library.html
+++ b/lib/templates/library.html
@@ -2,25 +2,7 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">{{parent.name}}</span> <span class="package-kind">{{parent.kind}}</span></h5>
-    {{#displayAsPackages}}
-    <ol>
-      {{#packageGraph.publicPackages}}
-        <li class="section-title">{{name}}</li>
-        {{#publicLibraries}}
-        <li>{{{linkedName}}}</li>
-        {{/publicLibraries}}
-      {{/packageGraph.publicPackages}}
-    </ol>
-    {{/displayAsPackages}}
-
-    {{^displayAsPackages}}
-    <ol>
-      <li class="section-title"><a href="{{packageGraph.href}}#libraries">Libraries</a></li>
-      {{#packageGraph.publicLibraries}}
-      <li>{{{linkedName}}}</li>
-      {{/packageGraph.publicLibraries}}
-    </ol>
-    {{/displayAsPackages}}
+    {{>packages}}
   </div>
 
   <div class="col-xs-12 col-sm-9 col-md-8 main-content">
diff --git a/test/model_test.dart b/test/model_test.dart
index d04a20f..e4fdef5 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -24,6 +24,7 @@
   }
 
   PackageGraph packageGraph;
+  PackageGraph packageGraphSmall;
   PackageGraph ginormousPackageGraph;
   Library exLibrary;
   Library fakeLibrary;
@@ -34,6 +35,7 @@
   setUpAll(() async {
     await utils.init();
     packageGraph = utils.testPackageGraph;
+    packageGraphSmall = utils.testPackageGraphSmall;
     ginormousPackageGraph = utils.testPackageGraphGinormous;
     exLibrary = packageGraph.libraries.firstWhere((lib) => lib.name == 'ex');
     fakeLibrary =
@@ -45,10 +47,47 @@
     sdkAsPackageGraph = utils.testPackageGraphSdk;
   });
 
+  group('Category', () {
+    test('Verify categories for test_package', () {
+      expect(packageGraph.publicPackages.length, equals(1));
+      expect(packageGraph.publicPackages.first.hasCategories, isTrue);
+      List<Category> packageCategories =
+          packageGraph.publicPackages.first.categories;
+      expect(packageCategories.length, equals(3));
+      expect(packageCategories.map((c) => c.name).toList(),
+          orderedEquals(['Real Libraries', 'Unreal', 'Misc']));
+      expect(packageCategories.map((c) => c.libraries.length).toList(),
+          orderedEquals([2, 2, 1]));
+      expect(
+          packageGraph
+              .publicPackages.first.defaultCategory.publicLibraries.length,
+          equals(3));
+    });
+
+    test('Verify that packages without categories get handled', () {
+      expect(packageGraphSmall.publicPackages.length, equals(1));
+      expect(packageGraphSmall.publicPackages.first.hasCategories, isFalse);
+      List<Category> packageCategories =
+          packageGraphSmall.publicPackages.first.categories;
+      expect(packageCategories.length, equals(0));
+      expect(
+          packageGraph
+              .publicPackages.first.defaultCategory.publicLibraries.length,
+          equals(3));
+    });
+  });
+
   group('Package', () {
     group('test package', () {
       setUp(() {
         setConfig();
+        ginormousPackageGraph.resetPublicPackages();
+        packageGraph.resetPublicPackages();
+      });
+      tearDown(() {
+        setConfig();
+        ginormousPackageGraph.resetPublicPackages();
+        packageGraph.resetPublicPackages();
       });
 
       test('name', () {
@@ -233,7 +272,7 @@
 
     test('has documentation', () {
       expect(exLibrary.documentation,
-          'a library. testing string escaping: `var s = \'a string\'` <cool>');
+          'a library. testing string escaping: `var s = \'a string\'` <cool>\n');
     });
 
     test('has one line docs', () {
diff --git a/testing/test_package/dartdoc_options.yaml b/testing/test_package/dartdoc_options.yaml
new file mode 100644
index 0000000..83ad422
--- /dev/null
+++ b/testing/test_package/dartdoc_options.yaml
@@ -0,0 +1,2 @@
+dartdoc:
+  categoryOrder: ["Real Libraries", "Unreal"]
diff --git a/testing/test_package/lib/css.dart b/testing/test_package/lib/css.dart
index 3215fe0..74a68c4 100644
--- a/testing/test_package/lib/css.dart
+++ b/testing/test_package/lib/css.dart
@@ -1,5 +1,6 @@
 /// Testing that a library name doesn't conflict
 /// with directories created by dartdoc.
+/// {@category Other}
 library css;
 
 String theOnlyThingInTheLibrary = 'hello';
diff --git a/testing/test_package/lib/example.dart b/testing/test_package/lib/example.dart
index c7664db..91febaa 100644
--- a/testing/test_package/lib/example.dart
+++ b/testing/test_package/lib/example.dart
@@ -1,4 +1,5 @@
 /// a library. testing string escaping: `var s = 'a string'` <cool>
+/// {@category Real Libraries}
 library ex;
 
 import 'dart:async';
diff --git a/testing/test_package/lib/fake.dart b/testing/test_package/lib/fake.dart
index fd88e32..c8785fe 100644
--- a/testing/test_package/lib/fake.dart
+++ b/testing/test_package/lib/fake.dart
@@ -1,5 +1,5 @@
 /// # WOW FAKE PACKAGE IS __BEST__ [PACKAGE][pkg]
-///
+/// {@category Real Libraries}
 /// If you don't have this package yet, get it.
 /// Don't ask questions.
 ///
diff --git a/testing/test_package/lib/reexport_one.dart b/testing/test_package/lib/reexport_one.dart
index 609d298..a0698a3 100644
--- a/testing/test_package/lib/reexport_one.dart
+++ b/testing/test_package/lib/reexport_one.dart
@@ -1,5 +1,6 @@
 /// {@canonicalFor reexport.somelib.SomeOtherClass}
 /// {@canonicalFor reexport.somelib.AUnicornClass}
+/// {@category Unreal}
 library reexport_one;
 
 export 'src/somelib.dart';
diff --git a/testing/test_package/lib/reexport_two.dart b/testing/test_package/lib/reexport_two.dart
index d8fbd05..bad819b 100644
--- a/testing/test_package/lib/reexport_two.dart
+++ b/testing/test_package/lib/reexport_two.dart
@@ -1,6 +1,7 @@
 /// {@canonicalFor reexport.somelib.SomeClass}
 /// {@canonicalFor reexport.somelib.AUnicornClass}
 /// {@canonicalFor something.ThatDoesntExist}
+/// {@category Unreal}
 library reexport_two;
 
 export 'src/somelib.dart';
diff --git a/testing/test_package/lib/two_exports.dart b/testing/test_package/lib/two_exports.dart
index 233d46e..c3e26f3 100644
--- a/testing/test_package/lib/two_exports.dart
+++ b/testing/test_package/lib/two_exports.dart
@@ -1,3 +1,4 @@
+/// {@category Misc}
 library two_exports;
 
 export 'src/base.dart';
diff --git a/testing/test_package_docs/anonymous_library/anonymous_library-library.html b/testing/test_package_docs/anonymous_library/anonymous_library-library.html
index 1d4534e..88f41e9 100644
--- a/testing/test_package_docs/anonymous_library/anonymous_library-library.html
+++ b/testing/test_package_docs/anonymous_library/anonymous_library-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/another_anonymous_lib/another_anonymous_lib-library.html b/testing/test_package_docs/another_anonymous_lib/another_anonymous_lib-library.html
index 22447b4..df4fbbe 100644
--- a/testing/test_package_docs/another_anonymous_lib/another_anonymous_lib-library.html
+++ b/testing/test_package_docs/another_anonymous_lib/another_anonymous_lib-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/code_in_comments/code_in_comments-library.html b/testing/test_package_docs/code_in_comments/code_in_comments-library.html
index c6dcd0d..e212de3 100644
--- a/testing/test_package_docs/code_in_comments/code_in_comments-library.html
+++ b/testing/test_package_docs/code_in_comments/code_in_comments-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/css/css-library.html b/testing/test_package_docs/css/css-library.html
index 35c76a5..ff38dcc 100644
--- a/testing/test_package_docs/css/css-library.html
+++ b/testing/test_package_docs/css/css-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/ex/ex-library.html b/testing/test_package_docs/ex/ex-library.html
index 2b4da0b..beefc48 100644
--- a/testing/test_package_docs/ex/ex-library.html
+++ b/testing/test_package_docs/ex/ex-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/fake/fake-library.html b/testing/test_package_docs/fake/fake-library.html
index 4584ec5..7be70a4 100644
--- a/testing/test_package_docs/fake/fake-library.html
+++ b/testing/test_package_docs/fake/fake-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/index.html b/testing/test_package_docs/index.html
index fe6e705..d9b6ac4 100644
--- a/testing/test_package_docs/index.html
+++ b/testing/test_package_docs/index.html
@@ -33,21 +33,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
@@ -97,23 +100,20 @@
 <p>Be sure to check out other awesome packages on <a href="https://pub.dartlang.org">pub</a>.</p>
       </section>
       
-
-      <section class="summary" id="libraries">
-        <h2>Libraries</h2>
-        <dl>
+        <section class="summary">
+            <h2>Libraries</h2>
+          <dl>
             <dt id="anonymous_library">
               <span class="name"><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></span>
             </dt>
             <dd>
               
-            </dd>
-            <dt id="another_anonymous_lib">
+            </dd>            <dt id="another_anonymous_lib">
               <span class="name"><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></span>
             </dt>
             <dd>
               
-            </dd>
-            <dt id="code_in_comments">
+            </dd>            <dt id="code_in_comments">
               <span class="name"><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></span>
             </dt>
             <dd>
@@ -121,58 +121,58 @@
   // in Dart!
 }
 </code> <a href="code_in_comments/code_in_comments-library.html">[...]</a>
-            </dd>
-            <dt id="css">
-              <span class="name"><a href="css/css-library.html">css</a></span>
-            </dt>
-            <dd>
-              Testing that a library name doesn't conflict
-with directories created by dartdoc.
-            </dd>
-            <dt id="ex">
-              <span class="name"><a href="ex/ex-library.html">ex</a></span>
-            </dt>
-            <dd>
-              a library. testing string escaping: <code>var s = 'a string'</code> <cool></cool>
-            </dd>
-            <dt id="fake">
-              <span class="name"><a href="fake/fake-library.html">fake</a></span>
-            </dt>
-            <dd>
-              WOW FAKE PACKAGE IS <strong>BEST</strong> <a href="http://example.org">PACKAGE</a> <a href="fake/fake-library.html">[...]</a>
-            </dd>
-            <dt id="is_deprecated">
+            </dd>            <dt id="is_deprecated">
               <span class="name"><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></span>
             </dt>
             <dd>
               This lib is deprecated. It never had a chance
-            </dd>
-            <dt id="reexport_one">
-              <span class="name"><a href="reexport_one/reexport_one-library.html">reexport_one</a></span>
-            </dt>
-            <dd>
-              
-            </dd>
-            <dt id="reexport_two">
-              <span class="name"><a href="reexport_two/reexport_two-library.html">reexport_two</a></span>
-            </dt>
-            <dd>
-              
-            </dd>
+            </dd>            <h3>Real Libraries</h3>
+              <dt id="ex">
+                <span class="name"><a href="ex/ex-library.html">ex</a></span>
+              </dt>
+              <dd>
+                a library. testing string escaping: <code>var s = 'a string'</code> <cool></cool>
+              </dd>              <dt id="fake">
+                <span class="name"><a href="fake/fake-library.html">fake</a></span>
+              </dt>
+              <dd>
+                WOW FAKE PACKAGE IS <strong>BEST</strong> <a href="http://example.org">PACKAGE</a> <a href="fake/fake-library.html">[...]</a>
+              </dd>            <h3>Unreal</h3>
+              <dt id="reexport_one">
+                <span class="name"><a href="reexport_one/reexport_one-library.html">reexport_one</a></span>
+              </dt>
+              <dd>
+                
+              </dd>              <dt id="reexport_two">
+                <span class="name"><a href="reexport_two/reexport_two-library.html">reexport_two</a></span>
+              </dt>
+              <dd>
+                
+              </dd>            <h3>Misc</h3>
+              <dt id="two_exports">
+                <span class="name"><a href="two_exports/two_exports-library.html">two_exports</a></span>
+              </dt>
+              <dd>
+                
+              </dd>            <h3>Other</h3>
+              <dt id="css">
+                <span class="name"><a href="css/css-library.html">css</a></span>
+              </dt>
+              <dd>
+                Testing that a library name doesn't conflict
+with directories created by dartdoc.
+              </dd>          </dl>
+        </section>
+        <section class="summary">
+            <h2>test_package_imported</h2>
+          <dl>
             <dt id="test_package_imported.main">
               <span class="name"><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></span>
             </dt>
             <dd>
               
-            </dd>
-            <dt id="two_exports">
-              <span class="name"><a href="two_exports/two_exports-library.html">two_exports</a></span>
-            </dt>
-            <dd>
-              
-            </dd>
-        </dl>
-      </section>
+            </dd>          </dl>
+        </section>
 
   </div> <!-- /.main-content -->
 
diff --git a/testing/test_package_docs/is_deprecated/is_deprecated-library.html b/testing/test_package_docs/is_deprecated/is_deprecated-library.html
index 906ba22..c918e01 100644
--- a/testing/test_package_docs/is_deprecated/is_deprecated-library.html
+++ b/testing/test_package_docs/is_deprecated/is_deprecated-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/reexport_one/reexport_one-library.html b/testing/test_package_docs/reexport_one/reexport_one-library.html
index 1230894..baadb44 100644
--- a/testing/test_package_docs/reexport_one/reexport_one-library.html
+++ b/testing/test_package_docs/reexport_one/reexport_one-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/reexport_two/reexport_two-library.html b/testing/test_package_docs/reexport_two/reexport_two-library.html
index 3bc1b49..6355f9b 100644
--- a/testing/test_package_docs/reexport_two/reexport_two-library.html
+++ b/testing/test_package_docs/reexport_two/reexport_two-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/static-assets/styles.css b/testing/test_package_docs/static-assets/styles.css
index bd1fc4e..ade56f4 100644
--- a/testing/test_package_docs/static-assets/styles.css
+++ b/testing/test_package_docs/static-assets/styles.css
@@ -630,6 +630,19 @@
   padding-top: 25px;
 }
 
+.sidebar ol li.section-subtitle a {
+  color: inherit;
+}
+
+.sidebar ol li.section-subtitle {
+  font-weight: 400;
+  text-transform: uppercase;
+}
+
+.sidebar ol li.section-subitem {
+  margin-left: 12px;
+}
+
 .sidebar ol li:first-child {
   padding-top: 0;
   margin-top: 0;
diff --git a/testing/test_package_docs/test_package_imported.main/test_package_imported.main-library.html b/testing/test_package_docs/test_package_imported.main/test_package_imported.main-library.html
index da267e3..f83b769 100644
--- a/testing/test_package_docs/test_package_imported.main/test_package_imported.main-library.html
+++ b/testing/test_package_docs/test_package_imported.main/test_package_imported.main-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>
 
diff --git a/testing/test_package_docs/two_exports/two_exports-library.html b/testing/test_package_docs/two_exports/two_exports-library.html
index ac5e38c..410e513 100644
--- a/testing/test_package_docs/two_exports/two_exports-library.html
+++ b/testing/test_package_docs/two_exports/two_exports-library.html
@@ -36,20 +36,24 @@
 
   <div class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left">
     <h5><span class="package-name">test_package</span> <span class="package-kind">package</span></h5>
-
     <ol>
-      <li class="section-title"><a href="index.html#libraries">Libraries</a></li>
-      <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
-      <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
-      <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
-      <li><a href="css/css-library.html">css</a></li>
-      <li><a href="ex/ex-library.html">ex</a></li>
-      <li><a href="fake/fake-library.html">fake</a></li>
-      <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
-      <li><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
-      <li><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
-      <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
-      <li><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-title">Libraries</li>
+          <li><a href="anonymous_library/anonymous_library-library.html">anonymous_library</a></li>
+          <li><a href="another_anonymous_lib/another_anonymous_lib-library.html">another_anonymous_lib</a></li>
+          <li><a href="code_in_comments/code_in_comments-library.html">code_in_comments</a></li>
+          <li><a class="deprecated" href="is_deprecated/is_deprecated-library.html">is_deprecated</a></li>
+          <li class="section-subtitle">Real Libraries</li>
+            <li class="section-subitem"><a href="ex/ex-library.html">ex</a></li>
+            <li class="section-subitem"><a href="fake/fake-library.html">fake</a></li>
+          <li class="section-subtitle">Unreal</li>
+            <li class="section-subitem"><a href="reexport_one/reexport_one-library.html">reexport_one</a></li>
+            <li class="section-subitem"><a href="reexport_two/reexport_two-library.html">reexport_two</a></li>
+          <li class="section-subtitle">Misc</li>
+            <li class="section-subitem"><a href="two_exports/two_exports-library.html">two_exports</a></li>
+          <li class="section-subtitle">Other</li>
+            <li class="section-subitem"><a href="css/css-library.html">css</a></li>
+          <li class="section-title">test_package_imported</li>
+          <li><a href="test_package_imported.main/test_package_imported.main-library.html">test_package_imported.main</a></li>
     </ol>
   </div>