OLD | NEW |
---|---|
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 // TODO(rnystrom): This is moving from a sample to being a real project. Right | 5 /** An awesome documentation generator. */ |
6 // now, to try this out: | 6 #library('dartdoc'); |
7 // 1. Compile interact.dart to JS: | |
8 // $ ./frogsh --out=docs/interact.js --compile-only docs/interact.dart | |
9 // 2. Run the doc generator: | |
10 // $ ./frogsh samples/doc.dart | |
11 // 3. Look at the results in frog/docs/ | |
12 | 7 |
13 /** An awesome documentation generator. */ | 8 #import('../../frog/lang.dart'); |
14 #library('doc'); | 9 #import('../../frog/file_system_node.dart'); |
15 | 10 |
16 #import('../lang.dart'); | 11 #source('classify.dart'); |
17 #import('../file_system_node.dart'); | |
18 #import('classify.dart'); | |
19 | |
20 /** Path to starting library or application. */ | |
21 // TODO(rnystrom): Make this a command-line arg. | |
22 final libPath = 'samples/doc.dart'; | |
23 | 12 |
24 /** Path to corePath library. */ | 13 /** Path to corePath library. */ |
25 final corePath = 'lib'; | 14 final corePath = 'lib'; |
26 | 15 |
27 /** Path to generate html files into. */ | 16 /** Path to generate html files into. */ |
28 final outdir = './docs'; | 17 final outdir = 'docs'; |
29 | 18 |
30 /** Special comment position used to store the library-level doc comment. */ | 19 /** Special comment position used to store the library-level doc comment. */ |
31 final _libraryDoc = -1; | 20 final _libraryDoc = -1; |
32 | 21 |
33 /** The file currently being written to. */ | 22 /** The file currently being written to. */ |
34 StringBuffer _file; | 23 StringBuffer _file; |
35 | 24 |
36 /** | 25 /** |
37 * The cached lookup-table to associate doc comments with spans. The outer map | 26 * The cached lookup-table to associate doc comments with spans. The outer map |
38 * is from filenames to doc comments in that file. The inner map maps from the | 27 * is from filenames to doc comments in that file. The inner map maps from the |
39 * token positions to doc comments. Each position is the starting offset of the | 28 * token positions to doc comments. Each position is the starting offset of the |
40 * next non-comment token *following* the doc comment. For example, the position | 29 * next non-comment token *following* the doc comment. For example, the position |
41 * for this comment would be the position of the "Map" token below. | 30 * for this comment would be the position of the "Map" token below. |
42 */ | 31 */ |
43 Map<String, Map<int, String>> _comments; | 32 Map<String, Map<int, String>> _comments; |
44 | 33 |
45 // TODO(jimhug): This generates really ugly output with lots of holes. | 34 int _totalLibraries = 0; |
Jennifer Messerly
2011/11/11 02:29:58
haha. yes, that TODO is very obsolete :)
jimhug
2011/11/11 18:02:31
Whoo hoo!
Bob Nystrom
2011/11/11 18:21:28
:D
Still need private members, but almost everyth
| |
35 int _totalTypes = 0; | |
36 int _totalMembers = 0; | |
46 | 37 |
47 /** | 38 /** |
48 * Run this from the frog/samples directory. Before running, you need | 39 * Run this from the frog/samples directory. Before running, you need |
49 * to create a docs dir with 'mkdir docs' - since Dart currently doesn't | 40 * to create a docs dir with 'mkdir docs' - since Dart currently doesn't |
50 * support creating new directories. | 41 * support creating new directories. |
51 */ | 42 */ |
52 void main() { | 43 void main() { |
44 // The entrypoint of the library to generate docs for. | |
45 final libPath = process.argv[2]; | |
46 | |
53 // TODO(rnystrom): Get options and homedir like frog.dart does. | 47 // TODO(rnystrom): Get options and homedir like frog.dart does. |
54 final files = new NodeFileSystem(); | 48 final files = new NodeFileSystem(); |
55 parseOptions('.', [] /* args */, files); | 49 parseOptions('../../frog', [] /* args */, files); |
56 | 50 |
57 initializeWorld(files); | 51 final elapsed = time(() { |
52 initializeWorld(files); | |
58 | 53 |
59 world.withTiming('parsed', () { | |
60 world.processScript(libPath); | 54 world.processScript(libPath); |
61 }); | 55 world.resolveAll(); |
62 | 56 |
63 world.withTiming('resolved', () { | |
64 world.resolveAll(); | |
65 }); | |
66 | |
67 world.withTiming('generated docs', () { | |
68 _comments = <String, Map<int, String>>{}; | 57 _comments = <String, Map<int, String>>{}; |
69 | 58 |
70 for (var library in world.libraries.getValues()) { | 59 for (var library in world.libraries.getValues()) { |
71 docLibrary(library); | 60 docLibrary(library); |
72 } | 61 } |
73 | 62 |
74 docIndex(world.libraries.getValues()); | 63 docIndex(world.libraries.getValues()); |
75 }); | 64 }); |
65 | |
66 print('Documented $_totalLibraries libraries, $_totalTypes types, and ' + | |
67 '$_totalMembers members in ${elapsed}msec.'); | |
jimhug
2011/11/11 18:02:31
Nice reporting code.
Bob Nystrom
2011/11/11 18:21:28
Thanks! I was using withTiming() before but that d
| |
68 } | |
69 | |
70 num time(callback()) { | |
71 // Unlike world.withTiming, returns the elapsed time. | |
72 final watch = new StopWatch(); | |
73 watch.start(); | |
74 callback(); | |
75 watch.stop(); | |
76 return watch.elapsedInMs(); | |
76 } | 77 } |
77 | 78 |
78 startFile() { | 79 startFile() { |
79 _file = new StringBuffer(); | 80 _file = new StringBuffer(); |
80 } | 81 } |
81 | 82 |
82 write(String s) { | 83 write(String s) { |
83 _file.add(s); | 84 _file.add(s); |
84 } | 85 } |
85 | 86 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 ''' | 127 ''' |
127 </ul> | 128 </ul> |
128 </div> | 129 </div> |
129 </body></html> | 130 </body></html> |
130 '''); | 131 '''); |
131 | 132 |
132 endFile('$outdir/index.html'); | 133 endFile('$outdir/index.html'); |
133 } | 134 } |
134 | 135 |
135 docLibrary(Library library) { | 136 docLibrary(Library library) { |
137 _totalLibraries++; | |
138 | |
136 startFile(); | 139 startFile(); |
137 writeln( | 140 writeln( |
138 ''' | 141 ''' |
139 <html> | 142 <html> |
140 <head> | 143 <head> |
141 <title>${library.name}</title> | 144 <title>${library.name}</title> |
142 <link rel="stylesheet" type="text/css" href="styles.css" /> | 145 <link rel="stylesheet" type="text/css" href="styles.css" /> |
143 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700,8 00" rel="stylesheet" type="text/css"> | 146 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700,8 00" rel="stylesheet" type="text/css"> |
144 <script src="interact.js"></script> | 147 <script src="interact.js"></script> |
145 </head> | 148 </head> |
146 <body> | 149 <body> |
147 <div class="content"> | 150 <div class="content"> |
148 <h1>Library <strong>${library.name}</strong></h1> | 151 <h1>Library <strong>${library.name}</strong></h1> |
149 '''); | 152 '''); |
150 | 153 |
151 bool needsSeparator = false; | 154 bool needsSeparator = false; |
152 | 155 |
153 // Look for a comment for the entire library. | 156 // Look for a comment for the entire library. |
154 final comment = findCommentInFile(library.baseSource, _libraryDoc); | 157 final comment = findCommentInFile(library.baseSource, _libraryDoc); |
155 if (comment != null) { | 158 if (comment != null) { |
156 writeln('<div class="doc"><p>$comment</p></div>'); | 159 writeln('<div class="doc"><p>$comment</p></div>'); |
157 needsSeparator = true; | 160 needsSeparator = true; |
158 } | 161 } |
159 | 162 |
160 for (var type in library.types.getValues()) { | 163 for (var type in library.types.getValues()) { |
161 if (needsSeparator) writeln('<hr/>'); | 164 if (needsSeparator) writeln('<hr/>'); |
162 if (docType(type)) needsSeparator = false; | 165 if (docType(type)) needsSeparator = true; |
163 } | 166 } |
164 | 167 |
165 writeln( | 168 writeln( |
166 ''' | 169 ''' |
167 </div> | 170 </div> |
168 </body></html> | 171 </body></html> |
169 '''); | 172 '''); |
170 | 173 |
171 endFile('$outdir/${sanitize(library.name)}.html'); | 174 endFile('$outdir/${sanitize(library.name)}.html'); |
172 } | 175 } |
173 | 176 |
174 /** | 177 /** |
175 * Documents [Type]. Handles top-level members if given an unnamed Type. | 178 * Documents [Type]. Handles top-level members if given an unnamed Type. |
176 * Returns [:true:] if it wrote anything. | 179 * Returns [:true:] if it wrote anything. |
177 */ | 180 */ |
178 bool docType(Type type) { | 181 bool docType(Type type) { |
182 _totalTypes++; | |
183 | |
179 bool wroteSomething = false; | 184 bool wroteSomething = false; |
180 | 185 |
181 if (type.name != null) { | 186 if (type.name != null) { |
182 write( | 187 write( |
183 ''' | 188 ''' |
184 <h2 id="${type.name}"> | 189 <h2 id="${type.name}"> |
185 ${type.isClass ? "Class" : "Interface"} <strong>${type.name}</strong> | 190 ${type.isClass ? "Class" : "Interface"} <strong>${type.name}</strong> |
186 <a class="anchor-link" href="#${type.name}" | 191 <a class="anchor-link" href="#${type.name}" |
187 title="Permalink to ${type.name}">#</a> | 192 title="Permalink to ${type.name}">#</a> |
188 </h2> | 193 </h2> |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 } | 284 } |
280 } | 285 } |
281 } | 286 } |
282 | 287 |
283 /** | 288 /** |
284 * Documents the [method] in a type named [typeName]. Handles all kinds of | 289 * Documents the [method] in a type named [typeName]. Handles all kinds of |
285 * methods including getters, setters, and constructors. | 290 * methods including getters, setters, and constructors. |
286 */ | 291 */ |
287 docMethod(String typeName, MethodMember method, | 292 docMethod(String typeName, MethodMember method, |
288 [String namedConstructor = null]) { | 293 [String namedConstructor = null]) { |
294 _totalMembers++; | |
295 | |
289 writeln( | 296 writeln( |
290 ''' | 297 ''' |
291 <div class="method"><h4 id="$typeName.${method.name}"> | 298 <div class="method"><h4 id="$typeName.${method.name}"> |
292 <span class="show-code">Code</span> | 299 <span class="show-code">Code</span> |
293 '''); | 300 '''); |
294 | 301 |
295 // A null typeName means it's a top-level definition which is implicitly | 302 // A null typeName means it's a top-level definition which is implicitly |
296 // static so doesn't need to annotate it. | 303 // static so doesn't need to annotate it. |
297 if (method.isStatic && (typeName != null)) { | 304 if (method.isStatic && (typeName != null)) { |
298 write('static '); | 305 write('static '); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
345 title="Permalink to $typeName.$name">#</a>'''); | 352 title="Permalink to $typeName.$name">#</a>'''); |
346 writeln('</h4>'); | 353 writeln('</h4>'); |
347 | 354 |
348 docCode(method.span, showCode: true); | 355 docCode(method.span, showCode: true); |
349 | 356 |
350 writeln('</div>'); | 357 writeln('</div>'); |
351 } | 358 } |
352 | 359 |
353 /** Documents the field [field] in a type named [typeName]. */ | 360 /** Documents the field [field] in a type named [typeName]. */ |
354 docField(String typeName, FieldMember field) { | 361 docField(String typeName, FieldMember field) { |
362 _totalMembers++; | |
363 | |
355 writeln( | 364 writeln( |
356 ''' | 365 ''' |
357 <div class="field"><h4 id="$typeName.${field.name}"> | 366 <div class="field"><h4 id="$typeName.${field.name}"> |
358 <span class="show-code">Code</span> | 367 <span class="show-code">Code</span> |
359 '''); | 368 '''); |
360 | 369 |
361 // A null typeName means it's a top-level definition which is implicitly | 370 // A null typeName means it's a top-level definition which is implicitly |
362 // static so doesn't need to annotate it. | 371 // static so doesn't need to annotate it. |
363 if (field.isStatic && (typeName != null)) { | 372 if (field.isStatic && (typeName != null)) { |
364 write('static '); | 373 write('static '); |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
533 if (line.endsWith('*/')) line = line.substring(0, line.length-2); | 542 if (line.endsWith('*/')) line = line.substring(0, line.length-2); |
534 line = line.trim(); | 543 line = line.trim(); |
535 while (line.startsWith('*')) line = line.substring(1, line.length); | 544 while (line.startsWith('*')) line = line.substring(1, line.length); |
536 line = line.trim(); | 545 line = line.trim(); |
537 buf.add(line); | 546 buf.add(line); |
538 buf.add(' '); | 547 buf.add(' '); |
539 } | 548 } |
540 | 549 |
541 return buf.toString(); | 550 return buf.toString(); |
542 } | 551 } |
OLD | NEW |