Sunday, March 25, 2012

Dartdoc (not Apidoc)

‹prev | My Chain | next›

If Hipster MVC is to rule the world, I need some documentation. Well, that and it would help if it could perform the "Update" part of CRUD, but I'll worry about that another day.

Bleeding edge Dart has a dartdoc tool that I have yet to play with—tonight seems like a fine time to start. The dartdoc code has moved about, but currently it resides in /bleeding_edge/dart/lib. I could check out all of bleeding_edge/dart, but that seems overkill. It contains the Dart Editor and third-party tools like Ant and Rhino. If I can avoid downloading that, I will.

So first, I start by installing subversion (really?):
sudo apt-get install subversion
With that, I can create a dart working directory to hold all of this and then proceed to checkout dart/lib:
➜  repos  mkdir dart
➜  dart  svn checkout http://dart.googlecode.com/svn/branches/bleeding_edge/dart/lib
A    lib/uri
A    lib/uri/uri.dart
A    lib/dartdoc
...
Checked out revision 5808.
Next, I try to generate documentation for the HipsterHistory class in Hipster MVC:
➜  dart  dart ./lib/dartdoc/dartdoc.dart /home/cstrom/repos/hipster-mvc/HipsterHistory.dart
Unable to open file: /home/cstrom/repos/dart/frog/lang.dart'file:///home/cstrom/repos/dart/lib/dartdoc/dartdoc.dart': Error: line 21 pos 1: library handler failed
#import('../../frog/lang.dart');
^
So it seems that I need to have dart/frog installed for this:
➜  dart  svn checkout http://dart.googlecode.com/svn/branches/bleeding_edge/dart/frog
A    frog/file_system_node.dart
A    frog/scripts
A    frog/scripts/tree_gen.py
...
Checked out revision 5808.
Now I get:
➜  dart  dart ./lib/dartdoc/dartdoc.dart /home/cstrom/repos/hipster-mvc/HipsterHistory.dart
error: File not found: /home/cstrom/repos/dart/corelib/src/bool.dart
error: File not found: /home/cstrom/repos/dart/corelib/src/collection.dart
error: File not found: /home/cstrom/repos/dart/corelib/src/comparable.dart
...
compilation failed with 378 errors
There are a ton of errors there, but I start with the first few lines. It seem clear that, in addition to dart/lib I also need dart/corelib:
➜  dart  svn checkout http://dart.googlecode.com/svn/branches/bleeding_edge/dart/corelib
A    corelib/src
A    corelib/src/iterable.dart
A    corelib/src/expect.dart
...
Checked out revision 5808.
Now, when I try to run dartdoc, I find:
➜  dart  dart ./lib/dartdoc/dartdoc.dart /home/cstrom/repos/hipster-mvc/HipsterHistory.dart
error: File not found: /home/cstrom/repos/dart/client/html/frog/html_frog.dart
Documented 4 libraries, 93 types, and 711 members.
error: File not found: /home/cstrom/repos/dart/client/html/frog/html_frog.dart
...
compilation failed with 8 errors
Eight errors is certainly an improvement over 378. Still, it is not quite there yet so I install dart/client:
➜  dart  svn checkout http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client
A    client/dom
A    client/dom/src
A    client/dom/src/EventListener.dart
...
Checked out revision 5808.
Now when I run dartdoc it completes successfully:
➜  dart  dart ./lib/dartdoc/dartdoc.dart /home/cstrom/repos/hipster-mvc/HipsterHistory.dart
Documented 4 libraries, 661 types, and 5470 members.
Compilation succeded. Code generated in: docs/client-live-nav.js
Four libraries? I only supplied one. That is odd. Loading up the index of the documentation I see:


Ah, so it got four libraries by including dart:core, dart:core, and dart:html in addition to my library. I need to figure out how to suppress those. Also, I need a better name for my library. I had been using a full description of the library after realizing that the dart2javascript compiler used the #library() declaration to comment the code in Javascript. So it seems that my current declaration:
#library('Manage pushState, usually through HipsterRouter.');

#import('dart:html');

class HipsterHistory {
  // ...
}
Would be better written as:
#library('Hipster MVC: Hipster History');

#import('dart:html');

class HipsterHistory {
  // ...
}
With that, my documentation now has a more proper name:


Looking through the dartdoc source code, I figure out what that "Code generated in: docs/client-live-nav.js" statement means -- it means that sidebar navigation is stored in JSON to be pulled in via Ajax by the browser. Since I am viewing the documentation locally, the Ajax load will not work. Still, that is a nice space savings optimization done by dartdoc. Of course, even more space would be saved if it was not documenting core libraries...

In addition to dartdoc, bleeding edge Dart also includes an apidoc command. Perhaps I am meant to use that? To test that theory, I checkout dart/utils:
➜  dart  svn checkout http://dart.googlecode.com/svn/branches/bleeding_edge/dart/utils
A    utils/apidoc
A    utils/apidoc/html_diff.dart
A    utils/apidoc/.gitignore
...
Checked out revision 5810.
My first attempt at running it is not a success:
➜  dart  dart ./utils/apidoc/apidoc.dart /home/cstrom/repos/hipster-mvc/HipsterHistory.dart 
Unknown option: /home/cstrom/repos/hipster-mvc/HipsterHistory.dart
So I check the source code, which seems to indicate that I should be running without any arguments. So I change directories into my Hipster MVC library to try again:
➜  hipster-mvc git:(master) ✗ dart ../dart/utils/apidoc/apidoc.dart          
Unhandled exception:
Unresolved static method: url 'file:///home/cstrom/repos/dart/utils/apidoc/apidoc.dart' line 53 pos 7
  doc.compileScript(frogPath,

 0. Function: 'StaticResolutionException._throwNew@127eafe4' url: 'bootstrap' line:620 col:3
 1. Function: '::main' url: 'file:///home/cstrom/repos/dart/utils/apidoc/apidoc.dart' line:53 col:7
Yikes!

Why on earth does Dart think that doc.compileScript() is a static method? My understanding was that classes needed to be upper-case....

It turns out that apidoc it importing dartdoc into the doc prefix:
#import('../../lib/dartdoc/dartdoc.dart', prefix: 'doc');
So, although doc looks like an object, it is really a prefix. That seems... deceptive.

As for why the static method is unknown, it seems that I am a victim of the bleeding edge here. In dartdoc, the compileScript function takes four arguments, but apidoc is supplying 3:
// ...
  // Compile the client-side code to JS.
  // TODO(bob): Right path.
  doc.compileScript(frogPath,
      '${doc.scriptDir}/../../lib/dartdoc/client-live-nav.dart',
      '${outputDir}/client-live-nav.js');
// ...
This is not a long term solution, but I copy the fourth argument from dartdoc to get past this:
// ...
  final libDir = joinPaths(frogPath, 'lib');
  doc.compileScript(frogPath, 
       libDir,
       '${doc.scriptDir}/../../lib/dartdoc/client-live-nav.dart',
       '${outputDir}/client-live-nav.js');
// ...
I also have to modify the Mozilla Documentation Path to get this to work:
// ...
  print('Parsing MDN data...');
  final mdnPath = joinPaths(doc.scriptDir, 'mdn');
 
  final mdn = JSON.parse(files.readAll('$mdnPath/database.json'));
// ...
With that, I get new errors:
➜  hipster-mvc git:(master) ✗ dart ../dart/utils/apidoc/apidoc.dart
Parsing MDN data...
Cross-referencing dart:dom and dart:html...
error: File not found: /home/cstrom/repos/dart/runtime/bin/buffer_list.dart
error: File not found: /home/cstrom/repos/dart/runtime/bin/common.dart
...
So it seem that I need dart/runtime for apidoc:
➜  dart  svn checkout http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime
A    runtime/tools
A    runtime/tools/gyp
A    runtime/tools/gyp/runtime-configurations.gypi
...
Checked out revision 5810.
Trying again, I get:
➜  hipster-mvc git:(master) ✗ dart ../dart/utils/apidoc/apidoc.dart
Parsing MDN data...
Cross-referencing dart:dom and dart:html...
Generating docs...
Failed to compile /home/cstrom/repos/dart/utils/apidoc/../../lib/dartdoc/client-live-nav.dart. Error:
ProcessException: Permission denied
Uhh.... "Permission Denied"? What the heck was it trying to do?

Regardless, what is generated has nothing to do with my Hipster MVC library. Rather it is the actual API documentation for Dart itself:


So, in the end, it seems that dartdoc is what I want, not apidoc. I see no reason to include the dependent core Dart libraries along with my own API documentation, so I still have some work ahead. I will either need to post-process the generated dartdoc, dig deeper for some as-yet unseen flag to suppress core libraries, or roll my own dartdoc sans core libraries. Tomorrow.


Day #336

2 comments:

  1. You can run dartdoc from a recent dart-sdk. You need to add .../dart-sdk/bin to your path, then cd to dart-sdk/lib/dartdoc and run './dartdoc --mode=static path/to/your/package'. That should give you docs with the full left column navigation in HTML (can be run from your filesystem without a server).

    There is a small bug in the sdk version that ignores the '--mode=static' switch, but it is fixed in bleeding_edge already.

    ReplyDelete
    Replies
    1. Dammit, but of course you are correct. I had downloaded the latest copy of the SDK before I began this merry chase, but never bothered to unzip it, let alone check for dartdoc. Sigh.

      Anyhow, thanks for pointing that out -- it'll definitely help today.

      Delete