Thursday, March 29, 2012

Don't Dartdoc the Core API

‹prev | My Chain | next›

Up tonight, I take the advice of John Evans to rework my hard fork of the dart-sdk to use a saner command-line option in dart-doc. Specifically, it makes sense to include an option to enable / disable the inclusion of core Dart API documentation in the output. I do not want it in Hipster MVC, and already have any references to core types pointing to api.dartlang.org.

The problem with my current solution is that it whitelists the files that I want documented and assumes that everything else is located on api.dartlang.org. It works when I can use the string "hipster" to include only libraries in my Hipster MVC package. If I wanted to add another library without the name "Hipster" embedded in it, then I would be out of luck. Besides, I am not really interested in only including certain libraries. I really want to enable / disable the inclusion of core documentation.

After much thought, I settle on a command line switch --no-dart-api. This seems to capture what I want and conform to the standard dartdoc options (e.g. --node-code). If this switch is not provided, then core documentation will be generated—just like it does in upstream. If it is provided....

I set a boolean instance variable accordingly:
// ...
    switch (arg) {
      case '--no-code':
        includeSource = false;
        break;

      case '--no-dart-api':
        includeDartApi = false;
        break;

      // ...
    }
// ...
The value of includeDartApi is passed into the DartDoc class. In there, I filter the list of libraries that will be documented:
// ...
      // Sort the libraries by name (not key).
      _sortedLibraries = world.
        libraries.
        getValues().
        filter(_includeLibrary);
// ...
That _includeLibrary() filter method can then make use of the includeDartApi instance variable:
  bool _includeLibrary(Library library) {
    // Exclude main.dart that might be index of library
    if (library.name == 'main') return false;

    if (includeDartApi) return true;

    if (library.isDartApi) return false;

    return true;
  }
If includeDartApi is true, then all documentation should be generated. If false, evaluation moves down to library.isDartApi. That isDartApi method is new to the Library. In there, I use a Set to describe the entire list of libraries that are considered part of the Dart API:
/** Represents a Dart library. */
class Library extends Element {
  // ...
  static Set get dartApiLibraries() =>
    new Set.from([
      'core',
      'dart:core',
      'coreimpl',
      'dart:coreimpl',
      'dart:isolate',
      'html',
      'dart:html',
      'io',
      'json',
      'uri'
    ]);
  
  bool get isDartApi() => Library.dartApiLibraries.contains(this.name);
}
The nice thing about Set is that it give me the contains() method, which I use in isDartApi to decide if the current library is one of the Dart API libraries.

Easy-peasy and I have dartdoc again generating only documentation for my 6 Hispter MVC libraries:
dart ~/src/dart-sdk/lib/dartdoc/dartdoc.dart \
    --title='Hipster MVC Documentation' \
    --description='API documentation for the very excellent MVC library...' \
  main.dart
Documented 6 libraries, 16 types, and 75 members.
With that working fairly well, I take a little time to actually document Hipster MVC, starting with the router. The dartdoc format is markdown:
class HipsterRouter {
  /// The router exposes named events on which listeners can wait. For example,
  /// if the router has a "page" route, the event will be available on the
  /// 'route:page' event:
  ///     HipsterRouter app = new MyRouter();
  ///       app.
  ///         on['route:page'].
  ///         add((num) {
  ///           print("Routed to page: $num");
  ///         });
  RouterEvents on;
  // ...
}
The result is some very pretty documentation on HipsterRouter. Looking that good, I may not be able to resist documenting the heck out of Hipster MVC.


Day #340

No comments:

Post a Comment