Saturday, November 3, 2012

Troubleshooting Triple Slash Dartdocs

‹prev | My Chain | next›

Thanks to dartdoc (and some minor hacking), I have some lovely documentation for Hipster MVC, the awesome MVC framework written in Dart.

I did run into a problem that is still bugging me. The dartdoc documentation format is written in markdown and is supposed to be able to be embedded in any kind of comment. I had originally used triple-slash comments:
   /// Application routers must subclass [HipsterRouter], definining at least the
   /// [routes] getter:
   ///
   ///     class MyRouter extends HipsterRouter {
   ///       List get routes() =>
   ///         [
   ///           ['page/:num', pageNum, 'page']
   ///         ];
   ///       //
   ///       pageNum(num) {
   ///         var el = document.query('body');
   ///          el.innerHTML = _pageNumTemplate(num);
   ///       }
   ///     }
   HipsterRouter() {
     on = new RouterEvents();
     this._initializeRoutes();
   }
But was forced to switch to slash-star comments instead:
  /**
   * Application routers must subclass [HipsterRouter], definining at least the
   * [routes] getter:
   *
   *     class MyRouter extends HipsterRouter {
   *       List get routes() =>
   *         [
   *           ['page/:num', pageNum, 'page']
   *         ];
   *       //
   *       pageNum(num) {
   *         var el = document.query('body');
   *          el.innerHTML = _pageNumTemplate(num);
   *       }
   *     }
   */
  HipsterRouter() {
    on = new RouterEvents();
    this._initializeRoutes();
  }
I rather like the star-slash better (though I must have preferred three-slashes at some point). Somehow slash-start is less noisy. Still, it bugs me that triple slashes stopped working.

I eventually track the problem down to the CommentMap in dart-sdk/pkg/dartdoc/lib/src/dartdoc/comment_map.dart. As the name suggests, the comment map links comments to spans of code.

The problem starts with the tokenizer that breaks comments (and other things) into chunks. The slash-star formatted chunks are easy for the tokenizer to identify as being part of a whole.

The triple-slash comments, however, are tokenized as separate lines. This leaves it to the calling context to decide if the tokens belong together. In CommentMap, this is handled by the private _parseComment method, which handles it as follows:
  _parseComments(Source source) {
    // ...
    while (token.kind != dart2js.EOF_TOKEN) {
      if (token.kind == dart2js.COMMENT_TOKEN) {
        // ...
        } else if (text.startsWith('///')) {
          var line = text.substring(3);
          // Allow a leading space.
          if (line.startsWith(' ')) line = line.substring(1);
          if (lastComment == null) {
            lastComment = line;
          } else {
            lastComment = "$lastComment$line";
          }
        }
      } else if (token.kind == dart2js.HASH_TOKEN) {
      // ...
    }
  }
The problem is not obvious from this context, but the tokens have all been stripped of whitespace—including newlines. Since this section of code is responsible for collecting triple-slash comments, it needs the newlines. Without them, this dartdoc:
   ///....
   /// [routes] getter:
   ///
   ///     class MyRouter extends HipsterRouter {
   /// ...
Is collected as:
... [routes] getter:     class MyRouter extends HipsterRouter { ...
The solution is simple enough, I add a newline character in between the lastComment so far, and the newly collected line:
            // ...
            lastComment = "$lastComment\n$line";
            // ...
With that, I can again use the triple-slash format to produce pretty documentation:


Looking through the code over on github, it does not appear as though this has been fixed yet. So, unless someone fixes this in the meantime, it seems like I have a good excuse to contribute a fix to the Dart SDK. Tomorrow.

Day #559

No comments:

Post a Comment