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

Side by Side Diff: utils/dartdoc/dartdoc.dart

Issue 8758010: Create separate HTML pages for each type. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Get rid of explicit link stuff and just use fixed URLs. 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * To use it, from this directory, run: 6 * To use it, from this directory, run:
7 * 7 *
8 * $ dartdoc <path to .dart file> 8 * $ dartdoc <path to .dart file>
9 * 9 *
10 * This will create a "docs" directory with the docs for your libraries. To do 10 * This will create a "docs" directory with the docs for your libraries. The
11 * so, dartdoc parses that library and every library it imports. From each 11 * easiest way to preview your generated docs is to spin up a little web
12 * library, it parses all classes and members, finds the associated doc 12 * server, like:
13 * comments and builds crosslinked docs from them. 13 *
14 * $ python -m SimpleHTTPServer
15 *
16 * Then point your browser at `localhost:8000` to see your magnificent creation.
sethladd 2011/12/01 04:50:33 Probably don't need this anymore.
Bob Nystrom 2011/12/02 19:40:55 Done.
17 *
18 * To make beatiful docs from your library, dartdoc parses it and every library
pquitslund 2011/12/01 23:29:54 beatiful -> beautiful
Bob Nystrom 2011/12/02 19:40:55 Done.
19 * it imports (recursively). From each library, it parses all classes and
20 * members, finds the associated doc comments and builds crosslinked docs from
21 * them.
14 */ 22 */
15 #library('dartdoc'); 23 #library('dartdoc');
16 24
17 #import('../../frog/lang.dart'); 25 #import('../../frog/lang.dart');
18 #import('../../frog/file_system.dart'); 26 #import('../../frog/file_system.dart');
19 #import('../../frog/file_system_node.dart'); 27 #import('../../frog/file_system_node.dart');
20 #import('../markdown/lib.dart', prefix: 'md'); 28 #import('../markdown/lib.dart', prefix: 'md');
21 29
22 #source('classify.dart'); 30 #source('classify.dart');
23 31
24 /** Path to corePath library. */ 32 /** Path to corePath library. */
25 final corePath = 'lib'; 33 final corePath = 'lib';
26 34
27 /** Path to generate html files into. */ 35 /** Path to generate html files into. */
28 final outdir = 'docs'; 36 final outdir = 'docs';
29 37
30 /** Set to `true` to include the source code in the generated docs. */ 38 /** Set to `true` to include the source code in the generated docs. */
31 bool includeSource = true; 39 bool includeSource = true;
32 40
33 /** Special comment position used to store the library-level doc comment. */ 41 /** Special comment position used to store the library-level doc comment. */
34 final _libraryDoc = -1; 42 final _libraryDoc = -1;
35 43
44 /** The path to the file currently being written to, relative to [outdir]. */
45 String _filePath;
46
36 /** The file currently being written to. */ 47 /** The file currently being written to. */
37 StringBuffer _file; 48 StringBuffer _file;
38 49
39 /** The library that we're currently generating docs for. */ 50 /** The library that we're currently generating docs for. */
40 Library _currentLibrary; 51 Library _currentLibrary;
41 52
42 /** The type that we're currently generating docs for. */ 53 /** The type that we're currently generating docs for. */
43 Type _currentType; 54 Type _currentType;
44 55
45 /** The member that we're currently generating docs for. */ 56 /** The member that we're currently generating docs for. */
(...skipping 14 matching lines...) Expand all
60 71
61 FileSystem files; 72 FileSystem files;
62 73
63 /** 74 /**
64 * Run this from the `utils/dartdoc` directory. 75 * Run this from the `utils/dartdoc` directory.
65 */ 76 */
66 void main() { 77 void main() {
67 // The entrypoint of the library to generate docs for. 78 // The entrypoint of the library to generate docs for.
68 final libPath = process.argv[2]; 79 final libPath = process.argv[2];
69 80
81 // Parse the dartdoc options.
82 for (int i = 3; i < process.argv.length; i++) {
83 final arg = process.argv[i];
84 switch (arg) {
85 case '--no-code':
86 includeSource = false;
87 break;
88
89 default:
90 print('Unknown option: $arg');
91 }
92 }
93
70 files = new NodeFileSystem(); 94 files = new NodeFileSystem();
71 parseOptions('../../frog', [] /* args */, files); 95 parseOptions('../../frog', [] /* args */, files);
72 96
73 // Patch in support for [:...:]-style code to the markdown parser. 97 // Patch in support for [:...:]-style code to the markdown parser.
74 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? 98 // TODO(rnystrom): Markdown already has syntax for this. Phase this out?
75 md.InlineParser.syntaxes.insertRange(0, 1, 99 md.InlineParser.syntaxes.insertRange(0, 1,
76 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); 100 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]'));
77 101
78 md.setImplicitLinkResolver(resolveNameReference); 102 md.setImplicitLinkResolver(resolveNameReference);
79 103
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 144
121 num time(callback()) { 145 num time(callback()) {
122 // Unlike world.withTiming, returns the elapsed time. 146 // Unlike world.withTiming, returns the elapsed time.
123 final watch = new Stopwatch(); 147 final watch = new Stopwatch();
124 watch.start(); 148 watch.start();
125 callback(); 149 callback();
126 watch.stop(); 150 watch.stop();
127 return watch.elapsedInMs(); 151 return watch.elapsedInMs();
128 } 152 }
129 153
130 startFile() { 154 startFile(String path) {
155 _filePath = path;
131 _file = new StringBuffer(); 156 _file = new StringBuffer();
132 } 157 }
133 158
134 write(String s) { 159 write(String s) {
135 _file.add(s); 160 _file.add(s);
136 } 161 }
137 162
138 writeln(String s) { 163 writeln(String s) {
139 write(s); 164 write(s);
140 write('\n'); 165 write('\n');
141 } 166 }
142 167
143 endFile(String outfile) { 168 endFile() {
144 world.files.writeString(outfile, _file.toString()); 169 String outPath = '$outdir/$_filePath';
170 files.createDirectory(dirname(outPath), recursive: true);
171
172 world.files.writeString(outPath, _file.toString());
173 _filePath = null;
145 _file = null; 174 _file = null;
146 } 175 }
147 176
148 /** Turns a library name into something that's safe to use as a file name. */ 177 /** Turns a library name into something that's safe to use as a file name. */
149 sanitize(String name) => name.replaceAll(':', '_').replaceAll('/', '_'); 178 sanitize(String name) => name.replaceAll(':', '_').replaceAll('/', '_');
150 179
151 docIndex(List<Library> libraries) { 180 docIndex(List<Library> libraries) {
152 startFile(); 181 startFile('index.html');
153 // TODO(rnystrom): Need to figure out what this should look like. 182 // TODO(rnystrom): Need to figure out what this should look like.
154 writeln( 183 writeln(
155 ''' 184 '''
156 <html><head> 185 <html><head>
157 <title>Index</title> 186 <title>Index</title>
158 <link rel="stylesheet" type="text/css" href="styles.css" /> 187 <link rel="stylesheet" type="text/css" href="styles.css" />
159 </head> 188 </head>
160 <body> 189 <body>
161 <div class="content"> 190 <div class="content">
162 <ul> 191 <ul>
163 '''); 192 ''');
164 193
165 final sorted = new List<Library>.from(libraries); 194 final sorted = new List<Library>.from(libraries);
166 sorted.sort((a, b) => a.name.compareTo(b.name)); 195 sorted.sort((a, b) => a.name.compareTo(b.name));
167 196
168 for (final library in sorted) { 197 for (final library in sorted) {
169 writeln( 198 writeln(
170 ''' 199 '''
171 <li><a href="${libraryUrl(library)}">Library ${library.name}</a></li> 200 <li>${a(libraryUrl(library), "Library ${library.name}")}</li>
pquitslund 2011/12/01 23:29:54 Aside: love that you extracted this method here.
Bob Nystrom 2011/12/02 19:40:55 Yeah, over time I suspect dartdoc will end up with
172 '''); 201 ''');
173 } 202 }
174 203
175 writeln( 204 writeln(
176 ''' 205 '''
177 </ul> 206 </ul>
178 </div> 207 </div>
179 </body></html> 208 </body></html>
180 '''); 209 ''');
181 210
182 endFile('$outdir/index.html'); 211 endFile();
212 }
213
214 /** Returs the number of times [needle] occurs in [haystack]. */
sethladd 2011/12/01 04:50:33 typo
Bob Nystrom 2011/12/02 19:40:55 Done.
215 int countOccurrences(String haystack, String needle) {
Siggi Cherem (dart-lang) 2011/12/02 16:50:26 nit: haystack, needle sound strange to me for this
Bob Nystrom 2011/12/02 19:40:55 Done: text/search.
216 int start = 0;
217 int count = 0;
218
219 while (true) {
220 start = haystack.indexOf(needle, start);
221 if (start == -1) break;
222 count++;
223 // Offsetting by needle length means overlapping needles are not counted.
224 start += needle.length;
225 }
226
227 return count;
228 }
229
230 /** Repeats [text] [count] times, separated by [separator] if given. */
231 String repeat(String text, int count, [String separator]) {
232 // TODO(rnystrom): Should be in stdlib.
Siggi Cherem (dart-lang) 2011/12/02 16:50:26 nit: stdlib -> corelib
Bob Nystrom 2011/12/02 19:40:55 Done.
233 final buffer = new StringBuffer();
234 for (int i = 0; i < count; i++) {
235 buffer.add(text);
236 if ((i < count - 1) && (separator !== null)) buffer.add(separator);
237 }
238
239 return buffer.toString();
240 }
241
242 /**
243 * Converts [absolute] which is understood to be a full path from the root of
244 * the generated docs to one relative to the current file.
245 */
246 String relativePath(String absolute) {
247 // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do this
248 // if the paths overlap.
249 return repeat('../', countOccurrences(_filePath, '/')) + absolute;
250 }
251
252 /**
253 * Creates a hyperlink. Handles turning the [href] into an appropriate relative
254 * path from the current file.
255 */
256 String a(String href, String contents, [String class]) {
257 final css = class == null ? '' : ' class="$class"';
258 return '<a href="${relativePath(href)}"$css>$contents</a>';
259 }
260
261 writeHeader(String title) {
262 writeln(
263 '''
sethladd 2011/12/01 04:50:33 let's get totally nerdy and put <!DOCTYPE html> he
Bob Nystrom 2011/12/02 19:40:55 Classy!
264 <html>
265 <head>
sethladd 2011/12/01 04:50:33 <meta charset="utf-8"> if you are utf-8
Bob Nystrom 2011/12/02 19:40:55 Done.
266 <title>$title</title>
267 <link rel="stylesheet" type="text/css"
268 href="${relativePath('styles.css')}" />
269 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700,8 00" rel="stylesheet" type="text/css">
270 <script src="${relativePath('interact.js')}"></script>
sethladd 2011/12/01 04:50:33 is there a way to insert an Analytics code here? i
Bob Nystrom 2011/12/02 19:40:55 I plan to make dartdoc more extensible so that you
271 </head>
272 <body>
273 <div class="content">
274 ''');
275 }
276
277 writeFooter() {
278 writeln(
279 '''
280 </div>
281 </body></html>
282 ''');
183 } 283 }
184 284
185 docLibrary(Library library) { 285 docLibrary(Library library) {
186 _totalLibraries++; 286 _totalLibraries++;
187 _currentLibrary = library; 287 _currentLibrary = library;
188 288
189 startFile(); 289 startFile(libraryUrl(library));
190 writeln( 290 writeHeader(library.name);
191 ''' 291 writeln('<h1>Library <strong>${library.name}</strong></h1>');
192 <html>
193 <head>
194 <title>${library.name}</title>
195 <link rel="stylesheet" type="text/css" href="styles.css" />
196 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700,8 00" rel="stylesheet" type="text/css">
197 <script src="interact.js"></script>
198 </head>
199 <body>
200 <div class="content">
201 <h1>Library <strong>${library.name}</strong></h1>
202 ''');
203
204 bool needsSeparator = false;
205 292
206 // Look for a comment for the entire library. 293 // Look for a comment for the entire library.
207 final comment = findCommentInFile(library.baseSource, _libraryDoc); 294 final comment = findCommentInFile(library.baseSource, _libraryDoc);
208 if (comment != null) { 295 if (comment != null) {
209 final html = md.markdownToHtml(comment); 296 final html = md.markdownToHtml(comment);
210 writeln('<div class="doc">$html</div>'); 297 writeln('<div class="doc">$html</div>');
211 needsSeparator = true;
212 } 298 }
213 299
300 // Document the top-level members.
301 docMembers(library.topType);
302
303 // TODO(rnystrom): Link to types.
304 writeln('<h3>Types</h3>');
305
214 for (final type in orderValuesByKeys(library.types)) { 306 for (final type in orderValuesByKeys(library.types)) {
215 // Skip private types (for now at least). 307 if (type.isTop) continue;
216 if ((type.name != null) && type.name.startsWith('_')) continue; 308 writeln(
217 309 '''
218 if (needsSeparator) writeln('<hr/>'); 310 <div class="type">
219 if (docType(type)) needsSeparator = true; 311 <h4>
sethladd 2011/12/01 04:50:33 why not apply the class="type" to the h4? then we
Bob Nystrom 2011/12/02 19:40:55 It's consistent with the markup we use for members
312 ${type.isClass ? "class" : "interface"}
313 ${a(typeUrl(type), "<strong>${type.name}</strong>")}
314 </h4>
315 </div>
316 ''');
220 } 317 }
221 318
222 writeln( 319 writeFooter();
223 ''' 320 endFile();
224 </div>
225 </body></html>
226 ''');
227 321
228 endFile('$outdir/${sanitize(library.name)}.html'); 322 for (final type in library.types.getValues()) {
323 if (!type.isTop) docType(type);
324 }
229 } 325 }
230 326
231 /** 327 docType(Type type) {
232 * Documents [type]. Handles top-level members if given an unnamed Type.
233 * Returns `true` if it wrote anything.
234 */
235 bool docType(Type type) {
236 _totalTypes++; 328 _totalTypes++;
237 _currentType = type; 329 _currentType = type;
238 330
239 bool wroteSomething = false; 331 startFile(typeUrl(type));
240 332
241 if (type.name != null) { 333 final typeName = '${type.isClass ? "Class" : "Interface"} ${type.name}';
242 final name = typeName(type); 334 writeHeader('Library ${type.library.name} / $typeName');
335 writeln(
336 '''
337 <h1>${a(libraryUrl(type.library),
338 "Library <strong>${type.library.name}</strong>")}</h1>
339 <h2>${type.isClass ? "Class" : "Interface"}
340 <strong>${type.name}</strong></h2>
341 ''');
243 342
244 write( 343 docInheritance(type);
245 ''' 344 docCode(type.span);
246 <h2 id="${typeAnchor(type)}"> 345 docConstructors(type);
247 ${type.isClass ? "Class" : "Interface"} <strong>$name</strong> 346 docMembers(type);
248 <a class="anchor-link" href="${typeUrl(type)}"
249 title="Permalink to $name">#</a>
250 </h2>
251 ''');
252 347
253 docInheritance(type); 348 writeFooter();
254 docCode(type.span); 349 endFile();
255 docConstructors(type); 350 }
256 351
257 wroteSomething = true; 352 void docMembers(Type type) {
258 }
259
260 // Collect the different kinds of members. 353 // Collect the different kinds of members.
261 final methods = []; 354 final methods = [];
262 final fields = []; 355 final fields = [];
263 356
264 for (final member in orderValuesByKeys(type.members)) { 357 for (final member in orderValuesByKeys(type.members)) {
265 if (member.isMethod && 358 if (member.name.startsWith('_')) continue;
266 (member.definition != null) && 359
267 !member.name.startsWith('_')) { 360 if (member.isProperty) {
268 methods.add(member);
269 } else if (member.isProperty) {
270 if (member.canGet) methods.add(member.getter); 361 if (member.canGet) methods.add(member.getter);
271 if (member.canSet) methods.add(member.setter); 362 if (member.canSet) methods.add(member.setter);
272 } else if (member.isField && !member.name.startsWith('_')) { 363 } else if (member.isMethod) {
364 methods.add(member);
365 } else if (member.isField) {
273 fields.add(member); 366 fields.add(member);
274 } 367 }
275 } 368 }
276 369
277 if (methods.length > 0) { 370 if (methods.length > 0) {
278 writeln('<h3>Methods</h3>'); 371 writeln('<h3>Methods</h3>');
279 for (final method in methods) docMethod(type, method); 372 for (final method in methods) docMethod(type, method);
280 } 373 }
281 374
282 if (fields.length > 0) { 375 if (fields.length > 0) {
283 writeln('<h3>Fields</h3>'); 376 writeln('<h3>Fields</h3>');
284 for (final field in fields) docField(type, field); 377 for (final field in fields) docField(type, field);
285 } 378 }
286
287 return wroteSomething || methods.length > 0 || fields.length > 0;
288 } 379 }
289 380
290 /** Document the superclass and superinterfaces of [Type]. */ 381 /** Document the superclass and superinterfaces of [Type]. */
291 docInheritance(Type type) { 382 docInheritance(Type type) {
292 // Show the superclass and superinterface(s). 383 // Show the superclass and superinterface(s).
293 final isSubclass = (type.parent != null) && !type.parent.isObject; 384 final isSubclass = (type.parent != null) && !type.parent.isObject;
294 385
295 if (isSubclass || (type.interfaces != null && type.interfaces.length > 0)) { 386 if (isSubclass || (type.interfaces != null && type.interfaces.length > 0)) {
296 writeln('<p>'); 387 writeln('<p>');
297 388
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 if (field.isFinal) { 518 if (field.isFinal) {
428 write('final '); 519 write('final ');
429 } else if (field.type.name == 'Dynamic') { 520 } else if (field.type.name == 'Dynamic') {
430 write('var '); 521 write('var ');
431 } 522 }
432 523
433 write(annotation(type, field.type)); 524 write(annotation(type, field.type));
434 write( 525 write(
435 ''' 526 '''
436 <strong>${field.name}</strong> <a class="anchor-link" 527 <strong>${field.name}</strong> <a class="anchor-link"
437 href="#${memberUrl(field)}" 528 href="#${memberAnchor(field)}"
438 title="Permalink to ${type.name}.${field.name}">#</a> 529 title="Permalink to ${type.name}.${field.name}">#</a>
439 </h4> 530 </h4>
440 '''); 531 ''');
441 532
442 docCode(field.span, showCode: true); 533 docCode(field.span, showCode: true);
443 writeln('</div>'); 534 writeln('</div>');
444 } 535 }
445 536
446 /** Generates a human-friendly string representation for a type. */ 537 /** Generates a human-friendly string representation for a type. */
447 typeName(Type type) { 538 typeName(Type type) {
448 // See if it's a generic type. 539 // See if it's a generic type.
449 if (type.isGeneric) { 540 if (type.isGeneric) {
450 final typeParams = type.genericType.typeParameters; 541 final typeParams = type.genericType.typeParameters;
451 final params = Strings.join(map(typeParams, (p) => p.name), ', '); 542 final params = Strings.join(map(typeParams, (p) => p.name), ', ');
452 return '${type.name}&lt;$params&gt;'; 543 return '${type.name}&lt;$params&gt;';
453 } 544 }
454 545
455 // See if it's an instantiation of a generic type. 546 // See if it's an instantiation of a generic type.
456 final typeArgs = type.typeArgsInOrder; 547 final typeArgs = type.typeArgsInOrder;
457 if (typeArgs != null) { 548 if (typeArgs != null) {
458 final args = Strings.join(map(typeArgs, typeName), ', '); 549 final args = Strings.join(map(typeArgs, typeName), ', ');
459 return '${type.genericType.name}&lt;$args&gt;'; 550 return '${type.genericType.name}&lt;$args&gt;';
460 } 551 }
461 552
462 // Regular type. 553 // Regular type.
463 return type.name; 554 return type.name;
464 } 555 }
465 556
466 /** Gets the URL to the documentation for [library]. */ 557 /** Gets the URL to the documentation for [library]. */
467 libraryUrl(Library library) => '${sanitize(library.name)}.html'; 558 libraryUrl(Library library) {
559 return '${sanitize(library.name)}.html';
560 }
468 561
469 /** Gets the URL for the documentation for [type]. */ 562 /** Gets the URL for the documentation for [type]. */
470 typeUrl(Type type) => '${libraryUrl(type.library)}#${typeAnchor(type)}'; 563 typeUrl(Type type) {
564 // Always get the generic type to strip off any type parameters or arguments.
565 // If the type isn't generic, genericType returns `this`, so it works for
566 // non-generic types too.
567 return '${sanitize(type.library.name)}/${type.genericType.name}.html';
568 }
471 569
472 /** Gets the URL for the documentation for [member]. */ 570 /** Gets the URL for the documentation for [member]. */
473 memberUrl(Member member) => '${typeUrl(member.declaringType)}-${member.name}'; 571 memberUrl(Member member) {
474 572 return '${typeUrl(member.declaringType)}#${member.name}';
475 /** Gets the anchor id for the document for [type]. */
476 typeAnchor(Type type) {
477 var name = type.name;
478
479 // No name for the special type that contains top-level members.
480 if (type.isTop) return '';
481
482 // Remove any type args or params that have been mangled into the name.
483 var dollar = name.indexOf('\$', 0);
484 if (dollar != -1) name = name.substring(0, dollar);
485
486 return name;
487 } 573 }
488 574
489 /** Gets the anchor id for the document for [member]. */ 575 /** Gets the anchor id for the document for [member]. */
490 memberAnchor(Member member) { 576 memberAnchor(Member member) => '${member.name}';
491 return '${typeAnchor(member.declaringType)}-${member.name}';
492 }
493 577
494 /** Writes a linked cross reference to [type]. */ 578 /** Writes a linked cross reference to [type]. */
495 typeReference(Type type) { 579 typeReference(Type type) {
496 // TODO(rnystrom): Do we need to handle ParameterTypes here like 580 // TODO(rnystrom): Do we need to handle ParameterTypes here like
497 // annotation() does? 581 // annotation() does?
498 return '<a href="${typeUrl(type)}" class="crossref">${typeName(type)}</a>'; 582 return a(typeUrl(type), typeName(type), class: 'crossref');
499 } 583 }
500 584
501 /** 585 /**
502 * Creates a linked string for an optional type annotation. Returns an empty 586 * Creates a linked string for an optional type annotation. Returns an empty
503 * string if the type is Dynamic. 587 * string if the type is Dynamic.
504 */ 588 */
505 annotation(Type enclosingType, Type type) { 589 annotation(Type enclosingType, Type type) {
506 if (type.name == 'Dynamic') return ''; 590 if (type.name == 'Dynamic') return '';
507 591
508 // If we're using a type parameter within the body of a generic class then 592 // If we're using a type parameter within the body of a generic class then
509 // just link back up to the class. 593 // just link back up to the class.
510 if (type is ParameterType) { 594 if (type is ParameterType) {
511 final library = sanitize(enclosingType.library.name); 595 return '${a(typeUrl(enclosingType), type.name)} ';
512 return '<a href="${typeUrl(enclosingType)}">${type.name}</a> ';
513 } 596 }
514 597
515 // Link to the type. 598 // Link to the type.
516 return '<a href="${typeUrl(type)}">${typeName(type)}</a> '; 599 return '${a(typeUrl(type), typeName(type))} ';
517 } 600 }
518 601
519 /** 602 /**
520 * This will be called whenever a doc comment hits a `[name]` in square 603 * This will be called whenever a doc comment hits a `[name]` in square
521 * brackets. It will try to figure out what the name refers to and link or 604 * brackets. It will try to figure out what the name refers to and link or
522 * style it appropriately. 605 * style it appropriately.
523 */ 606 */
524 md.Node resolveNameReference(String name) { 607 md.Node resolveNameReference(String name) {
525 if (_currentMember != null) {
526 // See if it's a parameter of the current method.
527 for (final parameter in _currentMember.parameters) {
528 if (parameter.name == name) {
529 final element = new md.Element.text('span', name);
530 element.attributes['class'] = 'param';
531 return element;
532 }
533 }
534 }
535
536 makeLink(String href) { 608 makeLink(String href) {
537 final anchor = new md.Element.text('a', name); 609 final anchor = new md.Element.text('a', name);
538 anchor.attributes['href'] = href; 610 anchor.attributes['href'] = relativePath(href);
539 anchor.attributes['class'] = 'crossref'; 611 anchor.attributes['class'] = 'crossref';
540 return anchor; 612 return anchor;
541 } 613 }
542 614
543 findMember(Type type) { 615 findMember(Type type) {
544 final member = type.members[name]; 616 final member = type.members[name];
545 if (member == null) return null; 617 if (member == null) return null;
546 618
547 // Special case: if the member we've resolved is a property (i.e. it wraps 619 // Special case: if the member we've resolved is a property (i.e. it wraps
548 // a getter and/or setter then *that* member itself won't be on the docs, 620 // a getter and/or setter then *that* member itself won't be on the docs,
549 // just the getter or setter will be. So pick one of those to link to. 621 // just the getter or setter will be. So pick one of those to link to.
550 if (member.isProperty) { 622 if (member.isProperty) {
551 return member.canGet ? member.getter : member.setter; 623 return member.canGet ? member.getter : member.setter;
552 } 624 }
553 625
554 return member; 626 return member;
555 } 627 }
556 628
629 // See if it's a parameter of the current method.
630 if (_currentMember != null) {
631 for (final parameter in _currentMember.parameters) {
632 if (parameter.name == name) {
633 final element = new md.Element.text('span', name);
634 element.attributes['class'] = 'param';
635 return element;
636 }
637 }
638 }
639
557 // See if it's another member of the current type. 640 // See if it's another member of the current type.
558 if (_currentType != null) { 641 if (_currentType != null) {
559 final member = findMember(_currentType); 642 final member = findMember(_currentType);
560 if (member != null) { 643 if (member != null) {
561 return makeLink(memberUrl(member)); 644 return makeLink(memberUrl(member));
562 } 645 }
563 } 646 }
564 647
565 // See if it's another type in the current library. 648 // See if it's another type in the current library.
566 if (_currentLibrary != null) { 649 if (_currentLibrary != null) {
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 } else if (line.startsWith('*')) { 800 } else if (line.startsWith('*')) {
718 line = line.substring(1, line.length); 801 line = line.substring(1, line.length);
719 } 802 }
720 803
721 buf.add(line); 804 buf.add(line);
722 buf.add('\n'); 805 buf.add('\n');
723 } 806 }
724 807
725 return buf.toString(); 808 return buf.toString();
726 } 809 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698