Chromium Code Reviews| Index: lib/dartdoc/dartdoc.dart | 
| diff --git a/lib/dartdoc/dartdoc.dart b/lib/dartdoc/dartdoc.dart | 
| index 63eb2b2f3ca7371cf218222f3b2f747797282413..1445e5aa0e2f341e2de4eec2c9e9a1a14b779c81 100644 | 
| --- a/lib/dartdoc/dartdoc.dart | 
| +++ b/lib/dartdoc/dartdoc.dart | 
| @@ -17,12 +17,18 @@ | 
| #library('dartdoc'); | 
| #import('dart:io'); | 
| +#import('dart:uri'); | 
| #import('dart:json'); | 
| -#import('frog/lang.dart'); | 
| -#import('frog/file_system.dart'); | 
| -#import('frog/file_system_vm.dart'); | 
| +#import('../compiler/implementation/util/characters.dart'); | 
| +#import('mirrors/mirrors.dart'); | 
| +#import('mirrors/mirrors_util.dart'); | 
| +#import('mirrors/dart2js_mirror.dart', prefix: 'dart2js'); | 
| #import('classify.dart'); | 
| #import('markdown.dart', prefix: 'md'); | 
| +#import('../compiler/implementation/dart2js.dart', prefix: 'dart2js'); | 
| +#import('../compiler/implementation/scanner/scannerlib.dart', | 
| + prefix: 'dart2js'); | 
| +#import('file_util.dart'); | 
| #source('comment_map.dart'); | 
| #source('utils.dart'); | 
| @@ -60,6 +66,13 @@ void main() { | 
| String outputDir; | 
| bool generateAppCache; | 
| bool omitGenerationTime; | 
| + bool verbose; | 
| + | 
| + if (args.isEmpty()) { | 
| + print('No arguments provided.'); | 
| + printUsage(); | 
| + return; | 
| + } | 
| for (int i = 0; i < args.length - 1; i++) { | 
| final arg = args[i]; | 
| @@ -85,12 +98,16 @@ void main() { | 
| case '--omit-generation-time': | 
| omitGenerationTime = true; | 
| break; | 
| + case '--verbose': | 
| + verbose = true; | 
| + break; | 
| default: | 
| if (arg.startsWith('--out=')) { | 
| outputDir = arg.substring('--out='.length); | 
| } else { | 
| print('Unknown option: $arg'); | 
| + printUsage(); | 
| return; | 
| } | 
| break; | 
| @@ -102,21 +119,14 @@ void main() { | 
| return; | 
| } | 
| - // The entrypoint of the library to generate docs for. | 
| - final entrypoint = args[args.length - 1]; | 
| - | 
| - final files = new VMFileSystem(); | 
| - | 
| // TODO(rnystrom): Note that the following lines get munged by create-sdk to | 
| // work with the SDK's different file layout. If you change, be sure to test | 
| // that dartdoc still works when run from the built SDK directory. | 
| - final frogPath = joinPaths(scriptDir, 'frog/'); | 
| - final libDir = joinPaths(scriptDir, '..'); | 
| - final compilerPath | 
| - = Platform.operatingSystem == 'windows' ? 'dart2js.bat' : 'dart2js'; | 
| + final String libPath = joinPaths(scriptDir,'../'); | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
space after comma.
 
Johnni Winther
2012/07/09 14:57:18
Done.
 
 | 
| - parseOptions(frogPath, ['', '', '--libdir=$libDir'], files); | 
| - initializeWorld(files); | 
| + // The entrypoint of the library to generate docs for. | 
| + // TODO(johnniwinther): Handle absolute/relative paths | 
| + final entrypoint = canonicalizePath(args[args.length - 1]); | 
| final dartdoc = new Dartdoc(); | 
| @@ -127,24 +137,63 @@ void main() { | 
| if (omitGenerationTime != null) { | 
| dartdoc.omitGenerationTime = omitGenerationTime; | 
| } | 
| + if (verbose != null) dartdoc.verbose = verbose; | 
| cleanOutputDirectory(dartdoc.outputDir); | 
| + dartdoc.documentEntryPoint(entrypoint, libPath); | 
| + | 
| // Compile the client-side code to JS. | 
| final clientScript = (dartdoc.mode == MODE_STATIC) ? 'static' : 'live-nav'; | 
| - final Future scriptCompiled = compileScript(compilerPath, | 
| - '$scriptDir/client-$clientScript.dart', | 
| - '${dartdoc.outputDir}/client-$clientScript.js'); | 
| - | 
| - final Future filesCopied = copyFiles('$scriptDir/static', dartdoc.outputDir); | 
| - | 
| - Futures.wait([scriptCompiled, filesCopied]).then((_) { | 
| - dartdoc.document(entrypoint); | 
| + final bool scriptCompiled = compileScript( | 
| + '$scriptDir/client-$clientScript.dart', | 
| + '${dartdoc.outputDir}/client-$clientScript.js'); | 
| + | 
| + if (scriptCompiled) { | 
| + final Future filesCopied = copyFiles('$scriptDir/static', | 
| + dartdoc.outputDir); | 
| + | 
| + Futures.wait([filesCopied]).then((_) { | 
| + print('Documented ${dartdoc._totalLibraries} libraries, ' | 
| + '${dartdoc._totalTypes} types, and ' | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
Indent to paren.
 
Johnni Winther
2012/07/09 14:57:18
Done.
 
 | 
| + '${dartdoc._totalMembers} members.'); | 
| + }); | 
| + } | 
| +} | 
| - print('Documented ${dartdoc._totalLibraries} libraries, ' | 
| - '${dartdoc._totalTypes} types, and ' | 
| - '${dartdoc._totalMembers} members.'); | 
| - }); | 
| +void printUsage() { | 
| + print(''' | 
| +Usage dartdoc [options] <entrypoint> | 
| +[options] include | 
| + --no-code Do not include source code in the documentation. | 
| + | 
| + --mode=static Generates completely static HTML containing | 
| + everything you need to browse the docs. The only | 
| + client side behavior is trivial stuff like syntax | 
| + highlighting code. | 
| + | 
| + --mode=live-nav (default) Generated docs do not include baked HTML | 
| + navigation. Instead, a single `nav.json` file is | 
| + created and the appropriate navigation is generated | 
| + client-side by parsing that and building HTML. | 
| + This dramatically reduces the generated size of | 
| + the HTML since a large fraction of each static page | 
| + is just redundant navigation links. | 
| + In this mode, the browser will do a XHR for | 
| + nav.json which means that to preview docs locally, | 
| + you will need to enable requesting file:// links in | 
| + your browser or run a little local server like | 
| + `python -m SimpleHTTPServer`. | 
| + | 
| + --generate-app-cache Generates the App Cache manifest file, enabling | 
| + offline doc viewing. | 
| + --generate-app-cache=true --''-- | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
I'm not sure --''-- is an internationally recogniz
 
Johnni Winther
2012/07/09 14:57:18
You can't write --generate-app-cache=false. I thin
 
 | 
| + | 
| + --out=<dir> Generates files into directory <dir>. If omitted | 
| + the files are generated into ./docs/ | 
| + | 
| + --verbose Print verbose information during generation. | 
| +'''); | 
| } | 
| /** | 
| @@ -166,7 +215,14 @@ void cleanOutputDirectory(String path) { | 
| outputDir.deleteRecursivelySync(); | 
| } | 
| - outputDir.createSync(); | 
| + try { | 
| + // TODO(johnniwinther): hack to avoid 'file already exists' exception thrown | 
| + // due to invalid result from dir.existsSync() (probably due to race | 
| + // conditions). | 
| + outputDir.createSync(); | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
I never like ignoring an exception.
So you first c
 
Johnni Winther
2012/07/09 14:57:18
I will fix it later.
 
 | 
| + } catch (DirectoryIOException e) { | 
| + // Ignore. | 
| + } | 
| } | 
| /** | 
| @@ -199,33 +255,20 @@ Future copyFiles(String from, String to) { | 
| /** | 
| * Compiles the given Dart script to a JavaScript file at [jsPath] using the | 
| - * Dart-to-JS compiler located at [compilerPath]. | 
| + * Dart2js compiler. | 
| */ | 
| -Future compileScript(String compilerPath, String dartPath, String jsPath) { | 
| - final completer = new Completer(); | 
| - onExit(ProcessResult result) { | 
| - if (result.exitCode != 0) { | 
| - final message = 'Non-zero exit code from $compilerPath'; | 
| - print('$message.'); | 
| - print(result.stdout); | 
| - print(result.stderr); | 
| - throw message; | 
| - } | 
| - completer.complete(true); | 
| - } | 
| - | 
| - onError(error) { | 
| - final message = 'Error trying to execute $compilerPath. Error: $error'; | 
| - print('$message.'); | 
| - throw message; | 
| - } | 
| - | 
| - print('Compiling $dartPath to $jsPath'); | 
| - var processFuture = Process.run(compilerPath, ['--out=$jsPath', dartPath]); | 
| - processFuture.handleException(onError); | 
| - processFuture.then(onExit); | 
| - | 
| - return completer.future; | 
| +bool compileScript(String dartPath, String jsPath) { | 
| + dart2js.compile([ | 
| + '--no-colors', | 
| + // TODO(johnniwinther): The following lines get munged by create-sdk to | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
How do they get "munged"? Is it just scriptDir/jsP
 
Johnni Winther
2012/07/09 14:57:18
Yes, create_sdk.py is!
 
 | 
| + // work with the SDK's different file layout. If you change, be sure to | 
| + // test that dartdoc still works when run from the built SDK directory. | 
| + '--library-root=${joinPaths(scriptDir,'../../')}', | 
| + '--out=$jsPath', | 
| + '--throw-on-error', | 
| + '--suppress-warnings', | 
| + dartPath]); | 
| + return true; | 
| } | 
| class Dartdoc { | 
| @@ -277,6 +320,12 @@ class Dartdoc { | 
| /** Set this to omit generation timestamp from output */ | 
| bool omitGenerationTime = false; | 
| + /** Set this to print verbose information during generation */ | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
/** Set by Dartdoc user to print extra information
 
Johnni Winther
2012/07/09 14:57:18
Done.
 
 | 
| + bool verbose = false; | 
| + | 
| + /** Set this to select the libraries to document */ | 
| + List<String> libraries = null; | 
| + | 
| /** | 
| * From exposes the set of libraries in `world.libraries`. That maps library | 
| * *keys* to [Library] objects. The keys are *not* exactly the same as their | 
| @@ -284,18 +333,18 @@ class Dartdoc { | 
| * correctly. This list contains the libraries in correct order by their | 
| * *name*. | 
| */ | 
| - List<Library> _sortedLibraries; | 
| + List<LibraryMirror> _sortedLibraries; | 
| CommentMap _comments; | 
| /** The library that we're currently generating docs for. */ | 
| - Library _currentLibrary; | 
| + LibraryMirror _currentLibrary; | 
| /** The type that we're currently generating docs for. */ | 
| - Type _currentType; | 
| + InterfaceMirror _currentType; | 
| /** The member that we're currently generating docs for. */ | 
| - Member _currentMember; | 
| + MemberMirror _currentMember; | 
| /** The path to the file currently being written to, relative to [outdir]. */ | 
| String _filePath; | 
| @@ -319,10 +368,17 @@ class Dartdoc { | 
| member: _currentMember)); | 
| } | 
| + bool includeLibrary(LibraryMirror library) { | 
| + if (libraries != null) { | 
| + return libraries.indexOf(library.simpleName()) != -1; | 
| + } | 
| + return true; | 
| + } | 
| + | 
| String get footerContent(){ | 
| var footerItems = []; | 
| if(!omitGenerationTime) { | 
| - footerItems.add("This page generated at ${new Date.now()}"); | 
| + footerItems.add("This page was generated at ${new Date.now()}"); | 
| } | 
| if(footerText != null) { | 
| footerItems.add(footerText); | 
| @@ -337,38 +393,35 @@ class Dartdoc { | 
| return content; | 
| } | 
| - void document([String entrypoint]) { | 
| - var oldDietParse = options.dietParse; | 
| - try { | 
| - options.dietParse = true; | 
| - | 
| - // If we have an entrypoint, process it. Otherwise, just use whatever | 
| - // libraries have been previously loaded by the calling code. | 
| - if (entrypoint != null) { | 
| - world.processDartScript(entrypoint); | 
| - } | 
| + void documentEntryPoint(String entrypoint, String libPath) { | 
| + final compilation = new Compilation(entrypoint, libPath); | 
| + _document(compilation); | 
| + } | 
| - world.resolveAll(); | 
| + void documentLibraries(List<String> libraries, String libPath) { | 
| + final compilation = new Compilation.library(libraries, libPath); | 
| + _document(compilation); | 
| + } | 
| - // Sort the libraries by name (not key). | 
| - _sortedLibraries = world.libraries.getValues(); | 
| - _sortedLibraries.sort((a, b) { | 
| - return a.name.toUpperCase().compareTo(b.name.toUpperCase()); | 
| - }); | 
| + void _document(Compilation compilation) { | 
| + // Sort the libraries by name (not key). | 
| + _sortedLibraries = new List<LibraryMirror>.from( | 
| + compilation.mirrors().libraries().getValues().filter(includeLibrary)); | 
| + _sortedLibraries.sort((x, y) { | 
| + return x.simpleName().toUpperCase().compareTo( | 
| + y.simpleName().toUpperCase()); | 
| + }); | 
| - // Generate the docs. | 
| - if (mode == MODE_LIVE_NAV) docNavigationJson(); | 
| + // Generate the docs. | 
| + if (mode == MODE_LIVE_NAV) docNavigationJson(); | 
| - docIndex(); | 
| - for (final library in _sortedLibraries) { | 
| - docLibrary(library); | 
| - } | 
| + docIndex(); | 
| + for (final library in _sortedLibraries) { | 
| + docLibrary(library); | 
| + } | 
| - if (generateAppCache) { | 
| - generateAppCacheManifest(); | 
| - } | 
| - } finally { | 
| - options.dietParse = oldDietParse; | 
| + if (generateAppCache) { | 
| + generateAppCacheManifest(); | 
| } | 
| } | 
| @@ -381,10 +434,17 @@ class Dartdoc { | 
| final outPath = '$outputDir/$_filePath'; | 
| final dir = new Directory(dirname(outPath)); | 
| if (!dir.existsSync()) { | 
| - dir.createSync(); | 
| + // TODO(johnniwinther): Hack to avoid 'file already exists' exception | 
| + // thrown due to invalid result from dir.existsSync() (probably due to | 
| + // race conditions). | 
| + try { | 
| + dir.createSync(); | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
Could you use
 dir.create().wait()
instead? It's n
 
Johnni Winther
2012/07/09 14:57:18
I will fix it later.
 
 | 
| + } catch (DirectoryIOException e) { | 
| + // Ignore. | 
| + } | 
| } | 
| - world.files.writeString(outPath, _file.toString()); | 
| + writeString(new File(outPath), _file.toString()); | 
| _filePath = null; | 
| _file = null; | 
| } | 
| @@ -424,7 +484,8 @@ class Dartdoc { | 
| // Add data attributes describing what the page documents. | 
| var data = ''; | 
| if (_currentLibrary != null) { | 
| - data = '$data data-library="${md.escapeHtml(_currentLibrary.name)}"'; | 
| + data = '$data data-library=' | 
| + '"${md.escapeHtml(_currentLibrary.simpleName())}"'; | 
| } | 
| if (_currentType != null) { | 
| @@ -520,8 +581,8 @@ class Dartdoc { | 
| endFile(); | 
| } | 
| - void docIndexLibrary(Library library) { | 
| - writeln('<h4>${a(libraryUrl(library), library.name)}</h4>'); | 
| + void docIndexLibrary(LibraryMirror library) { | 
| + writeln('<h4>${a(libraryUrl(library), library.simpleName())}</h4>'); | 
| } | 
| /** | 
| @@ -531,29 +592,28 @@ class Dartdoc { | 
| void docNavigationJson() { | 
| startFile('nav.json'); | 
| - final libraries = {}; | 
| + final libraryMap = {}; | 
| for (final library in _sortedLibraries) { | 
| - docLibraryNavigationJson(library, libraries); | 
| + docLibraryNavigationJson(library, libraryMap); | 
| } | 
| - writeln(JSON.stringify(libraries)); | 
| + writeln(JSON.stringify(libraryMap)); | 
| endFile(); | 
| } | 
| - void docLibraryNavigationJson(Library library, Map libraries) { | 
| + void docLibraryNavigationJson(LibraryMirror library, Map libraryMap) { | 
| final types = []; | 
| - for (final type in orderByName(library.types)) { | 
| - if (type.isTop) continue; | 
| - if (type.name.startsWith('_')) continue; | 
| + for (final type in orderByName(library.types().getValues())) { | 
| + if (type.isPrivate) continue; | 
| final kind = type.isClass ? 'class' : 'interface'; | 
| final url = typeUrl(type); | 
| types.add({ 'name': typeName(type), 'kind': kind, 'url': url }); | 
| } | 
| - libraries[library.name] = types; | 
| + libraryMap[library.simpleName()] = types; | 
| } | 
| void docNavigation() { | 
| @@ -567,9 +627,9 @@ class Dartdoc { | 
| write('<h2><div class="icon-library"></div>'); | 
| if ((_currentLibrary == library) && (_currentType == null)) { | 
| - write('<strong>${library.name}</strong>'); | 
| + write('<strong>${library.simpleName()}</strong>'); | 
| } else { | 
| - write('${a(libraryUrl(library), library.name)}'); | 
| + write('${a(libraryUrl(library), library.simpleName())}'); | 
| } | 
| write('</h2>'); | 
| @@ -582,16 +642,15 @@ class Dartdoc { | 
| } | 
| /** Writes the navigation for the types contained by the given library. */ | 
| - void docLibraryNavigation(Library library) { | 
| + void docLibraryNavigation(LibraryMirror library) { | 
| // Show the exception types separately. | 
| - final types = <Type>[]; | 
| - final exceptions = <Type>[]; | 
| + final types = <InterfaceMirror>[]; | 
| + final exceptions = <InterfaceMirror>[]; | 
| - for (final type in orderByName(library.types)) { | 
| - if (type.isTop) continue; | 
| - if (type.name.startsWith('_')) continue; | 
| + for (final type in orderByName(library.types().getValues())) { | 
| + if (type.isPrivate) continue; | 
| - if (type.name.endsWith('Exception')) { | 
| + if (isException(type)) { | 
| exceptions.add(type); | 
| } else { | 
| types.add(type); | 
| @@ -607,9 +666,9 @@ class Dartdoc { | 
| } | 
| /** Writes a linked navigation list item for the given type. */ | 
| - void docTypeNavigation(Type type) { | 
| + void docTypeNavigation(InterfaceMirror type) { | 
| var icon = 'interface'; | 
| - if (type.name.endsWith('Exception')) { | 
| + if (type.simpleName().endsWith('Exception')) { | 
| icon = 'exception'; | 
| } else if (type.isClass) { | 
| icon = 'class'; | 
| @@ -626,15 +685,18 @@ class Dartdoc { | 
| writeln('</li>'); | 
| } | 
| - void docLibrary(Library library) { | 
| + void docLibrary(LibraryMirror library) { | 
| + if (verbose) { | 
| + print('Library \'${library.simpleName()}\':'); | 
| + } | 
| _totalLibraries++; | 
| _currentLibrary = library; | 
| _currentType = null; | 
| startFile(libraryUrl(library)); | 
| - writeHeader('${library.name} Library', | 
| - [library.name, libraryUrl(library)]); | 
| - writeln('<h2><strong>${library.name}</strong> library</h2>'); | 
| + writeHeader('${library.simpleName()} Library', | 
| + [library.simpleName(), libraryUrl(library)]); | 
| + writeln('<h2><strong>${library.simpleName()}</strong> library</h2>'); | 
| // Look for a comment for the entire library. | 
| final comment = getLibraryComment(library); | 
| @@ -643,18 +705,17 @@ class Dartdoc { | 
| } | 
| // Document the top-level members. | 
| - docMembers(library.topType); | 
| + docMembers(library); | 
| // Document the types. | 
| - final classes = <Type>[]; | 
| - final interfaces = <Type>[]; | 
| - final exceptions = <Type>[]; | 
| + final classes = <InterfaceMirror>[]; | 
| + final interfaces = <InterfaceMirror>[]; | 
| + final exceptions = <InterfaceMirror>[]; | 
| - for (final type in orderByName(library.types)) { | 
| - if (type.isTop) continue; | 
| - if (type.name.startsWith('_')) continue; | 
| + for (final type in orderByName(library.types().getValues())) { | 
| + if (type.isPrivate) continue; | 
| - if (type.name.endsWith('Exception')) { | 
| + if (isException(type)) { | 
| exceptions.add(type); | 
| } else if (type.isClass) { | 
| classes.add(type); | 
| @@ -670,14 +731,15 @@ class Dartdoc { | 
| writeFooter(); | 
| endFile(); | 
| - for (final type in library.types.getValues()) { | 
| - if (type.isTop) continue; | 
| - if (type.name.startsWith('_')) continue; | 
| + for (final type in library.types().getValues()) { | 
| + //if (type.isTop) continue; | 
| + if (type.isPrivate) continue; | 
| + | 
| docType(type); | 
| } | 
| } | 
| - void docTypes(List<Type> types, String header) { | 
| + void docTypes(List<InterfaceMirror> types, String header) { | 
| if (types.length == 0) return; | 
| writeln('<h3>$header</h3>'); | 
| @@ -694,26 +756,37 @@ class Dartdoc { | 
| } | 
| } | 
| - void docType(Type type) { | 
| + void docType(InterfaceMirror type) { | 
| + if (verbose) { | 
| + print('- ${type.simpleName()}'); | 
| + } | 
| _totalTypes++; | 
| _currentType = type; | 
| startFile(typeUrl(type)); | 
| + var kind = 'Interface'; | 
| + if (type.isTypedef) { | 
| + kind = 'Typedef'; | 
| + } else if (type.isClass) { | 
| + kind = 'Class'; | 
| + } | 
| + | 
| final typeTitle = | 
| - '${typeName(type)} ${type.isClass ? "Class" : "Interface"}'; | 
| - writeHeader('$typeTitle / ${type.library.name} Library', | 
| - [type.library.name, libraryUrl(type.library), | 
| + '${typeName(type)} ${kind}'; | 
| + writeHeader('$typeTitle / ${type.library().simpleName()} Library', | 
| + [type.library().simpleName(), libraryUrl(type.library()), | 
| typeName(type), typeUrl(type)]); | 
| writeln( | 
| ''' | 
| <h2><strong>${typeName(type, showBounds: true)}</strong> | 
| - ${type.isClass ? "Class" : "Interface"} | 
| + $kind | 
| </h2> | 
| '''); | 
| - docCode(type.span, getTypeComment(type)); | 
| + docCode(type.location(), getTypeComment(type)); | 
| docInheritance(type); | 
| + docTypedef(type); | 
| docConstructors(type); | 
| docMembers(type); | 
| @@ -732,9 +805,9 @@ class Dartdoc { | 
| * an icon and the type's name. It's similar to how types appear in the | 
| * navigation, but is suitable for inline (as opposed to in a `<ul>`) use. | 
| */ | 
| - void typeSpan(Type type) { | 
| + void typeSpan(InterfaceMirror type) { | 
| var icon = 'interface'; | 
| - if (type.name.endsWith('Exception')) { | 
| + if (type.simpleName().endsWith('Exception')) { | 
| icon = 'exception'; | 
| } else if (type.isClass) { | 
| icon = 'class'; | 
| @@ -754,7 +827,7 @@ class Dartdoc { | 
| * subclasses, superclasses, subinterfaces, superinferfaces, and default | 
| * class. | 
| */ | 
| - void docInheritance(Type type) { | 
| + void docInheritance(InterfaceMirror type) { | 
| // Don't show the inheritance details for Object. It doesn't have any base | 
| // class (obviously) and it has too many subclasses to be useful. | 
| if (type.isObject) return; | 
| @@ -764,30 +837,36 @@ class Dartdoc { | 
| if (types == null) return; | 
| // Skip private types. | 
| - final publicTypes = types.filter((type) => !type.name.startsWith('_')); | 
| + final publicTypes | 
| + = new List.from(types).filter((t) => !t.isPrivate); | 
| if (publicTypes.length == 0) return; | 
| writeln('<h3>$header</h3>'); | 
| writeln('<p>'); | 
| bool first = true; | 
| - for (final type in publicTypes) { | 
| + for (final t in publicTypes) { | 
| if (!first) write(', '); | 
| - typeSpan(type); | 
| + typeSpan(t); | 
| first = false; | 
| } | 
| writeln('</p>'); | 
| } | 
| + final subtypes = []; | 
| + for (final subtype in computeSubdeclarations(type)) { | 
| + subtypes.add(subtype); | 
| + } | 
| + subtypes.sort((x, y) => x.simpleName().compareTo(y.simpleName())); | 
| if (type.isClass) { | 
| // Show the chain of superclasses. | 
| - if (!type.parent.isObject) { | 
| + if (!type.superclass().isObject) { | 
| final supertypes = []; | 
| - var thisType = type.parent; | 
| + var thisType = type.superclass(); | 
| // As a sanity check, only show up to five levels of nesting, otherwise | 
| // the box starts to get hideous. | 
| do { | 
| supertypes.add(thisType); | 
| - thisType = thisType.parent; | 
| + thisType = thisType.superclass(); | 
| } while (!thisType.isObject); | 
| writeln('<h3>Extends</h3>'); | 
| @@ -802,41 +881,26 @@ class Dartdoc { | 
| writeln('</p>'); | 
| } | 
| - // Find the immediate declared subclasses (Type.subtypes includes many | 
| - // transitive subtypes). | 
| - final subtypes = []; | 
| - for (final subtype in type.subtypes) { | 
| - if (subtype.parent == type) subtypes.add(subtype); | 
| - } | 
| - subtypes.sort((a, b) => a.name.compareTo(b.name)); | 
| - | 
| listTypes(subtypes, 'Subclasses'); | 
| - listTypes(type.interfaces, 'Implements'); | 
| + listTypes(type.interfaces().getValues(), 'Implements'); | 
| } else { | 
| // Show the default class. | 
| - if (type.genericType.defaultType != null) { | 
| - listTypes([type.genericType.defaultType], 'Default class'); | 
| + if (type.defaultType() != null) { | 
| + listTypes([type.defaultType()], 'Default class'); | 
| } | 
| // List extended interfaces. | 
| - listTypes(type.interfaces, 'Extends'); | 
| + listTypes(type.interfaces().getValues(), 'Extends'); | 
| // List subinterfaces and implementing classes. | 
| final subinterfaces = []; | 
| final implementing = []; | 
| - for (final subtype in type.subtypes) { | 
| - // We only want explicitly declared subinterfaces, so check that this | 
| - // type is a superinterface. | 
| - for (final supertype in subtype.interfaces) { | 
| - if (supertype == type) { | 
| - if (subtype.isClass) { | 
| - implementing.add(subtype); | 
| - } else { | 
| - subinterfaces.add(subtype); | 
| - } | 
| - break; | 
| - } | 
| + for (final subtype in subtypes) { | 
| + if (subtype.isClass) { | 
| + implementing.add(subtype); | 
| + } else { | 
| + subinterfaces.add(subtype); | 
| } | 
| } | 
| @@ -845,38 +909,69 @@ class Dartdoc { | 
| } | 
| } | 
| + /** | 
| + * Documents the [method] in type [type]. Handles all kinds of methods | 
| + * including getters, setters, and constructors. | 
| + */ | 
| + void docTypedef(TypeMirror type) { | 
| + if (type is! TypedefMirror) { | 
| + return; | 
| + } | 
| + writeln('<div class="method"><h4 id="${type.simpleName()}">'); | 
| + | 
| + if (includeSource) { | 
| + writeln('<span class="show-code">Code</span>'); | 
| + } | 
| + | 
| + if (type.definition() !== null) { | 
| + // TODO(johnniwinther): Implement [:TypedefMirror.definition():]. | 
| + write('typedef '); | 
| + annotateType(type, type.definition(), type.simpleName()); | 
| + | 
| + write(''' <a class="anchor-link" href="#${type.simpleName()}" | 
| + title="Permalink to ${type.simpleName()}">#</a>'''); | 
| + } | 
| + writeln('</h4>'); | 
| + | 
| + docCode(type.location(), null, showCode: true); | 
| + | 
| + writeln('</div>'); | 
| + } | 
| + | 
| /** Document the constructors for [Type], if any. */ | 
| - void docConstructors(Type type) { | 
| - final names = type.constructors.getKeys().filter( | 
| - (name) => !name.startsWith('_')); | 
| + void docConstructors(InterfaceMirror type) { | 
| + final constructors = <MethodMirror>[]; | 
| + for (var constructor in type.constructors().getValues()) { | 
| + if (!constructor.isPrivate) { | 
| + constructors.add(constructor); | 
| + } | 
| + } | 
| - if (names.length > 0) { | 
| + if (constructors.length > 0) { | 
| writeln('<h3>Constructors</h3>'); | 
| - names.sort((x, y) => x.toUpperCase().compareTo(y.toUpperCase())); | 
| + constructors.sort((x, y) => x.simpleName().toUpperCase().compareTo( | 
| + y.simpleName().toUpperCase())); | 
| - for (final name in names) { | 
| - docMethod(type, type.constructors[name], constructorName: name); | 
| + for (final constructor in constructors) { | 
| + docMethod(type, constructor); | 
| } | 
| } | 
| } | 
| - void docMembers(Type type) { | 
| + void docMembers(ObjectMirror host) { | 
| // Collect the different kinds of members. | 
| final staticMethods = []; | 
| final staticFields = []; | 
| final instanceMethods = []; | 
| final instanceFields = []; | 
| - for (final member in orderByName(type.members)) { | 
| - if (member.name.startsWith('_')) continue; | 
| + for (final member in orderByName(host.declaredMembers().getValues())) { | 
| + if (member.isPrivate) continue; | 
| final methods = member.isStatic ? staticMethods : instanceMethods; | 
| final fields = member.isStatic ? staticFields : instanceFields; | 
| - if (member.isProperty) { | 
| - if (member.canGet) methods.add(member.getter); | 
| - if (member.canSet) methods.add(member.setter); | 
| - } else if (member.isMethod) { | 
| + if (member.isMethod) { | 
| methods.add(member); | 
| } else if (member.isField) { | 
| fields.add(member); | 
| @@ -884,25 +979,33 @@ class Dartdoc { | 
| } | 
| if (staticMethods.length > 0) { | 
| - final title = type.isTop ? 'Functions' : 'Static Methods'; | 
| + final title = host is LibraryMirror ? 'Functions' : 'Static Methods'; | 
| writeln('<h3>$title</h3>'); | 
| - for (final method in staticMethods) docMethod(type, method); | 
| + for (final method in orderByName(staticMethods)) { | 
| + docMethod(host, method); | 
| + } | 
| } | 
| if (staticFields.length > 0) { | 
| - final title = type.isTop ? 'Variables' : 'Static Fields'; | 
| + final title = host is LibraryMirror ? 'Variables' : 'Static Fields'; | 
| writeln('<h3>$title</h3>'); | 
| - for (final field in staticFields) docField(type, field); | 
| + for (final field in orderByName(staticFields)) { | 
| + docField(host, field); | 
| + } | 
| } | 
| if (instanceMethods.length > 0) { | 
| writeln('<h3>Methods</h3>'); | 
| - for (final method in instanceMethods) docMethod(type, method); | 
| + for (final method in orderByName(instanceMethods)) { | 
| + docMethod(host, method); | 
| + } | 
| } | 
| if (instanceFields.length > 0) { | 
| writeln('<h3>Fields</h3>'); | 
| - for (final field in instanceFields) docField(type, field); | 
| + for (final field in orderByName(instanceFields)) { | 
| + docField(host, field); | 
| + } | 
| } | 
| } | 
| @@ -910,8 +1013,7 @@ class Dartdoc { | 
| * Documents the [method] in type [type]. Handles all kinds of methods | 
| * including getters, setters, and constructors. | 
| */ | 
| - void docMethod(Type type, MethodMember method, | 
| - [String constructorName = null]) { | 
| + void docMethod(ObjectMirror host, MethodMirror method) { | 
| _totalMembers++; | 
| _currentMember = method; | 
| @@ -922,57 +1024,54 @@ class Dartdoc { | 
| } | 
| if (method.isConstructor) { | 
| - write(method.isConst ? 'const ' : 'new '); | 
| + if (method.isFactory) { | 
| + write('factory '); | 
| + } else { | 
| + write(method.isConst ? 'const ' : 'new '); | 
| + } | 
| } | 
| - if (constructorName == null) { | 
| - annotateType(type, method.returnType); | 
| + if (method.constructorName == null) { | 
| + annotateType(host, method.returnType()); | 
| } | 
| + var name = method.simpleName(); | 
| // Translate specially-named methods: getters, setters, operators. | 
| - var name = method.name; | 
| - if (name.startsWith('get:')) { | 
| + if (method.isGetter) { | 
| // Getter. | 
| - name = 'get ${name.substring(4)}'; | 
| - } else if (name.startsWith('set:')) { | 
| + name = 'get $name'; | 
| + } else if (method.isSetter) { | 
| // Setter. | 
| - name = 'set ${name.substring(4)}'; | 
| - } else if (name == ':negate') { | 
| - // Dart uses 'negate' for prefix negate operators, not '!'. | 
| - name = 'operator negate'; | 
| + name = 'set $name'; | 
| + } else if (method.isOperator) { | 
| + name = 'operator ${method.operatorName}'; | 
| } else if (name == ':call') { | 
| + // TODO(johnniwinther): Not (currently) used with mirrors. | 
| name = 'operator call'; | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
There is no "operator call", nor will there be one
 
Johnni Winther
2012/07/09 14:57:18
Done.
 
 | 
| - } else { | 
| - // See if it's an operator. | 
| - name = TokenKind.rawOperatorFromMethod(name); | 
| - if (name == null) { | 
| - name = method.name; | 
| - } else { | 
| - name = 'operator $name'; | 
| - } | 
| } | 
| write('<strong>$name</strong>'); | 
| // Named constructors. | 
| - if (constructorName != null && constructorName != '') { | 
| + if (method.constructorName != null && method.constructorName != '') { | 
| write('.'); | 
| - write(constructorName); | 
| + write(method.constructorName); | 
| } | 
| - docParamList(type, method); | 
| + docParamList(host, method.parameters()); | 
| + var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; | 
| write(''' <a class="anchor-link" href="#${memberAnchor(method)}" | 
| - title="Permalink to ${typeName(type)}.$name">#</a>'''); | 
| + title="Permalink to $prefix$name">#</a>'''); | 
| writeln('</h4>'); | 
| - docCode(method.span, getMethodComment(method), showCode: true); | 
| + docCode(method.location(), getMethodComment(method), showCode: true); | 
| writeln('</div>'); | 
| } | 
| /** Documents the field [field] of type [type]. */ | 
| - void docField(Type type, FieldMember field) { | 
| + void docField(ObjectMirror host, FieldMirror field) { | 
| _totalMembers++; | 
| _currentMember = field; | 
| @@ -984,39 +1083,41 @@ class Dartdoc { | 
| if (field.isFinal) { | 
| write('final '); | 
| - } else if (field.type.name == 'Dynamic') { | 
| + } else if (field.type().isDynamic) { | 
| write('var '); | 
| } | 
| - annotateType(type, field.type); | 
| + annotateType(host, field.type()); | 
| + var prefix = host is LibraryMirror ? '' : '${typeName(host)}.'; | 
| write( | 
| ''' | 
| - <strong>${field.name}</strong> <a class="anchor-link" | 
| + <strong>${field.simpleName()}</strong> <a class="anchor-link" | 
| href="#${memberAnchor(field)}" | 
| - title="Permalink to ${typeName(type)}.${field.name}">#</a> | 
| + title="Permalink to $prefix${field.simpleName()}">#</a> | 
| </h4> | 
| '''); | 
| - docCode(field.span, getFieldComment(field), showCode: true); | 
| + docCode(field.location(), getFieldComment(field), showCode: true); | 
| writeln('</div>'); | 
| } | 
| - void docParamList(Type enclosingType, MethodMember member) { | 
| + void docParamList(ObjectMirror enclosingType, | 
| + List<ParameterMirror> parameters) { | 
| write('('); | 
| bool first = true; | 
| bool inOptionals = false; | 
| - for (final parameter in member.parameters) { | 
| + for (final parameter in parameters) { | 
| if (!first) write(', '); | 
| - if (!inOptionals && parameter.isOptional) { | 
| + if (!inOptionals && parameter.isOptional()) { | 
| write('['); | 
| inOptionals = true; | 
| } | 
| - annotateType(enclosingType, parameter.type, parameter.name); | 
| + annotateType(enclosingType, parameter.type(), parameter.simpleName()); | 
| // Show the default value for named optional parameters. | 
| - if (parameter.isOptional && parameter.hasDefaultValue) { | 
| + if (parameter.isOptional() && parameter.hasDefaultValue()) { | 
| write(' = '); | 
| // TODO(rnystrom): Using the definition text here is a bit cheap. | 
| // We really should be pretty-printing the AST so that if you have: | 
| @@ -1024,7 +1125,7 @@ class Dartdoc { | 
| // the docs should just show: | 
| // foo([arg = 1 + 2]) | 
| // For now, we'll assume you don't do that. | 
| - write(parameter.definition.value.span.text); | 
| + write(parameter.defaultValue()); | 
| } | 
| first = false; | 
| @@ -1038,7 +1139,7 @@ class Dartdoc { | 
| * Documents the code contained within [span] with [comment]. If [showCode] | 
| * is `true` (and [includeSource] is set), also includes the source code. | 
| */ | 
| - void docCode(SourceSpan span, String comment, [bool showCode = false]) { | 
| + void docCode(Location location, String comment, [bool showCode = false]) { | 
| writeln('<div class="doc">'); | 
| if (comment != null) { | 
| writeln(comment); | 
| @@ -1046,7 +1147,7 @@ class Dartdoc { | 
| if (includeSource && showCode) { | 
| writeln('<pre class="source">'); | 
| - writeln(md.escapeHtml(unindentCode(span))); | 
| + writeln(md.escapeHtml(unindentCode(location))); | 
| writeln('</pre>'); | 
| } | 
| @@ -1055,9 +1156,9 @@ class Dartdoc { | 
| /** Get the doc comment associated with the given library. */ | 
| - String getLibraryComment(Library library) { | 
| + String getLibraryComment(LibraryMirror library) { | 
| // Look for a comment for the entire library. | 
| - final comment = _comments.findLibrary(library.baseSource); | 
| + final comment = _comments.findLibrary(library.location().source()); | 
| if (comment != null) { | 
| return md.markdownToHtml(comment); | 
| } | 
| @@ -1065,22 +1166,22 @@ class Dartdoc { | 
| } | 
| /** Get the doc comment associated with the given type. */ | 
| - String getTypeComment(Type type) { | 
| - String comment = _comments.find(type.span); | 
| + String getTypeComment(TypeMirror type) { | 
| + String comment = _comments.find(type.location()); | 
| if (comment == null) return null; | 
| return commentToHtml(comment); | 
| } | 
| /** Get the doc comment associated with the given method. */ | 
| - String getMethodComment(MethodMember method) { | 
| - String comment = _comments.find(method.span); | 
| + String getMethodComment(MethodMirror method) { | 
| + String comment = _comments.find(method.location()); | 
| if (comment == null) return null; | 
| return commentToHtml(comment); | 
| } | 
| /** Get the doc comment associated with the given field. */ | 
| - String getFieldComment(FieldMember field) { | 
| - String comment = _comments.find(field.span); | 
| + String getFieldComment(FieldMirror field) { | 
| + String comment = _comments.find(field.location()); | 
| if (comment == null) return null; | 
| return commentToHtml(comment); | 
| } | 
| @@ -1109,30 +1210,33 @@ class Dartdoc { | 
| } | 
| /** Gets the URL to the documentation for [library]. */ | 
| - String libraryUrl(Library library) { | 
| - return '${sanitize(library.name)}.html'; | 
| + String libraryUrl(LibraryMirror library) { | 
| + return '${sanitize(library.simpleName())}.html'; | 
| } | 
| /** Gets the URL for the documentation for [type]. */ | 
| - String typeUrl(Type type) { | 
| - if (type.isTop) return '${sanitize(type.library.name)}.html'; | 
| + String typeUrl(ObjectMirror type) { | 
| + if (type is LibraryMirror) return '${sanitize(type.simpleName())}.html'; | 
| + assert (type is TypeMirror); | 
| // Always get the generic type to strip off any type parameters or | 
| // arguments. If the type isn't generic, genericType returns `this`, so it | 
| // works for non-generic types too. | 
| - return '${sanitize(type.library.name)}/${type.genericType.name}.html'; | 
| + return '${sanitize(type.library().simpleName())}/' | 
| + '${type.declaration.simpleName()}.html'; | 
| } | 
| /** Gets the URL for the documentation for [member]. */ | 
| - String memberUrl(Member member) { | 
| - final typeUrl = typeUrl(member.declaringType); | 
| - if (!member.isConstructor) return '$typeUrl#${member.name}'; | 
| - if (member.constructorName == '') return '$typeUrl#new:${member.name}'; | 
| - return '$typeUrl#new:${member.name}.${member.constructorName}'; | 
| + String memberUrl(MemberMirror member) { | 
| + final url = typeUrl(member.surroundingDeclaration()); | 
| + if (!member.isConstructor) return '$url#${member.simpleName()}'; | 
| + assert (member is MethodMirror); | 
| + if (member.constructorName == '') return '$url#new:${member.simpleName()}'; | 
| + return '$url#new:${member.simpleName()}.${member.constructorName}'; | 
| } | 
| /** Gets the anchor id for the document for [member]. */ | 
| - String memberAnchor(Member member) { | 
| - return '${member.name}'; | 
| + String memberAnchor(MemberMirror member) { | 
| + return '${member.simpleName()}'; | 
| } | 
| /** | 
| @@ -1149,23 +1253,23 @@ class Dartdoc { | 
| /** | 
| * Writes a type annotation for the given type and (optional) parameter name. | 
| */ | 
| - annotateType(Type enclosingType, Type type, [String paramName = null]) { | 
| + annotateType(ObjectMirror enclosingType, | 
| + TypeMirror type, | 
| + [String paramName = null]) { | 
| // Don't bother explicitly displaying Dynamic. | 
| - if (type.isVar) { | 
| + if (type.isDynamic) { | 
| if (paramName !== null) write(paramName); | 
| return; | 
| } | 
| // For parameters, handle non-typedefed function types. | 
| - if (paramName !== null) { | 
| - final call = type.getCallMethod(); | 
| - if (call != null) { | 
| - annotateType(enclosingType, call.returnType); | 
| - write(paramName); | 
| + if (paramName !== null && type is FunctionTypeMirror) { | 
| + //print('$paramName: $type'); | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
Remove commented code.
 
Johnni Winther
2012/07/09 14:57:18
Done.
 
 | 
| + annotateType(enclosingType, type.returnType()); | 
| + write(paramName); | 
| - docParamList(enclosingType, call); | 
| - return; | 
| - } | 
| + docParamList(enclosingType, type.parameters()); | 
| + return; | 
| } | 
| linkToType(enclosingType, type); | 
| @@ -1175,30 +1279,44 @@ class Dartdoc { | 
| } | 
| /** Writes a link to a human-friendly string representation for a type. */ | 
| - linkToType(Type enclosingType, Type type) { | 
| - if (type is ParameterType) { | 
| + linkToType(ObjectMirror enclosingType, TypeMirror type) { | 
| + if (type.isVoid) { | 
| + // Do not generate links for void | 
| + // TODO(johnniwinter): Generate span for specific style? | 
| + write('void'); | 
| + return; | 
| + } | 
| + | 
| + if (type.isTypeVariable) { | 
| // If we're using a type parameter within the body of a generic class then | 
| // just link back up to the class. | 
| - write(a(typeUrl(enclosingType), type.name)); | 
| + write(a(typeUrl(enclosingType), type.simpleName())); | 
| return; | 
| } | 
| + assert (type is InterfaceMirror); // type is a interface | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
No space after assert.
"... is an interface", but
 
Johnni Winther
2012/07/09 14:57:18
Done.
 
 | 
| + | 
| // Link to the type. | 
| // Use .genericType to avoid writing the <...> here. | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
Comment out of sync.
 
Johnni Winther
2012/07/09 14:57:18
It doesn't apply anymore.
 
 | 
| - write(a(typeUrl(type), type.genericType.name)); | 
| + if (includeLibrary(type.library())) { | 
| + write(a(typeUrl(type), type.declaration.simpleName())); | 
| + } else { | 
| + write(type.declaration.simpleName()); | 
| + } | 
| // See if it's a generic type. | 
| - if (type.isGeneric) { | 
| + if (type.isDeclaration) { | 
| // TODO(rnystrom): This relies on a weird corner case of frog. Currently, | 
| // the only time we get into this case is when we have a "raw" generic | 
| // that's been instantiated with Dynamic for all type arguments. It's kind | 
| // of strange that frog works that way, but we take advantage of it to | 
| // show raw types without any type arguments. | 
| + // TODO(johnniwinter): Does this still apply? | 
| return; | 
| } | 
| // See if it's an instantiation of a generic type. | 
| - final typeArgs = type.typeArgsInOrder; | 
| + final typeArgs = type.typeArguments(); | 
| if (typeArgs.length > 0) { | 
| write('<'); | 
| bool first = true; | 
| @@ -1212,49 +1330,59 @@ class Dartdoc { | 
| } | 
| /** Creates a linked cross reference to [type]. */ | 
| - typeReference(Type type) { | 
| + typeReference(InterfaceMirror type) { | 
| // TODO(rnystrom): Do we need to handle ParameterTypes here like | 
| // annotation() does? | 
| return a(typeUrl(type), typeName(type), css: 'crossref'); | 
| } | 
| /** Generates a human-friendly string representation for a type. */ | 
| - typeName(Type type, [bool showBounds = false]) { | 
| + typeName(TypeMirror type, [bool showBounds = false]) { | 
| + if (type.isVoid) { | 
| + return 'void'; | 
| + } | 
| + if (type is TypeVariableMirror) { | 
| + return type.simpleName(); | 
| + } | 
| + assert (type is InterfaceMirror); | 
| + | 
| // See if it's a generic type. | 
| - if (type.isGeneric) { | 
| + if (type.isDeclaration) { | 
| final typeParams = []; | 
| - for (final typeParam in type.genericType.typeParameters) { | 
| + for (final typeParam in type.declaration.typeVariables()) { | 
| if (showBounds && | 
| - (typeParam.extendsType != null) && | 
| - !typeParam.extendsType.isObject) { | 
| - final bound = typeName(typeParam.extendsType, showBounds: true); | 
| - typeParams.add('${typeParam.name} extends $bound'); | 
| + (typeParam.bound() != null) && | 
| + !typeParam.bound().isObject) { | 
| + final bound = typeName(typeParam.bound(), showBounds: true); | 
| + typeParams.add('${typeParam.simpleName()} extends $bound'); | 
| } else { | 
| - typeParams.add(typeParam.name); | 
| + typeParams.add(typeParam.simpleName()); | 
| } | 
| } | 
| - | 
| + if (typeParams.isEmpty()) { | 
| + return type.simpleName(); | 
| + } | 
| final params = Strings.join(typeParams, ', '); | 
| - return '${type.name}<$params>'; | 
| + return '${type.simpleName()}<$params>'; | 
| } | 
| // See if it's an instantiation of a generic type. | 
| - final typeArgs = type.typeArgsInOrder; | 
| + final typeArgs = type.typeArguments(); | 
| if (typeArgs.length > 0) { | 
| - final args = Strings.join(map(typeArgs, (arg) => typeName(arg)), ', '); | 
| - return '${type.genericType.name}<$args>'; | 
| + final args = Strings.join(typeArgs.map((arg) => typeName(arg)), ', '); | 
| + return '${type.declaration.simpleName()}<$args>'; | 
| } | 
| // Regular type. | 
| - return type.name; | 
| + return type.simpleName(); | 
| } | 
| /** | 
| * Remove leading indentation to line up with first line. | 
| */ | 
| - unindentCode(SourceSpan span) { | 
| + unindentCode(Location span) { | 
| final column = getSpanColumn(span); | 
| - final lines = span.text.split('\n'); | 
| + final lines = span.text().split('\n'); | 
| // TODO(rnystrom): Dirty hack. | 
| for (var i = 1; i < lines.length; i++) { | 
| lines[i] = unindent(lines[i], column); | 
| @@ -1267,11 +1395,11 @@ class Dartdoc { | 
| /** | 
| * Takes a string of Dart code and turns it into sanitized HTML. | 
| */ | 
| - formatCode(SourceSpan span) { | 
| + formatCode(Location span) { | 
| final code = unindentCode(span); | 
| // Syntax highlight. | 
| - return classifySource(new SourceFile('', code)); | 
| + return classifySource(code); | 
| } | 
| /** | 
| @@ -1279,8 +1407,10 @@ class Dartdoc { | 
| * brackets. It will try to figure out what the name refers to and link or | 
| * style it appropriately. | 
| */ | 
| - md.Node resolveNameReference(String name, [Member member = null, | 
| - Type type = null, Library library = null]) { | 
| + md.Node resolveNameReference(String name, | 
| + [MemberMirror member = null, | 
| + ObjectMirror type = null, | 
| + LibraryMirror library = null]) { | 
| makeLink(String href) { | 
| final anchor = new md.Element.text('a', name); | 
| anchor.attributes['href'] = relativePath(href); | 
| @@ -1288,24 +1418,10 @@ class Dartdoc { | 
| return anchor; | 
| } | 
| - findMember(Type type, String memberName) { | 
| - final member = type.members[memberName]; | 
| - if (member == null) return null; | 
| - | 
| - // Special case: if the member we've resolved is a property (i.e. it wraps | 
| - // a getter and/or setter then *that* member itself won't be on the docs, | 
| - // just the getter or setter will be. So pick one of those to link to. | 
| - if (member.isProperty) { | 
| - return member.canGet ? member.getter : member.setter; | 
| - } | 
| - | 
| - return member; | 
| - } | 
| - | 
| // See if it's a parameter of the current method. | 
| - if (member != null) { | 
| - for (final parameter in member.parameters) { | 
| - if (parameter.name == name) { | 
| + if (member is MethodMirror) { | 
| + for (final parameter in member.parameters()) { | 
| + if (parameter.simpleName() == name) { | 
| final element = new md.Element.text('span', name); | 
| element.attributes['class'] = 'param'; | 
| return element; | 
| @@ -1315,7 +1431,7 @@ class Dartdoc { | 
| // See if it's another member of the current type. | 
| if (type != null) { | 
| - final member = findMember(type, name); | 
| + final member = findMirror(type.declaredMembers(), name); | 
| if (member != null) { | 
| return makeLink(memberUrl(member)); | 
| } | 
| @@ -1328,10 +1444,11 @@ class Dartdoc { | 
| final constructorLink = (() { | 
| final match = new RegExp(@'new (\w+)(?:\.(\w+))?').firstMatch(name); | 
| 
 
Lasse Reichstein Nielsen
2012/07/09 10:39:33
This uses \w for identifiers, which misses "$" as
 
Johnni Winther
2012/07/09 14:57:18
Done.
 
 | 
| if (match == null) return; | 
| - final type = library.types[match[1]]; | 
| + final type = findMirror(library.types(), match[1]); | 
| if (type == null) return; | 
| - final constructor = type.getConstructor( | 
| - match[2] == null ? '' : match[2]); | 
| + final constructor = | 
| + findMirror(type.constructors(), | 
| + match[2] == null ? '' : match[2]); | 
| if (constructor == null) return; | 
| return makeLink(memberUrl(constructor)); | 
| })(); | 
| @@ -1341,21 +1458,21 @@ class Dartdoc { | 
| final foreignMemberLink = (() { | 
| final match = new RegExp(@'(\w+)\.(\w+)').firstMatch(name); | 
| if (match == null) return; | 
| - final type = library.types[match[1]]; | 
| + final type = findMirror(library.types(), match[1]); | 
| if (type == null) return; | 
| - final member = findMember(type, match[2]); | 
| + final member = findMirror(type.declaredMembers(), match[2]); | 
| if (member == null) return; | 
| return makeLink(memberUrl(member)); | 
| })(); | 
| if (foreignMemberLink != null) return foreignMemberLink; | 
| - final type = library.types[name]; | 
| + final type = findMirror(library.types(), name); | 
| if (type != null) { | 
| return makeLink(typeUrl(type)); | 
| } | 
| // See if it's a top-level member in the current library. | 
| - final member = findMember(library.topType, name); | 
| + final member = findMirror(library.declaredMembers(), name); | 
| if (member != null) { | 
| return makeLink(memberUrl(member)); | 
| } | 
| @@ -1368,10 +1485,19 @@ class Dartdoc { | 
| return new md.Element.text('code', name); | 
| } | 
| - // TODO(rnystrom): Move into SourceSpan? | 
| - int getSpanColumn(SourceSpan span) { | 
| - final line = span.file.getLine(span.start); | 
| - return span.file.getColumn(line, span.start); | 
| + int getSpanColumn(Location span) { | 
| + String text = span.source().text(); | 
| + int index = span.start()-1; | 
| + var column = 0; | 
| + while (0 <= index && index < text.length) { | 
| + var charCode = text.charCodeAt(index); | 
| + if (charCode == $CR || charCode == $LF) { | 
| + break; | 
| + } | 
| + index--; | 
| + column++; | 
| + } | 
| + return column; | 
| } | 
| generateAppCacheManifest() { | 
| @@ -1394,4 +1520,12 @@ class Dartdoc { | 
| toCache.onDone = (done) => endFile(); | 
| toCache.list(recursive: true); | 
| } | 
| + | 
| + /** | 
| + * Returns [:true:] if [type] should be regarded as an exception. | 
| + */ | 
| + bool isException(TypeMirror type) { | 
| + return type.simpleName().endsWith('Exception'); | 
| + } | 
| } | 
| + |