Chromium Code Reviews| Index: lib/dartdoc/dartdoc.dart |
| diff --git a/lib/dartdoc/dartdoc.dart b/lib/dartdoc/dartdoc.dart |
| index 63eb2b2f3ca7371cf218222f3b2f747797282413..43c0411d6a67acce79ff036aa6cadeea392085dd 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, '../'); |
| - 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,62 @@ 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 ' |
| + '${dartdoc._totalMembers} members.'); |
| + }); |
| + } |
| +} |
| - print('Documented ${dartdoc._totalLibraries} libraries, ' |
| - '${dartdoc._totalTypes} types, and ' |
| - '${dartdoc._totalMembers} members.'); |
| - }); |
| +void printUsage() { |
|
Bob Nystrom
2012/07/09 16:59:55
This is very nice, but at some point (not in this
Johnni Winther
2012/07/12 08:51:39
Yes.
|
| + 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. |
| + |
| + --out=<dir> Generates files into directory <dir>. If omitted |
| + the files are generated into ./docs/ |
| + |
| + --verbose Print verbose information during generation. |
| +'''); |
| } |
| /** |
| @@ -166,7 +214,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(); |
| + } catch (DirectoryIOException e) { |
| + // Ignore. |
| + } |
| } |
| /** |
| @@ -199,33 +254,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 |
| + // 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; |
|
Bob Nystrom
2012/07/09 16:59:55
Why have this return value if it's always true?
Johnni Winther
2012/07/12 08:51:39
Legacy code. Return type changed to void.
|
| } |
| class Dartdoc { |
| @@ -277,6 +319,12 @@ class Dartdoc { |
| /** Set this to omit generation timestamp from output */ |
| bool omitGenerationTime = false; |
| + /** Set by Dartdoc user to print extra information during generation. */ |
| + 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 |
|
Bob Nystrom
2012/07/09 16:59:55
This comment probably needs updating now.
Johnni Winther
2012/07/12 08:51:39
Done.
|
| * *keys* to [Library] objects. The keys are *not* exactly the same as their |
| @@ -284,18 +332,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 +367,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 +392,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 +433,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(); |
| + } catch (DirectoryIOException e) { |
| + // Ignore. |
| + } |
| } |
| - world.files.writeString(outPath, _file.toString()); |
| + writeString(new File(outPath), _file.toString()); |
| _filePath = null; |
| _file = null; |
| } |
| @@ -424,7 +483,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 +580,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 +591,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 +626,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 +641,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 +665,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 +684,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 +704,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 +730,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; |
|
Bob Nystrom
2012/07/09 16:59:55
Just delete this if it's dead code.
Johnni Winther
2012/07/12 08:51:39
Done.
|
| + 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 +755,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 +804,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 +826,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 +836,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); |
|
Bob Nystrom
2012/07/09 16:59:55
Style nit. I would wrap this after filter(
Johnni Winther
2012/07/12 08:51:39
Done.
|
| 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 +880,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 +908,69 @@ class Dartdoc { |
| } |
| } |
| + /** |
| + * Documents the [method] in type [type]. Handles all kinds of methods |
| + * including getters, setters, and constructors. |
|
Bob Nystrom
2012/07/09 16:59:55
Fix this comment.
Johnni Winther
2012/07/12 08:51:39
Done.
|
| + */ |
| + 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 +978,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 +1012,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 +1023,51 @@ 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'; |
| - } else if (name == ':call') { |
| - name = 'operator call'; |
| - } else { |
| - // See if it's an operator. |
| - name = TokenKind.rawOperatorFromMethod(name); |
| - if (name == null) { |
| - name = method.name; |
| - } else { |
| - name = 'operator $name'; |
| - } |
| + name = 'set $name'; |
| + } else if (method.isOperator) { |
| + name = 'operator ${method.operatorName}'; |
| } |
| 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 +1079,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 +1121,7 @@ class Dartdoc { |
| // the docs should just show: |
| // foo([arg = 1 + 2]) |
| // For now, we'll assume you don't do that. |
|
Bob Nystrom
2012/07/09 16:59:55
You can remove this comment now.
Johnni Winther
2012/07/12 08:51:39
Done.
|
| - write(parameter.definition.value.span.text); |
| + write(parameter.defaultValue()); |
| } |
| first = false; |
| @@ -1038,7 +1135,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 +1143,7 @@ class Dartdoc { |
| if (includeSource && showCode) { |
| writeln('<pre class="source">'); |
| - writeln(md.escapeHtml(unindentCode(span))); |
| + writeln(md.escapeHtml(unindentCode(location))); |
| writeln('</pre>'); |
| } |
| @@ -1055,9 +1152,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 +1162,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 +1206,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 +1249,22 @@ 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) { |
| + annotateType(enclosingType, type.returnType()); |
| + write(paramName); |
| - docParamList(enclosingType, call); |
| - return; |
| - } |
| + docParamList(enclosingType, type.parameters()); |
| + return; |
| } |
| linkToType(enclosingType, type); |
| @@ -1175,30 +1274,37 @@ 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 |
|
Bob Nystrom
2012/07/09 16:59:55
"." at end of comment.
Johnni Winther
2012/07/12 08:51:39
Done.
|
| + // 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); |
| + |
| // Link to the type. |
| - // Use .genericType to avoid writing the <...> here. |
| - write(a(typeUrl(type), type.genericType.name)); |
| + if (includeLibrary(type.library())) { |
| + write(a(typeUrl(type), type.simpleName())); |
| + } else { |
| + write(type.simpleName()); |
| + } |
| - // See if it's a generic type. |
| - if (type.isGeneric) { |
| - // 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. |
| + if (type.isDeclaration) { |
| + // Avoid calling [:typeArguments():] on a declaration. |
| 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 +1318,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'; |
| + } |
|
Bob Nystrom
2012/07/09 16:59:55
The style guide allows single-line ifs for things
|
| + 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 +1383,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 +1395,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 +1406,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 +1419,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)); |
| } |
| @@ -1326,12 +1430,13 @@ class Dartdoc { |
| if (library != null) { |
| // See if it's a constructor |
| final constructorLink = (() { |
| - final match = new RegExp(@'new (\w+)(?:\.(\w+))?').firstMatch(name); |
| + final match = new RegExp(@'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name); |
|
Bob Nystrom
2012/07/09 16:59:55
Long line.
Johnni Winther
2012/07/12 08:51:39
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)); |
| })(); |
| @@ -1339,23 +1444,23 @@ class Dartdoc { |
| // See if it's a member of another type |
| final foreignMemberLink = (() { |
| - final match = new RegExp(@'(\w+)\.(\w+)').firstMatch(name); |
| + 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 +1473,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) { |
|
Bob Nystrom
2012/07/09 16:59:55
This seems like something Location should support
Johnni Winther
2012/07/12 08:51:39
Moved to mirrors_util.dart instead. We haven't set
|
| + 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 +1508,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'); |
| + } |
| } |
| + |