Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Unified Diff: utils/dartdoc/dartdoc.dart

Issue 9555013: Get dartdoc in the SDK and working correctly. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update copyright date. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: utils/dartdoc/dartdoc.dart
diff --git a/utils/dartdoc/dartdoc.dart b/utils/dartdoc/dartdoc.dart
deleted file mode 100644
index 417234949756f9bc645b8045a65965ef773379be..0000000000000000000000000000000000000000
--- a/utils/dartdoc/dartdoc.dart
+++ /dev/null
@@ -1,1218 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * To use it, from this directory, run:
- *
- * $ ./dartdoc <path to .dart file>
- *
- * This will create a "docs" directory with the docs for your libraries. To
- * create these beautiful docs, dartdoc parses your library and every library
- * it imports (recursively). From each library, it parses all classes and
- * members, finds the associated doc comments and builds crosslinked docs from
- * them.
- */
-#library('dartdoc');
-
-#import('dart:io');
-#import('dart:json');
-#import('../../frog/lang.dart');
-#import('../../frog/file_system.dart');
-#import('../../frog/file_system_vm.dart');
-#import('classify.dart');
-#import('markdown.dart', prefix: 'md');
-
-#source('comment_map.dart');
-#source('utils.dart');
-
-/** Path to generate HTML files into. */
-final _outdir = 'docs';
-
-/**
- * Generates completely static HTML containing everything you need to browse
- * the docs. The only client side behavior is trivial stuff like syntax
- * highlighting code.
- */
-final MODE_STATIC = 0;
-
-/**
- * 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`.
- */
-final MODE_LIVE_NAV = 1;
-
-/**
- * Run this from the `utils/dartdoc` directory.
- */
-void main() {
- final args = new Options().arguments;
-
- // The entrypoint of the library to generate docs for.
- final entrypoint = args[args.length - 1];
-
- // Parse the dartdoc options.
- bool includeSource = true;
- var mode = MODE_LIVE_NAV;
-
- for (int i = 2; i < args.length - 1; i++) {
- final arg = args[i];
- switch (arg) {
- case '--no-code':
- includeSource = false;
- break;
-
- case '--mode=static':
- mode = MODE_STATIC;
- break;
-
- case '--mode=live-nav':
- mode = MODE_LIVE_NAV;
- break;
-
- default:
- print('Unknown option: $arg');
- }
- }
-
- final files = new VMFileSystem();
- parseOptions('../../frog', ['', '', '--libdir=../../frog/lib'], files);
- initializeWorld(files);
-
- var dartdoc;
- final elapsed = time(() {
- dartdoc = new Dartdoc();
- dartdoc.includeSource = includeSource;
- dartdoc.mode = mode;
-
- dartdoc.document(entrypoint);
- });
-
- print('Documented ${dartdoc._totalLibraries} libraries, ' +
- '${dartdoc._totalTypes} types, and ' +
- '${dartdoc._totalMembers} members in ${elapsed}msec.');
-}
-
-class Dartdoc {
- /** Set to `false` to not include the source code in the generated docs. */
- bool includeSource = true;
-
- /**
- * Dartdoc can generate docs in a few different ways based on how dynamic you
- * want the client-side behavior to be. The value for this should be one of
- * the `MODE_` constants.
- */
- int mode = MODE_LIVE_NAV;
-
- /**
- * The title used for the overall generated output. Set this to change it.
- */
- String mainTitle = 'Dart Documentation';
-
- /**
- * The URL that the Dart logo links to. Defaults "index.html", the main
- * page for the generated docs, but can be anything.
- */
- String mainUrl = 'index.html';
-
- /**
- * The Google Custom Search ID that should be used for the search box. If
- * this is `null` then no search box will be shown.
- */
- String searchEngineId = null;
-
- /* The URL that the embedded search results should be displayed on. */
- String searchResultsUrl = 'results.html';
-
- /** Set this to add footer text to each generated page. */
- String footerText = '';
-
- /**
- * 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
- * names. This means if we order by key, we won't actually have them sorted
- * correctly. This list contains the libraries in correct order by their
- * *name*.
- */
- List<Library> _sortedLibraries;
-
- CommentMap _comments;
-
- /** The library that we're currently generating docs for. */
- Library _currentLibrary;
-
- /** The type that we're currently generating docs for. */
- Type _currentType;
-
- /** The member that we're currently generating docs for. */
- Member _currentMember;
-
- /** The path to the file currently being written to, relative to [outdir]. */
- String _filePath;
-
- /** The file currently being written to. */
- StringBuffer _file;
-
- int _totalLibraries = 0;
- int _totalTypes = 0;
- int _totalMembers = 0;
-
- Dartdoc()
- : _comments = new CommentMap() {
- // Patch in support for [:...:]-style code to the markdown parser.
- // TODO(rnystrom): Markdown already has syntax for this. Phase this out?
- md.InlineParser.syntaxes.insertRange(0, 1,
- new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]'));
-
- md.setImplicitLinkResolver((name) => resolveNameReference(name,
- library: _currentLibrary, type: _currentType,
- member: _currentMember));
- }
-
- void document(String entrypoint) {
- var oldDietParse = options.dietParse;
- try {
- options.dietParse = true;
-
- // Handle the built-in entrypoints.
- switch (entrypoint) {
- case 'corelib':
- world.getOrAddLibrary('dart:core');
- world.getOrAddLibrary('dart:coreimpl');
- world.getOrAddLibrary('dart:json');
- world.getOrAddLibrary('dart:isolate');
- world.process();
- break;
-
- case 'dom':
- world.getOrAddLibrary('dart:core');
- world.getOrAddLibrary('dart:coreimpl');
- world.getOrAddLibrary('dart:json');
- world.getOrAddLibrary('dart:dom');
- world.getOrAddLibrary('dart:isolate');
- world.process();
- break;
-
- case 'html':
- world.getOrAddLibrary('dart:core');
- world.getOrAddLibrary('dart:coreimpl');
- world.getOrAddLibrary('dart:json');
- world.getOrAddLibrary('dart:dom');
- world.getOrAddLibrary('dart:html');
- world.getOrAddLibrary('dart:isolate');
- world.process();
- break;
-
- default:
- // Normal entrypoint script.
- world.processDartScript(entrypoint);
- }
-
- world.resolveAll();
-
- // Sort the libraries by name (not key).
- _sortedLibraries = world.libraries.getValues();
- _sortedLibraries.sort((a, b) {
- return a.name.toUpperCase().compareTo(b.name.toUpperCase());
- });
-
- // Generate the docs.
- if (mode == MODE_LIVE_NAV) docNavigationJson();
-
- docIndex();
- for (final library in _sortedLibraries) {
- docLibrary(library);
- }
- } finally {
- options.dietParse = oldDietParse;
- }
- }
-
- void startFile(String path) {
- _filePath = path;
- _file = new StringBuffer();
- }
-
- void endFile() {
- final outPath = '$_outdir/$_filePath';
- final dir = new Directory(dirname(outPath));
- if (!dir.existsSync()) {
- dir.createSync();
- }
-
- world.files.writeString(outPath, _file.toString());
- _filePath = null;
- _file = null;
- }
-
- void write(String s) {
- _file.add(s);
- }
-
- void writeln(String s) {
- write(s);
- write('\n');
- }
-
- /**
- * Writes the page header with the given [title] and [breadcrumbs]. The
- * breadcrumbs are an interleaved list of links and titles. If a link is null,
- * then no link will be generated. For example, given:
- *
- * ['foo', 'foo.html', 'bar', null]
- *
- * It will output:
- *
- * <a href="foo.html">foo</a> &rsaquo; bar
- */
- void writeHeader(String title, List<String> breadcrumbs) {
- write(
- '''
- <!DOCTYPE html>
- <html>
- <head>
- ''');
- writeHeadContents(title);
-
- // Add data attributes describing what the page documents.
- var data = '';
- if (_currentLibrary != null) {
- data += ' data-library="${md.escapeHtml(_currentLibrary.name)}"';
- }
-
- if (_currentType != null) {
- data += ' data-type="${md.escapeHtml(typeName(_currentType))}"';
- }
-
- write(
- '''
- </head>
- <body$data>
- <div class="page">
- <div class="header">
- ${a(mainUrl, '<div class="logo"></div>')}
- ${a('index.html', mainTitle)}
- ''');
-
- // Write the breadcrumb trail.
- for (int i = 0; i < breadcrumbs.length; i += 2) {
- if (breadcrumbs[i + 1] == null) {
- write(' &rsaquo; ${breadcrumbs[i]}');
- } else {
- write(' &rsaquo; ${a(breadcrumbs[i + 1], breadcrumbs[i])}');
- }
- }
-
- if (searchEngineId != null) {
- writeln(
- '''
- <form action="$searchResultsUrl" id="search-box">
- <input type="hidden" name="cx" value="$searchEngineId">
- <input type="hidden" name="ie" value="UTF-8">
- <input type="hidden" name="hl" value="en">
- <input type="search" name="q" id="q" autocomplete="off"
- placeholder="Search">
- </form>
- ''');
- }
-
- writeln('</div>');
-
- docNavigation();
- writeln('<div class="content">');
- }
-
- String get clientScript() {
- switch (mode) {
- case MODE_STATIC: return 'client-static';
- case MODE_LIVE_NAV: return 'client-live-nav';
- default: throw 'Unknown mode $mode.';
- }
- }
-
- void writeHeadContents(String title) {
- writeln(
- '''
- <meta charset="utf-8">
- <title>$title</title>
- <link rel="stylesheet" type="text/css"
- href="${relativePath('styles.css')}" />
- <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700,800" rel="stylesheet" type="text/css">
- <link rel="shortcut icon" href="${relativePath('favicon.ico')}" />
- <script src="${relativePath('$clientScript.js')}"></script>
- ''');
- }
-
- void writeFooter() {
- writeln(
- '''
- </div>
- <div class="clear"></div>
- </div>
- <div class="footer">$footerText</div>
- </body></html>
- ''');
- }
-
- void docIndex() {
- startFile('index.html');
-
- writeHeader(mainTitle, []);
-
- writeln('<h2>$mainTitle</h2>');
- writeln('<h3>Libraries</h3>');
-
- for (final library in _sortedLibraries) {
- docIndexLibrary(library);
- }
-
- writeFooter();
- endFile();
- }
-
- void docIndexLibrary(Library library) {
- writeln('<h4>${a(libraryUrl(library), library.name)}</h4>');
- }
-
- /**
- * Walks the libraries and creates a JSON object containing the data needed
- * to generate navigation for them.
- */
- void docNavigationJson() {
- startFile('nav.json');
-
- final libraries = {};
-
- for (final library in _sortedLibraries) {
- docLibraryNavigationJson(library, libraries);
- }
-
- writeln(JSON.stringify(libraries));
- endFile();
- }
-
- void docLibraryNavigationJson(Library library, Map libraries) {
- final types = [];
-
- for (final type in orderByName(library.types)) {
- if (type.isTop) continue;
- if (type.name.startsWith('_')) continue;
-
- final kind = type.isClass ? 'class' : 'interface';
- final url = typeUrl(type);
- types.add({ 'name': typeName(type), 'kind': kind, 'url': url });
- }
-
- libraries[library.name] = types;
- }
-
- void docNavigation() {
- writeln(
- '''
- <div class="nav">
- ''');
-
- if (mode == MODE_STATIC) {
- for (final library in _sortedLibraries) {
- write('<h2><div class="icon-library"></div>');
-
- if ((_currentLibrary == library) && (_currentType == null)) {
- write('<strong>${library.name}</strong>');
- } else {
- write('${a(libraryUrl(library), library.name)}');
- }
- write('</h2>');
-
- // Only expand classes in navigation for current library.
- if (_currentLibrary == library) docLibraryNavigation(library);
- }
- }
-
- writeln('</div>');
- }
-
- /** Writes the navigation for the types contained by the given library. */
- void docLibraryNavigation(Library library) {
- // Show the exception types separately.
- final types = <Type>[];
- final exceptions = <Type>[];
-
- for (final type in orderByName(library.types)) {
- if (type.isTop) continue;
- if (type.name.startsWith('_')) continue;
-
- if (type.name.endsWith('Exception')) {
- exceptions.add(type);
- } else {
- types.add(type);
- }
- }
-
- if ((types.length == 0) && (exceptions.length == 0)) return;
-
- writeln('<ul class="icon">');
- types.forEach(docTypeNavigation);
- exceptions.forEach(docTypeNavigation);
- writeln('</ul>');
- }
-
- /** Writes a linked navigation list item for the given type. */
- void docTypeNavigation(Type type) {
- var icon = 'interface';
- if (type.name.endsWith('Exception')) {
- icon = 'exception';
- } else if (type.isClass) {
- icon = 'class';
- }
-
- write('<li>');
- if (_currentType == type) {
- write(
- '<div class="icon-$icon"></div><strong>${typeName(type)}</strong>');
- } else {
- write(a(typeUrl(type),
- '<div class="icon-$icon"></div>${typeName(type)}'));
- }
- writeln('</li>');
- }
-
- void docLibrary(Library library) {
- _totalLibraries++;
- _currentLibrary = library;
- _currentType = null;
-
- startFile(libraryUrl(library));
- writeHeader(library.name, [library.name, libraryUrl(library)]);
- writeln('<h2>Library <strong>${library.name}</strong></h2>');
-
- // Look for a comment for the entire library.
- final comment = _comments.findLibrary(library.baseSource);
- if (comment != null) {
- final html = md.markdownToHtml(comment);
- writeln('<div class="doc">$html</div>');
- }
-
- // Document the top-level members.
- docMembers(library.topType);
-
- // Document the types.
- final classes = <Type>[];
- final interfaces = <Type>[];
- final exceptions = <Type>[];
-
- for (final type in orderByName(library.types)) {
- if (type.isTop) continue;
- if (type.name.startsWith('_')) continue;
-
- if (type.name.endsWith('Exception')) {
- exceptions.add(type);
- } else if (type.isClass) {
- classes.add(type);
- } else {
- interfaces.add(type);
- }
- }
-
- docTypes(classes, 'Classes');
- docTypes(interfaces, 'Interfaces');
- docTypes(exceptions, 'Exceptions');
-
- writeFooter();
- endFile();
-
- for (final type in library.types.getValues()) {
- if (!type.isTop) docType(type);
- }
- }
-
- void docTypes(List<Type> types, String header) {
- if (types.length == 0) return;
-
- writeln('<h3>$header</h3>');
-
- for (final type in types) {
- writeln(
- '''
- <div class="type">
- <h4>
- ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")}
- </h4>
- </div>
- ''');
- }
- }
-
- void docType(Type type) {
- _totalTypes++;
- _currentType = type;
-
- startFile(typeUrl(type));
-
- final typeTitle =
- '${type.isClass ? "Class" : "Interface"} ${typeName(type)}';
- writeHeader('Library ${type.library.name} / $typeTitle',
- [type.library.name, libraryUrl(type.library),
- typeName(type), typeUrl(type)]);
- writeln(
- '''
- <h2>${type.isClass ? "Class" : "Interface"}
- <strong>${typeName(type, showBounds: true)}</strong></h2>
- ''');
-
- docCode(type.span, getTypeComment(type));
- docInheritance(type);
- docConstructors(type);
- docMembers(type);
-
- writeTypeFooter();
- writeFooter();
- endFile();
- }
-
- /** Override this to write additional content at the end of a type's page. */
- void writeTypeFooter() {
- // Do nothing.
- }
-
- /**
- * Writes an inline type span for the given type. This is a little box with
- * 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) {
- var icon = 'interface';
- if (type.name.endsWith('Exception')) {
- icon = 'exception';
- } else if (type.isClass) {
- icon = 'class';
- }
-
- write('<span class="type-box"><span class="icon-$icon"></span>');
- if (_currentType == type) {
- write('<strong>${typeName(type)}</strong>');
- } else {
- write(a(typeUrl(type), typeName(type)));
- }
- write('</span>');
- }
-
- /**
- * Document the other types that touch [Type] in the inheritance hierarchy:
- * subclasses, superclasses, subinterfaces, superinferfaces, and default
- * class.
- */
- void docInheritance(Type 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;
-
- // Writes an unordered list of references to types with an optional header.
- listTypes(types, header) {
- if (types == null) return;
-
- // Skip private types.
- final publicTypes = types.filter((type) => !type.name.startsWith('_'));
- if (publicTypes.length == 0) return;
-
- writeln('<h3>$header</h3>');
- writeln('<p>');
- bool first = true;
- for (final type in publicTypes) {
- if (!first) write(', ');
- typeSpan(type);
- first = false;
- }
- writeln('</p>');
- }
-
- if (type.isClass) {
- // Show the chain of superclasses.
- if (!type.parent.isObject) {
- final supertypes = [];
- var thisType = type.parent;
- // 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;
- } while (!thisType.isObject);
-
- writeln('<h3>Extends</h3>');
- writeln('<p>');
- for (var i = supertypes.length - 1; i >= 0; i--) {
- typeSpan(supertypes[i]);
- write('&nbsp;&gt;&nbsp;');
- }
-
- // Write this class.
- typeSpan(type);
- 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');
- } else {
- // Show the default class.
- if (type.genericType.defaultType != null) {
- listTypes([type.genericType.defaultType], 'Default class');
- }
-
- // List extended interfaces.
- listTypes(type.interfaces, '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;
- }
- }
- }
-
- listTypes(subinterfaces, 'Subinterfaces');
- listTypes(implementing, 'Implemented by');
- }
- }
-
- /** Document the constructors for [Type], if any. */
- void docConstructors(Type type) {
- final names = type.constructors.getKeys().filter(
- (name) => !name.startsWith('_'));
-
- if (names.length > 0) {
- writeln('<h3>Constructors</h3>');
- names.sort((x, y) => x.toUpperCase().compareTo(y.toUpperCase()));
-
- for (final name in names) {
- docMethod(type, type.constructors[name], constructorName: name);
- }
- }
- }
-
- void docMembers(Type type) {
- // 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;
-
- 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) {
- methods.add(member);
- } else if (member.isField) {
- fields.add(member);
- }
- }
-
- if (staticMethods.length > 0) {
- final title = type.isTop ? 'Functions' : 'Static Methods';
- writeln('<h3>$title</h3>');
- for (final method in staticMethods) docMethod(type, method);
- }
-
- if (staticFields.length > 0) {
- final title = type.isTop ? 'Variables' : 'Static Fields';
- writeln('<h3>$title</h3>');
- for (final field in staticFields) docField(type, field);
- }
-
- if (instanceMethods.length > 0) {
- writeln('<h3>Methods</h3>');
- for (final method in instanceMethods) docMethod(type, method);
- }
-
- if (instanceFields.length > 0) {
- writeln('<h3>Fields</h3>');
- for (final field in instanceFields) docField(type, field);
- }
- }
-
- /**
- * 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]) {
- _totalMembers++;
- _currentMember = method;
-
- writeln('<div class="method"><h4 id="${memberAnchor(method)}">');
-
- if (includeSource) {
- writeln('<span class="show-code">Code</span>');
- }
-
- if (method.isConstructor) {
- write(method.isConst ? 'const ' : 'new ');
- }
-
- if (constructorName == null) {
- annotateType(type, method.returnType);
- }
-
- // Translate specially-named methods: getters, setters, operators.
- var name = method.name;
- if (name.startsWith('get:')) {
- // Getter.
- name = 'get ${name.substring(4)}';
- } else if (name.startsWith('set:')) {
- // 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';
- }
- }
-
- write('<strong>$name</strong>');
-
- // Named constructors.
- if (constructorName != null && constructorName != '') {
- write('.');
- write(constructorName);
- }
-
- docParamList(type, method);
-
- write(''' <a class="anchor-link" href="#${memberAnchor(method)}"
- title="Permalink to ${typeName(type)}.$name">#</a>''');
- writeln('</h4>');
-
- docCode(method.span, getMethodComment(method), showCode: true);
-
- writeln('</div>');
- }
-
- /** Documents the field [field] of type [type]. */
- void docField(Type type, FieldMember field) {
- _totalMembers++;
- _currentMember = field;
-
- writeln('<div class="field"><h4 id="${memberAnchor(field)}">');
-
- if (includeSource) {
- writeln('<span class="show-code">Code</span>');
- }
-
- if (field.isFinal) {
- write('final ');
- } else if (field.type.name == 'Dynamic') {
- write('var ');
- }
-
- annotateType(type, field.type);
- write(
- '''
- <strong>${field.name}</strong> <a class="anchor-link"
- href="#${memberAnchor(field)}"
- title="Permalink to ${typeName(type)}.${field.name}">#</a>
- </h4>
- ''');
-
- docCode(field.span, getFieldComment(field), showCode: true);
- writeln('</div>');
- }
-
- void docParamList(Type enclosingType, MethodMember member) {
- write('(');
- bool first = true;
- bool inOptionals = false;
- for (final parameter in member.parameters) {
- if (!first) write(', ');
-
- if (!inOptionals && parameter.isOptional) {
- write('[');
- inOptionals = true;
- }
-
- annotateType(enclosingType, parameter.type, parameter.name);
-
- // Show the default value for named optional parameters.
- 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:
- // foo([arg = 1 + /* comment */ 2])
- // 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);
- }
-
- first = false;
- }
-
- if (inOptionals) write(']');
- write(')');
- }
-
- /**
- * 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]) {
- writeln('<div class="doc">');
- if (comment != null) {
- writeln(comment);
- }
-
- if (includeSource && showCode) {
- writeln('<pre class="source">');
- writeln(md.escapeHtml(unindentCode(span)));
- writeln('</pre>');
- }
-
- writeln('</div>');
- }
-
- /** Get the doc comment associated with the given type. */
- String getTypeComment(Type type) {
- String comment = _comments.find(type.span);
- if (comment == null) return null;
- return md.markdownToHtml(comment);
- }
-
- /** Get the doc comment associated with the given method. */
- String getMethodComment(MethodMember method) {
- String comment = _comments.find(method.span);
- if (comment == null) return null;
- return md.markdownToHtml(comment);
- }
-
- /** Get the doc comment associated with the given field. */
- String getFieldComment(FieldMember field) {
- String comment = _comments.find(field.span);
- if (comment == null) return null;
- return md.markdownToHtml(comment);
- }
-
- /**
- * Converts [fullPath] which is understood to be a full path from the root of
- * the generated docs to one relative to the current file.
- */
- String relativePath(String fullPath) {
- // Don't make it relative if it's an absolute path.
- if (isAbsolute(fullPath)) return fullPath;
-
- // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do
- // this if the paths overlap.
- return repeat('../', countOccurrences(_filePath, '/')) + fullPath;
- }
-
- /** Gets whether or not the given URL is absolute or relative. */
- bool isAbsolute(String url) {
- // TODO(rnystrom): Why don't we have a nice type in the platform for this?
- // TODO(rnystrom): This is a bit hackish. We consider any URL that lacks
- // a scheme to be relative.
- return const RegExp(@'^\w+:').hasMatch(url);
- }
-
- /** Gets the URL to the documentation for [library]. */
- String libraryUrl(Library library) {
- return '${sanitize(library.name)}.html';
- }
-
- /** Gets the URL for the documentation for [type]. */
- String typeUrl(Type type) {
- if (type.isTop) return '${sanitize(type.library.name)}.html';
- // 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';
- }
-
- /** 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}';
- }
-
- /** Gets the anchor id for the document for [member]. */
- String memberAnchor(Member member) {
- return '${member.name}';
- }
-
- /**
- * Creates a hyperlink. Handles turning the [href] into an appropriate
- * relative path from the current file.
- */
- String a(String href, String contents, [String css]) {
- // Mark outgoing external links, mainly so we can style them.
- final rel = isAbsolute(href) ? ' ref="external"' : '';
- final cssClass = css == null ? '' : ' class="$css"';
- return '<a href="${relativePath(href)}"$cssClass$rel>$contents</a>';
- }
-
- /**
- * Writes a type annotation for the given type and (optional) parameter name.
- */
- annotateType(Type enclosingType, Type type, [String paramName = null]) {
- // Don't bother explicitly displaying Dynamic.
- if (type.isVar) {
- 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);
-
- docParamList(enclosingType, call);
- return;
- }
- }
-
- linkToType(enclosingType, type);
-
- write(' ');
- if (paramName !== null) write(paramName);
- }
-
- /** Writes a link to a human-friendly string representation for a type. */
- linkToType(Type enclosingType, Type type) {
- if (type is ParameterType) {
- // 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));
- return;
- }
-
- // Link to the type.
- // Use .genericType to avoid writing the <...> here.
- write(a(typeUrl(type), type.genericType.name));
-
- // 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.
- return;
- }
-
- // See if it's an instantiation of a generic type.
- final typeArgs = type.typeArgsInOrder;
- if (typeArgs.length > 0) {
- write('&lt;');
- bool first = true;
- for (final arg in typeArgs) {
- if (!first) write(', ');
- first = false;
- linkToType(enclosingType, arg);
- }
- write('&gt;');
- }
- }
-
- /** Creates a linked cross reference to [type]. */
- typeReference(Type 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]) {
- // See if it's a generic type.
- if (type.isGeneric) {
- final typeParams = [];
- for (final typeParam in type.genericType.typeParameters) {
- if (showBounds &&
- (typeParam.extendsType != null) &&
- !typeParam.extendsType.isObject) {
- final bound = typeName(typeParam.extendsType, showBounds: true);
- typeParams.add('${typeParam.name} extends $bound');
- } else {
- typeParams.add(typeParam.name);
- }
- }
-
- final params = Strings.join(typeParams, ', ');
- return '${type.name}&lt;$params&gt;';
- }
-
- // See if it's an instantiation of a generic type.
- final typeArgs = type.typeArgsInOrder;
- if (typeArgs.length > 0) {
- final args = Strings.join(map(typeArgs, (arg) => typeName(arg)), ', ');
- return '${type.genericType.name}&lt;$args&gt;';
- }
-
- // Regular type.
- return type.name;
- }
-
- /**
- * Remove leading indentation to line up with first line.
- */
- unindentCode(SourceSpan span) {
- final column = getSpanColumn(span);
- final lines = span.text.split('\n');
- // TODO(rnystrom): Dirty hack.
- for (var i = 1; i < lines.length; i++) {
- lines[i] = unindent(lines[i], column);
- }
-
- final code = Strings.join(lines, '\n');
- return code;
- }
-
- /**
- * Takes a string of Dart code and turns it into sanitized HTML.
- */
- formatCode(SourceSpan span) {
- final code = unindentCode(span);
-
- // Syntax highlight.
- return classifySource(new SourceFile('', code));
- }
-
- /**
- * This will be called whenever a doc comment hits a `[name]` in square
- * 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]) {
- makeLink(String href) {
- final anchor = new md.Element.text('a', name);
- anchor.attributes['href'] = relativePath(href);
- anchor.attributes['class'] = 'crossref';
- 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) {
- final element = new md.Element.text('span', name);
- element.attributes['class'] = 'param';
- return element;
- }
- }
- }
-
- // See if it's another member of the current type.
- if (type != null) {
- final member = findMember(type, name);
- if (member != null) {
- return makeLink(memberUrl(member));
- }
- }
-
- // See if it's another type or a member of another type in the current
- // library.
- if (library != null) {
- // See if it's a constructor
- final constructorLink = (() {
- final match = new RegExp(@'new (\w+)(?:\.(\w+))?').firstMatch(name);
- if (match == null) return;
- final type = library.types[match[1]];
- if (type == null) return;
- final constructor = type.getConstructor(
- match[2] == null ? '' : match[2]);
- if (constructor == null) return;
- return makeLink(memberUrl(constructor));
- })();
- if (constructorLink != null) return constructorLink;
-
- // See if it's a member of another type
- final foreignMemberLink = (() {
- final match = new RegExp(@'(\w+)\.(\w+)').firstMatch(name);
- if (match == null) return;
- final type = library.types[match[1]];
- if (type == null) return;
- final member = findMember(type, match[2]);
- if (member == null) return;
- return makeLink(memberUrl(member));
- })();
- if (foreignMemberLink != null) return foreignMemberLink;
-
- final type = 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);
- if (member != null) {
- return makeLink(memberUrl(member));
- }
- }
-
- // TODO(rnystrom): Should also consider:
- // * Names imported by libraries this library imports.
- // * Type parameters of the enclosing type.
-
- 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);
- }
-}
« frog/presubmit.py ('K') | « utils/dartdoc/dartdoc ('k') | utils/dartdoc/html_renderer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698