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

Unified Diff: utils/dartdoc/dartdoc.dart

Issue 8947005: Refactor dartdoc into a class. Use method overriding to extend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Respond to review. Created 9 years 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
« no previous file with comments | « utils/dartdoc/comment_map.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: utils/dartdoc/dartdoc.dart
diff --git a/utils/dartdoc/dartdoc.dart b/utils/dartdoc/dartdoc.dart
index a77fb1ae3898baa7474a53c521dbb1afb548b8f5..91a97ef092542eded879c65932fe4e03316d0d90 100644
--- a/utils/dartdoc/dartdoc.dart
+++ b/utils/dartdoc/dartdoc.dart
@@ -21,6 +21,7 @@
#import('../markdown/lib.dart', prefix: 'md');
#source('classify.dart');
+#source('comment_map.dart');
#source('files.dart');
#source('utils.dart');
@@ -30,63 +31,19 @@ final corePath = 'lib';
/** Path to generate html files into. */
final outdir = 'docs';
-/** Set to `false` to not include the source code in the generated docs. */
-bool includeSource = true;
-
FileSystem files;
-/** Special comment position used to store the library-level doc comment. */
-final _libraryDoc = -1;
-
-/** 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 cached lookup-table to associate doc comments with spans. The outer map
- * is from filenames to doc comments in that file. The inner map maps from the
- * token positions to doc comments. Each position is the starting offset of the
- * next non-comment token *following* the doc comment. For example, the position
- * for this comment would be the position of the "Map" token below.
- */
-Map<String, Map<int, String>> _comments;
-
-/** A callback that returns additional Markdown documentation for a type. */
-typedef String TypeDocumenter(Type type);
-
-/** A list of callbacks registered for documenting types. */
-List<TypeDocumenter> _typeDocumenters;
-
-/** A callback that returns additional Markdown documentation for a method. */
-typedef String MethodDocumenter(MethodMember method);
-
-/** A list of callbacks registered for documenting methods. */
-List<MethodDocumenter> _methodDocumenters;
-
-/** A callback that returns additional Markdown documentation for a field. */
-typedef String FieldDocumenter(FieldMember field);
-
-/** A list of callbacks registered for documenting fields. */
-List<FieldDocumenter> _fieldDocumenters;
-
-int _totalLibraries = 0;
-int _totalTypes = 0;
-int _totalMembers = 0;
-
/**
* Run this from the `utils/dartdoc` directory.
*/
void main() {
// The entrypoint of the library to generate docs for.
- final entrypoint = process.argv[2];
+ final entrypoint = process.argv[process.argv.length - 1];
// Parse the dartdoc options.
- for (int i = 3; i < process.argv.length; i++) {
+ bool includeSource = true;
+
+ for (int i = 2; i < process.argv.length - 1; i++) {
final arg = process.argv[i];
switch (arg) {
case '--no-code':
@@ -102,811 +59,732 @@ void main() {
parseOptions('../../frog', [] /* args */, files);
initializeWorld(files);
+ var dartdoc;
final elapsed = time(() {
- initializeDartDoc();
- document(entrypoint);
+ dartdoc = new Dartdoc();
+ dartdoc.includeSource = includeSource;
+ dartdoc.document(entrypoint);
});
- printStats(elapsed);
-}
-
-void initializeDartDoc() {
- _comments = <Map<int, String>>{};
- _typeDocumenters = <TypeDocumenter>[];
- _methodDocumenters = <MethodDocumenter>[];
- _fieldDocumenters = <FieldDocumenter>[];
-
- // 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(resolveNameReference);
+ print('Documented ${dartdoc._totalLibraries} libraries, ' +
+ '${dartdoc._totalTypes} types, and ' +
+ '${dartdoc._totalMembers} members in ${elapsed}msec.');
}
-document(String entrypoint) {
- try {
- var oldDietParse = options.dietParse;
- 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.process();
- break;
-
- case 'dom':
- world.getOrAddLibrary('dart:core');
- world.getOrAddLibrary('dart:coreimpl');
- world.getOrAddLibrary('dart:json');
- world.getOrAddLibrary('dart:dom');
- world.process();
- break;
+class Dartdoc {
+ /** Set to `false` to not include the source code in the generated docs. */
+ bool includeSource = true;
+
+ 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;
+
+ 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(resolveNameReference);
+ }
+
+ document(String entrypoint) {
+ try {
+ var oldDietParse = options.dietParse;
+ 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.process();
+ break;
+
+ case 'dom':
+ world.getOrAddLibrary('dart:core');
+ world.getOrAddLibrary('dart:coreimpl');
+ world.getOrAddLibrary('dart:json');
+ world.getOrAddLibrary('dart:dom');
+ 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.process();
+ break;
+
+ default:
+ // Normal entrypoint script.
+ world.processDartScript(entrypoint);
+ }
- case 'html':
- world.getOrAddLibrary('dart:core');
- world.getOrAddLibrary('dart:coreimpl');
- world.getOrAddLibrary('dart:json');
- world.getOrAddLibrary('dart:dom');
- world.getOrAddLibrary('dart:html');
- world.process();
- break;
+ world.resolveAll();
- default:
- // Normal entrypoint script.
- world.processDartScript(entrypoint);
+ // Generate the docs.
+ docIndex();
+ for (final library in world.libraries.getValues()) {
+ docLibrary(library);
+ }
+ } finally {
+ options.dietParse = oldDietParse;
}
+ }
- world.resolveAll();
-
- // Generate the docs.
- docIndex();
- for (final library in world.libraries.getValues()) {
- docLibrary(library);
- }
- } finally {
- options.dietParse = oldDietParse;
+ writeHeader(String title) {
+ writeln(
+ '''
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <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">
+ <script src="${relativePath('interact.js')}"></script>
+ </head>
+ <body>
+ <div class="page">
+ ''');
+ docNavigation();
+ writeln('<div class="content">');
}
-}
-printStats(num elapsed) {
- print('Documented $_totalLibraries libraries, $_totalTypes types, and ' +
- '$_totalMembers members in ${elapsed}msec.');
-}
+ writeFooter() {
+ writeln(
+ '''
+ </div>
+ <div class="footer"</div>
+ </body></html>
+ ''');
+ }
-writeHeader(String title) {
- writeln(
- '''
- <!DOCTYPE html>
- <html>
- <head>
- <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">
- <script src="${relativePath('interact.js')}"></script>
- </head>
- <body>
- <div class="page">
- ''');
- docNavigation();
- writeln('<div class="content">');
-}
+ docIndex() {
+ startFile('index.html');
-writeFooter() {
- writeln(
- '''
- </div>
- <div class="footer"</div>
- </body></html>
- ''');
-}
+ writeHeader('Dart Documentation');
-docIndex() {
- startFile('index.html');
+ writeln('<h1>Dart Documentation</h1>');
+ writeln('<h3>Libraries</h3>');
- writeHeader('Dart Documentation');
+ for (final library in orderByName(world.libraries)) {
+ writeln(
+ '''
+ <h4>${a(libraryUrl(library), library.name)}</h4>
+ ''');
+ }
- writeln('<h1>Dart Documentation</h1>');
- writeln('<h3>Libraries</h3>');
+ writeFooter();
+ endFile();
+ }
- for (final library in orderByName(world.libraries)) {
+ docNavigation() {
writeln(
'''
- <h4>${a(libraryUrl(library), library.name)}</h4>
+ <div class="nav">
+ <h1>${a("index.html", "Dart Documentation")}</h1>
''');
- }
- writeFooter();
- endFile();
-}
-
-docNavigation() {
- writeln(
- '''
- <div class="nav">
- <h1>${a("index.html", "Dart Documentation")}</h1>
- ''');
+ for (final library in orderByName(world.libraries)) {
+ write('<h2><div class="icon-library"></div>');
- for (final library in orderByName(world.libraries)) {
- 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>');
- if ((_currentLibrary == library) && (_currentType == null)) {
- write('<strong>${library.name}</strong>');
- } else {
- write('${a(libraryUrl(library), library.name)}');
+ // Only expand classes in navigation for current library.
+ if (_currentLibrary == library) docLibraryNavigation(library);
}
- write('</h2>');
- // Only expand classes in navigation for current library.
- if (_currentLibrary == library) docLibraryNavigation(library);
+ writeln('</div>');
}
- writeln('</div>');
-}
-
-/** Writes the navigation for the types contained by the given library. */
-docLibraryNavigation(Library library) {
- // Show the exception types separately.
- final types = <Type>[];
- final exceptions = <Type>[];
+ /** Writes the navigation for the types contained by the given library. */
+ 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;
+ 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 (type.name.endsWith('Exception')) {
+ exceptions.add(type);
+ } else {
+ types.add(type);
+ }
}
- }
- if ((types.length == 0) && (exceptions.length == 0)) return;
+ if ((types.length == 0) && (exceptions.length == 0)) return;
- writeType(String icon, Type type) {
- 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)}'));
+ writeType(String icon, Type type) {
+ 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>');
}
- writeln('</li>');
+
+ writeln('<ul>');
+ types.forEach((type) => writeType(type.isClass ? 'class' : 'interface',
+ type));
+ exceptions.forEach((type) => writeType('exception', type));
+ writeln('</ul>');
}
- writeln('<ul>');
- types.forEach((type) => writeType(type.isClass ? 'class' : 'interface',
- type));
- exceptions.forEach((type) => writeType('exception', type));
- writeln('</ul>');
-}
+ docLibrary(Library library) {
+ _totalLibraries++;
+ _currentLibrary = library;
+ _currentType = null;
-String _runDocumenters(var item, List<Function> documenters) =>
- Strings.join(map(documenters, (doc) => doc(item)), '\n\n');
+ startFile(libraryUrl(library));
+ writeHeader(library.name);
+ writeln('<h1>Library <strong>${library.name}</strong></h1>');
-docLibrary(Library library) {
- _totalLibraries++;
- _currentLibrary = library;
- _currentType = null;
+ // 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>');
+ }
- startFile(libraryUrl(library));
- writeHeader(library.name);
- writeln('<h1>Library <strong>${library.name}</strong></h1>');
+ // Document the top-level members.
+ docMembers(library.topType);
- // Look for a comment for the entire library.
- final comment = findCommentInFile(library.baseSource, _libraryDoc);
- if (comment != null) {
- final html = md.markdownToHtml(comment);
- writeln('<div class="doc">$html</div>');
- }
+ // 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;
- // Document the top-level members.
- docMembers(library.topType);
+ if (type.name.endsWith('Exception')) {
+ exceptions.add(type);
+ } else if (type.isClass) {
+ classes.add(type);
+ } else {
+ interfaces.add(type);
+ }
+ }
- // Document the types.
- final classes = <Type>[];
- final interfaces = <Type>[];
- final exceptions = <Type>[];
+ docTypes(classes, 'Classes');
+ docTypes(interfaces, 'Interfaces');
+ docTypes(exceptions, 'Exceptions');
- for (final type in orderByName(library.types)) {
- if (type.isTop) continue;
- if (type.name.startsWith('_')) continue;
+ writeFooter();
+ endFile();
- if (type.name.endsWith('Exception')) {
- exceptions.add(type);
- } else if (type.isClass) {
- classes.add(type);
- } else {
- interfaces.add(type);
+ for (final type in library.types.getValues()) {
+ if (!type.isTop) docType(type);
}
}
- docTypes(classes, 'Classes');
- docTypes(interfaces, 'Interfaces');
- docTypes(exceptions, 'Exceptions');
+ docTypes(List<Type> types, String header) {
+ if (types.length == 0) return;
- writeFooter();
- endFile();
+ writeln('<h3>$header</h3>');
- for (final type in library.types.getValues()) {
- if (!type.isTop) docType(type);
+ for (final type in types) {
+ writeln(
+ '''
+ <div class="type">
+ <h4>
+ ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")}
+ </h4>
+ </div>
+ ''');
+ }
}
-}
-docTypes(List<Type> types, String header) {
- if (types.length == 0) return;
+ docType(Type type) {
+ _totalTypes++;
+ _currentType = type;
- writeln('<h3>$header</h3>');
+ startFile(typeUrl(type));
- for (final type in types) {
+ final typeTitle =
+ '${type.isClass ? "Class" : "Interface"} ${typeName(type)}';
+ writeHeader('Library ${type.library.name} / $typeTitle');
writeln(
'''
- <div class="type">
- <h4>
- ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")}
- </h4>
- </div>
+ <h1>${a(libraryUrl(type.library),
+ "Library <strong>${type.library.name}</strong>")}</h1>
+ <h2>${type.isClass ? "Class" : "Interface"}
+ <strong>${typeName(type, showBounds: true)}</strong></h2>
''');
- }
-}
-docType(Type type) {
- _totalTypes++;
- _currentType = type;
-
- startFile(typeUrl(type));
-
- final typeTitle = '${type.isClass ? "Class" : "Interface"} ${typeName(type)}';
- writeHeader('Library ${type.library.name} / $typeTitle');
- writeln(
- '''
- <h1>${a(libraryUrl(type.library),
- "Library <strong>${type.library.name}</strong>")}</h1>
- <h2>${type.isClass ? "Class" : "Interface"}
- <strong>${typeName(type, showBounds: true)}</strong></h2>
- ''');
-
- docInheritance(type);
- docCode(type.span, _runDocumenters(type, _typeDocumenters));
- docConstructors(type);
- docMembers(type);
-
- writeFooter();
- endFile();
-}
-
-void docMembers(Type type) {
- // Collect the different kinds of members.
- final methods = [];
- final fields = [];
+ docInheritance(type);
- for (final member in orderByName(type.members)) {
- if (member.name.startsWith('_')) continue;
+ docCode(type.span, getTypeComment(type));
+ docConstructors(type);
+ docMembers(type);
- 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);
- }
+ writeFooter();
+ endFile();
}
- if (methods.length > 0) {
- writeln('<h3>Methods</h3>');
- for (final method in methods) docMethod(type, method);
- }
-
- if (fields.length > 0) {
- writeln('<h3>Fields</h3>');
- for (final field in fields) docField(type, field);
- }
-}
+ /** Document the superclass, superinterfaces and default class of [Type]. */
+ docInheritance(Type type) {
+ final isSubclass = (type.parent != null) && !type.parent.isObject;
-/** Document the superclass, superinterfaces and factory of [Type]. */
-docInheritance(Type type) {
- final isSubclass = (type.parent != null) && !type.parent.isObject;
-
- Type factory;
- if (type.definition is TypeDefinition) {
- TypeDefinition definition = type.definition;
- if (definition.factoryType != null) {
- factory = definition.factoryType.type;
+ Type defaultType;
+ if (type.definition is TypeDefinition) {
+ TypeDefinition definition = type.definition;
+ if (definition.defaultType != null) {
+ defaultType = definition.defaultType.type;
+ }
}
- }
- if (isSubclass ||
- (type.interfaces != null && type.interfaces.length > 0) ||
- (factory != null)) {
- writeln('<p>');
+ if (isSubclass ||
+ (type.interfaces != null && type.interfaces.length > 0) ||
+ (defaultType != null)) {
+ writeln('<p>');
- if (isSubclass) {
- write('Extends ${typeReference(type.parent)}. ');
- }
+ if (isSubclass) {
+ write('Extends ${typeReference(type.parent)}. ');
+ }
- if (type.interfaces != null && type.interfaces.length > 0) {
- var interfaceStr = joinWithCommas(map(type.interfaces, typeReference));
- write('Implements ${interfaceStr}. ');
- }
+ if (type.interfaces != null && type.interfaces.length > 0) {
+ var interfaceStr = joinWithCommas(map(type.interfaces, typeReference));
+ write('Implements ${interfaceStr}. ');
+ }
- if (factory != null) {
- write('Has factory class ${typeReference(factory)}.');
+ if (defaultType != null) {
+ write('Has default class ${typeReference(defaultType)}.');
+ }
}
}
-}
-/** Document the constructors for [Type], if any. */
-docConstructors(Type type) {
- final names = type.constructors.getKeys().filter(
- (name) => !name.startsWith('_'));
+ /** Document the constructors for [Type], if any. */
+ 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()));
+ 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);
+ for (final name in names) {
+ docMethod(type, type.constructors[name], constructorName: name);
+ }
}
}
-}
-
-/**
- * Documents the [method] in type [type]. Handles all kinds of methods
- * including getters, setters, and constructors.
- */
-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>');
- }
+ void docMembers(Type type) {
+ // Collect the different kinds of members.
+ final methods = [];
+ final fields = [];
- if (method.isStatic && !type.isTop) {
- write('static ');
- }
+ for (final member in orderByName(type.members)) {
+ if (member.name.startsWith('_')) continue;
- if (method.isConstructor) {
- write(method.isConst ? 'const ' : 'new ');
- }
+ 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 (constructorName == null) {
- annotateType(type, method.returnType);
- }
+ if (methods.length > 0) {
+ writeln('<h3>Methods</h3>');
+ for (final method in methods) docMethod(type, method);
+ }
- // 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 {
- // See if it's an operator.
- name = TokenKind.rawOperatorFromMethod(name);
- if (name == null) {
- name = method.name;
- } else {
- name = 'operator $name';
+ if (fields.length > 0) {
+ writeln('<h3>Fields</h3>');
+ for (final field in fields) docField(type, field);
}
}
- write('<strong>$name</strong>');
-
- // Named constructors.
- if (constructorName != null && constructorName != '') {
- write('.');
- write(constructorName);
- }
+ /**
+ * Documents the [method] in type [type]. Handles all kinds of methods
+ * including getters, setters, and constructors.
+ */
+ docMethod(Type type, MethodMember method, [String constructorName = null]) {
+ _totalMembers++;
+ _currentMember = method;
- docParamList(type, method);
+ writeln('<div class="method"><h4 id="${memberAnchor(method)}">');
- write(''' <a class="anchor-link" href="#${memberAnchor(method)}"
- title="Permalink to ${typeName(type)}.$name">#</a>''');
- writeln('</h4>');
+ if (includeSource) {
+ writeln('<span class="show-code">Code</span>');
+ }
- docCode(method.span, _runDocumenters(method, _methodDocumenters),
- showCode: true);
+ if (method.isStatic && !type.isTop) {
+ write('static ');
+ }
- writeln('</div>');
-}
+ if (method.isConstructor) {
+ write(method.isConst ? 'const ' : 'new ');
+ }
-docParamList(Type enclosingType, MethodMember member) {
- write('(');
- bool first = true;
- bool inOptionals = false;
- for (final parameter in member.parameters) {
- if (!first) write(', ');
+ if (constructorName == null) {
+ annotateType(type, method.returnType);
+ }
- if (!inOptionals && parameter.isOptional) {
- write('[');
- inOptionals = true;
+ // 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 {
+ // See if it's an operator.
+ name = TokenKind.rawOperatorFromMethod(name);
+ if (name == null) {
+ name = method.name;
+ } else {
+ name = 'operator $name';
+ }
}
- annotateType(enclosingType, parameter.type, parameter.name);
+ write('<strong>$name</strong>');
- // 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);
+ // Named constructors.
+ if (constructorName != null && constructorName != '') {
+ write('.');
+ write(constructorName);
}
- first = false;
- }
-
- if (inOptionals) write(']');
- write(')');
-}
+ docParamList(type, method);
-/** Documents the field [field] of type [type]. */
-docField(Type type, FieldMember field) {
- _totalMembers++;
- _currentMember = field;
+ write(''' <a class="anchor-link" href="#${memberAnchor(method)}"
+ title="Permalink to ${typeName(type)}.$name">#</a>''');
+ writeln('</h4>');
- writeln('<div class="field"><h4 id="${memberAnchor(field)}">');
+ docCode(method.span, getMethodComment(method), showCode: true);
- if (includeSource) {
- writeln('<span class="show-code">Code</span>');
+ writeln('</div>');
}
- if (field.isStatic && !type.isTop) {
- write('static ');
- }
+ /** Documents the field [field] of type [type]. */
+ docField(Type type, FieldMember field) {
+ _totalMembers++;
+ _currentMember = field;
- if (field.isFinal) {
- write('final ');
- } else if (field.type.name == 'Dynamic') {
- write('var ');
- }
+ writeln('<div class="field"><h4 id="${memberAnchor(field)}">');
- 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, _runDocumenters(field, _fieldDocumenters),
- showCode: true);
- writeln('</div>');
-}
+ if (includeSource) {
+ writeln('<span class="show-code">Code</span>');
+ }
-/**
- * Creates a hyperlink. Handles turning the [href] into an appropriate relative
- * path from the current file.
- */
-String a(String href, String contents, [String class]) {
- final css = class == null ? '' : ' class="$class"';
- return '<a href="${relativePath(href)}"$css>$contents</a>';
-}
+ if (field.isStatic && !type.isTop) {
+ write('static ');
+ }
-/** 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);
- }
+ if (field.isFinal) {
+ write('final ');
+ } else if (field.type.name == 'Dynamic') {
+ write('var ');
}
- final params = Strings.join(typeParams, ', ');
- return '${type.name}&lt;$params&gt;';
- }
+ 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>
+ ''');
- // See if it's an instantiation of a generic type.
- final typeArgs = type.typeArgsInOrder;
- if (typeArgs != null) {
- final args = Strings.join(map(typeArgs, typeName), ', ');
- return '${type.genericType.name}&lt;$args&gt;';
+ docCode(field.span, getFieldComment(field), showCode: true);
+ writeln('</div>');
}
- // Regular type.
- return type.name;
-}
+ docParamList(Type enclosingType, MethodMember member) {
+ write('(');
+ bool first = true;
+ bool inOptionals = false;
+ for (final parameter in member.parameters) {
+ if (!first) write(', ');
-/** 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;
- }
+ if (!inOptionals && parameter.isOptional) {
+ write('[');
+ inOptionals = true;
+ }
- // 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;
- }
+ 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);
+ }
- // See if it's an instantiation of a generic type.
- final typeArgs = type.typeArgsInOrder;
- if (typeArgs != null) {
- 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), class: 'crossref');
-}
-/**
- * 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;
+ if (inOptionals) write(']');
+ write(')');
}
- // For parameters, handle non-typedefed function types.
- if (paramName !== null) {
- final call = type.getCallMethod();
- if (call != null) {
- annotateType(enclosingType, call.returnType);
- write(paramName);
+ /**
+ * Documents the code contained within [span] with [comment]. If [showCode]
+ * is `true` (and [includeSource] is set), also includes the source code.
+ */
+ docCode(SourceSpan span, String comment, [bool showCode = false]) {
+ writeln('<div class="doc">');
+ if (comment != null) {
+ writeln(md.markdownToHtml(comment));
+ }
- docParamList(enclosingType, call);
- return;
+ if (includeSource && showCode) {
+ writeln('<pre class="source">');
+ write(formatCode(span));
+ writeln('</pre>');
}
+
+ writeln('</div>');
}
- linkToType(enclosingType, type);
+ /** Get the doc comment associated with the given type. */
+ String getTypeComment(Type type) => _comments.find(type.span);
- write(' ');
- if (paramName !== null) write(paramName);
-}
+ /** Get the doc comment associated with the given method. */
+ String getMethodComment(MethodMember method) => _comments.find(method.span);
+ /** Get the doc comment associated with the given field. */
+ String getFieldComment(FieldMember field) => _comments.find(field.span);
-/**
- * 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) {
- makeLink(String href) {
- final anchor = new md.Element.text('a', name);
- anchor.attributes['href'] = relativePath(href);
- anchor.attributes['class'] = 'crossref';
- return anchor;
+ /**
+ * Creates a hyperlink. Handles turning the [href] into an appropriate
+ * relative path from the current file.
+ */
+ String a(String href, String contents, [String class]) {
+ final css = class == null ? '' : ' class="$class"';
+ return '<a href="${relativePath(href)}"$css>$contents</a>';
}
- findMember(Type type) {
- final member = type.members[name];
- 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;
+ /**
+ * 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;
}
- return member;
- }
+ // For parameters, handle non-typedefed function types.
+ if (paramName !== null) {
+ final call = type.getCallMethod();
+ if (call != null) {
+ annotateType(enclosingType, call.returnType);
+ write(paramName);
- // See if it's a parameter of the current method.
- if (_currentMember != null) {
- for (final parameter in _currentMember.parameters) {
- if (parameter.name == name) {
- final element = new md.Element.text('span', name);
- element.attributes['class'] = 'param';
- return element;
+ docParamList(enclosingType, call);
+ return;
}
}
+
+ linkToType(enclosingType, type);
+
+ write(' ');
+ if (paramName !== null) write(paramName);
}
- // See if it's another member of the current type.
- if (_currentType != null) {
- final member = findMember(_currentType);
- if (member != null) {
- return makeLink(memberUrl(member));
+ /** 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;
}
- }
- // See if it's another type in the current library.
- if (_currentLibrary != null) {
- final type = _currentLibrary.types[name];
- if (type != null) {
- return makeLink(typeUrl(type));
+ // 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 a top-level member in the current library.
- final member = findMember(_currentLibrary.topType);
- if (member != null) {
- return makeLink(memberUrl(member));
+ // See if it's an instantiation of a generic type.
+ final typeArgs = type.typeArgsInOrder;
+ if (typeArgs != null) {
+ write('&lt;');
+ bool first = true;
+ for (final arg in typeArgs) {
+ if (!first) write(', ');
+ first = false;
+ linkToType(enclosingType, arg);
+ }
+ write('&gt;');
}
}
- // TODO(rnystrom): Should also consider:
- // * Names imported by libraries this library imports.
- // * Type parameters of the enclosing type.
+ /** 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), class: '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);
+ }
+ }
- return new md.Element.text('code', name);
-}
+ final params = Strings.join(typeParams, ', ');
+ return '${type.name}&lt;$params&gt;';
+ }
-/**
- * Documents the code contained within [span]. Will include the previous
- * Dartdoc associated with that span if found, and will include the syntax
- * highlighted code itself if desired.
- */
-docCode(SourceSpan span, String extraMarkdown, [bool showCode = false]) {
- if (span == null) return;
-
- writeln('<div class="doc">');
- final comment = findComment(span);
- if (comment != null) {
- writeln(md.markdownToHtml('${comment}\n\n${extraMarkdown}'));
- } else {
- writeln(md.markdownToHtml(extraMarkdown));
+ // See if it's an instantiation of a generic type.
+ final typeArgs = type.typeArgsInOrder;
+ if (typeArgs != null) {
+ final args = Strings.join(map(typeArgs, (arg) => typeName(arg)), ', ');
+ return '${type.genericType.name}&lt;$args&gt;';
+ }
+
+ // Regular type.
+ return type.name;
}
- if (includeSource && showCode) {
- writeln('<pre class="source">');
- write(formatCode(span));
- writeln('</pre>');
+ /**
+ * Takes a string of Dart code and turns it into sanitized HTML.
+ */
+ formatCode(SourceSpan span) {
+ // Remove leading indentation to line up with first line.
+ final column = getSpanColumn(span);
+ final lines = span.text.split('\n');
+ // TODO(rnystrom): Dirty hack.
+ for (final i = 1; i < lines.length; i++) {
+ lines[i] = unindent(lines[i], column);
+ }
+
+ final code = Strings.join(lines, '\n');
+
+ // Syntax highlight.
+ return classifySource(new SourceFile('', code));
}
- writeln('</div>');
-}
+ /**
+ * 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) {
+ makeLink(String href) {
+ final anchor = new md.Element.text('a', name);
+ anchor.attributes['href'] = relativePath(href);
+ anchor.attributes['class'] = 'crossref';
+ return anchor;
+ }
-/** Finds the doc comment preceding the given source span, if there is one. */
-findComment(SourceSpan span) => findCommentInFile(span.file, span.start);
+ findMember(Type type) {
+ final member = type.members[name];
+ if (member == null) return null;
-/** Finds the doc comment preceding the given source span, if there is one. */
-findCommentInFile(SourceFile file, int position) {
- // Get the doc comments for this file.
- final fileComments = _comments.putIfAbsent(file.filename,
- () => parseDocComments(file));
+ // 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 fileComments[position];
-}
+ return member;
+ }
-parseDocComments(SourceFile file) {
- final comments = new Map<int, String>();
-
- final tokenizer = new Tokenizer(file, false);
- var lastComment = null;
-
- while (true) {
- final token = tokenizer.next();
- if (token.kind == TokenKind.END_OF_FILE) break;
-
- if (token.kind == TokenKind.COMMENT) {
- final text = token.text;
- if (text.startsWith('/**')) {
- // Remember that we've encountered a doc comment.
- lastComment = stripComment(token.text);
- } else if (text.startsWith('///')) {
- var line = text.substring(3, text.length);
- // Allow a leading space.
- if (line.startsWith(' ')) line = line.substring(1, text.length);
- if (lastComment == null) {
- lastComment = line;
- } else {
- lastComment = '$lastComment$line';
+ // See if it's a parameter of the current method.
+ if (_currentMember != null) {
+ for (final parameter in _currentMember.parameters) {
+ if (parameter.name == name) {
+ final element = new md.Element.text('span', name);
+ element.attributes['class'] = 'param';
+ return element;
}
}
- } else if (token.kind == TokenKind.WHITESPACE) {
- // Ignore whitespace tokens.
- } else if (token.kind == TokenKind.HASH) {
- // Look for #library() to find the library comment.
- final next = tokenizer.next();
- if ((lastComment != null) && (next.kind == TokenKind.LIBRARY)) {
- comments[_libraryDoc] = lastComment;
- lastComment = null;
- }
- } else {
- if (lastComment != null) {
- // We haven't attached the last doc comment to something yet, so stick
- // it to this token.
- comments[token.start] = lastComment;
- lastComment = null;
- }
}
- }
- return comments;
-}
-
-/**
- * Takes a string of Dart code and turns it into sanitized HTML.
- */
-formatCode(SourceSpan span) {
- // Remove leading indentation to line up with first line.
- final column = getSpanColumn(span);
- final lines = span.text.split('\n');
- // TODO(rnystrom): Dirty hack.
- for (final i = 1; i < lines.length; i++) {
- lines[i] = unindent(lines[i], column);
- }
+ // See if it's another member of the current type.
+ if (_currentType != null) {
+ final member = findMember(_currentType);
+ if (member != null) {
+ return makeLink(memberUrl(member));
+ }
+ }
- final code = Strings.join(lines, '\n');
+ // See if it's another type in the current library.
+ if (_currentLibrary != null) {
+ final type = _currentLibrary.types[name];
+ if (type != null) {
+ return makeLink(typeUrl(type));
+ }
- // Syntax highlight.
- return classifySource(new SourceFile('', code));
-}
+ // See if it's a top-level member in the current library.
+ final member = findMember(_currentLibrary.topType);
+ if (member != null) {
+ return makeLink(memberUrl(member));
+ }
+ }
-// TODO(rnystrom): Move into SourceSpan?
-int getSpanColumn(SourceSpan span) {
- final line = span.file.getLine(span.start);
- return span.file.getColumn(line, span.start);
-}
+ // TODO(rnystrom): Should also consider:
+ // * Names imported by libraries this library imports.
+ // * Type parameters of the enclosing type.
-/**
- * Pulls the raw text out of a doc comment (i.e. removes the comment
- * characters).
- */
-stripComment(comment) {
- StringBuffer buf = new StringBuffer();
-
- for (final line in comment.split('\n')) {
- line = line.trim();
- if (line.startsWith('/**')) line = line.substring(3, line.length);
- if (line.endsWith('*/')) line = line.substring(0, line.length - 2);
- line = line.trim();
- if (line.startsWith('* ')) {
- line = line.substring(2, line.length);
- } else if (line.startsWith('*')) {
- line = line.substring(1, line.length);
- }
-
- buf.add(line);
- buf.add('\n');
+ return new md.Element.text('code', name);
}
- return buf.toString();
+ // TODO(rnystrom): Move into SourceSpan?
+ int getSpanColumn(SourceSpan span) {
+ final line = span.file.getLine(span.start);
+ return span.file.getColumn(line, span.start);
+ }
}
-
-/** Register a callback to add additional documentation to a type. */
-addTypeDocumenter(TypeDocumenter fn) => _typeDocumenters.add(fn);
-
-/** Register a callback to add additional documentation to a method. */
-addMethodDocumenter(MethodDocumenter fn) => _methodDocumenters.add(fn);
-
-/** Register a callback to add additional documentation to a field. */
-addFieldDocumenter(FieldDocumenter fn) => _fieldDocumenters.add(fn);
« no previous file with comments | « utils/dartdoc/comment_map.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698