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 /** | 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 | 10 * This will create a "docs" directory with the docs for your libraries. To |
(...skipping 12 matching lines...) Expand all Loading... |
23 #source('classify.dart'); | 23 #source('classify.dart'); |
24 #source('files.dart'); | 24 #source('files.dart'); |
25 #source('utils.dart'); | 25 #source('utils.dart'); |
26 | 26 |
27 /** Path to corePath library. */ | 27 /** Path to corePath library. */ |
28 final corePath = 'lib'; | 28 final corePath = 'lib'; |
29 | 29 |
30 /** Path to generate html files into. */ | 30 /** Path to generate html files into. */ |
31 final outdir = 'docs'; | 31 final outdir = 'docs'; |
32 | 32 |
33 /** Set to `true` to include the source code in the generated docs. */ | 33 /** Set to `false` to not include the source code in the generated docs. */ |
34 bool includeSource = false; | 34 bool includeSource = true; |
35 | 35 |
36 /** Special comment position used to store the library-level doc comment. */ | 36 /** Special comment position used to store the library-level doc comment. */ |
37 final _libraryDoc = -1; | 37 final _libraryDoc = -1; |
38 | 38 |
39 /** The library that we're currently generating docs for. */ | 39 /** The library that we're currently generating docs for. */ |
40 Library _currentLibrary; | 40 Library _currentLibrary; |
41 | 41 |
42 /** The type that we're currently generating docs for. */ | 42 /** The type that we're currently generating docs for. */ |
43 Type _currentType; | 43 Type _currentType; |
44 | 44 |
(...skipping 11 matching lines...) Expand all Loading... |
56 | 56 |
57 int _totalLibraries = 0; | 57 int _totalLibraries = 0; |
58 int _totalTypes = 0; | 58 int _totalTypes = 0; |
59 int _totalMembers = 0; | 59 int _totalMembers = 0; |
60 | 60 |
61 /** | 61 /** |
62 * Run this from the `utils/dartdoc` directory. | 62 * Run this from the `utils/dartdoc` directory. |
63 */ | 63 */ |
64 void main() { | 64 void main() { |
65 // The entrypoint of the library to generate docs for. | 65 // The entrypoint of the library to generate docs for. |
66 final libPath = process.argv[2]; | 66 final entrypoint = process.argv[2]; |
67 | 67 |
68 // Parse the dartdoc options. | 68 // Parse the dartdoc options. |
69 for (int i = 3; i < process.argv.length; i++) { | 69 for (int i = 3; i < process.argv.length; i++) { |
70 final arg = process.argv[i]; | 70 final arg = process.argv[i]; |
71 switch (arg) { | 71 switch (arg) { |
72 case '--no-code': | 72 case '--no-code': |
73 includeSource = false; | 73 includeSource = false; |
74 break; | 74 break; |
75 | 75 |
76 default: | 76 default: |
77 print('Unknown option: $arg'); | 77 print('Unknown option: $arg'); |
78 } | 78 } |
79 } | 79 } |
80 | 80 |
81 files = new NodeFileSystem(); | 81 files = new NodeFileSystem(); |
82 parseOptions('../../frog', [] /* args */, files); | 82 parseOptions('../../frog', [] /* args */, files); |
| 83 options.dietParse = true; |
83 | 84 |
84 // Patch in support for [:...:]-style code to the markdown parser. | 85 // Patch in support for [:...:]-style code to the markdown parser. |
85 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? | 86 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? |
86 md.InlineParser.syntaxes.insertRange(0, 1, | 87 md.InlineParser.syntaxes.insertRange(0, 1, |
87 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); | 88 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); |
88 | 89 |
89 md.setImplicitLinkResolver(resolveNameReference); | 90 md.setImplicitLinkResolver(resolveNameReference); |
90 | 91 |
91 final elapsed = time(() { | 92 final elapsed = time(() { |
92 initializeDartDoc(); | 93 initializeDartDoc(); |
93 | 94 |
94 initializeWorld(files); | 95 initializeWorld(files); |
95 | 96 |
96 world.processDartScript(libPath); | 97 // Handle the built-in entrypoints. |
| 98 switch (entrypoint) { |
| 99 case 'corelib': |
| 100 world.getOrAddLibrary('dart:core'); |
| 101 world.getOrAddLibrary('dart:coreimpl'); |
| 102 world.process(); |
| 103 break; |
| 104 |
| 105 case 'dom': |
| 106 world.getOrAddLibrary('dart:core'); |
| 107 world.getOrAddLibrary('dart:coreimpl'); |
| 108 world.getOrAddLibrary('dart:dom'); |
| 109 world.process(); |
| 110 break; |
| 111 |
| 112 case 'html': |
| 113 world.getOrAddLibrary('dart:core'); |
| 114 world.getOrAddLibrary('dart:coreimpl'); |
| 115 world.getOrAddLibrary('dart:dom'); |
| 116 world.getOrAddLibrary('dart:html'); |
| 117 world.process(); |
| 118 break; |
| 119 |
| 120 default: |
| 121 // Normal entrypoint script. |
| 122 world.processDartScript(entrypoint); |
| 123 } |
| 124 |
97 world.resolveAll(); | 125 world.resolveAll(); |
98 | 126 |
99 // Generate the docs. | 127 // Generate the docs. |
| 128 docIndex(); |
100 for (final library in world.libraries.getValues()) { | 129 for (final library in world.libraries.getValues()) { |
101 docLibrary(library); | 130 docLibrary(library); |
102 } | 131 } |
103 | |
104 docIndex(world.libraries.getValues()); | |
105 }); | 132 }); |
106 | 133 |
107 print('Documented $_totalLibraries libraries, $_totalTypes types, and ' + | 134 print('Documented $_totalLibraries libraries, $_totalTypes types, and ' + |
108 '$_totalMembers members in ${elapsed}msec.'); | 135 '$_totalMembers members in ${elapsed}msec.'); |
109 } | 136 } |
110 | 137 |
111 void initializeDartDoc() { | 138 void initializeDartDoc() { |
112 _comments = <String, Map<int, String>>{}; | 139 _comments = <String, Map<int, String>>{}; |
113 } | 140 } |
114 | 141 |
115 docIndex(List<Library> libraries) { | |
116 startFile('index.html'); | |
117 // TODO(rnystrom): Need to figure out what this should look like. | |
118 writeln( | |
119 ''' | |
120 <html><head> | |
121 <title>Index</title> | |
122 <link rel="stylesheet" type="text/css" href="styles.css" /> | |
123 </head> | |
124 <body> | |
125 <div class="content"> | |
126 <ul> | |
127 '''); | |
128 | |
129 final sorted = new List<Library>.from(libraries); | |
130 sorted.sort((a, b) => a.name.compareTo(b.name)); | |
131 | |
132 for (final library in sorted) { | |
133 writeln( | |
134 ''' | |
135 <li>${a(libraryUrl(library), "Library ${library.name}")}</li> | |
136 '''); | |
137 } | |
138 | |
139 writeln( | |
140 ''' | |
141 </ul> | |
142 </div> | |
143 </body></html> | |
144 '''); | |
145 | |
146 endFile(); | |
147 } | |
148 | |
149 writeHeader(String title) { | 142 writeHeader(String title) { |
150 writeln( | 143 writeln( |
151 ''' | 144 ''' |
152 <!DOCTYPE html> | 145 <!DOCTYPE html> |
153 <html> | 146 <html> |
154 <head> | 147 <head> |
155 <meta charset="utf-8"> | 148 <meta charset="utf-8"> |
156 <title>$title</title> | 149 <title>$title</title> |
157 <link rel="stylesheet" type="text/css" | 150 <link rel="stylesheet" type="text/css" |
158 href="${relativePath('styles.css')}" /> | 151 href="${relativePath('styles.css')}" /> |
159 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700,8
00" rel="stylesheet" type="text/css"> | 152 <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600,700,8
00" rel="stylesheet" type="text/css"> |
160 <script src="${relativePath('interact.js')}"></script> | 153 <script src="${relativePath('interact.js')}"></script> |
161 </head> | 154 </head> |
162 <body> | 155 <body> |
163 <div class="page"> | 156 <div class="page"> |
164 '''); | 157 '''); |
165 docNavigation(); | 158 docNavigation(); |
166 writeln('<div class="content">'); | 159 writeln('<div class="content">'); |
167 } | 160 } |
168 | 161 |
169 writeFooter() { | 162 writeFooter() { |
170 writeln( | 163 writeln( |
171 ''' | 164 ''' |
172 </div> | 165 </div> |
173 <div class="footer"</div> | 166 <div class="footer"</div> |
174 </body></html> | 167 </body></html> |
175 '''); | 168 '''); |
176 } | 169 } |
177 | 170 |
| 171 docIndex() { |
| 172 startFile('index.html'); |
| 173 |
| 174 writeHeader('Dart Documentation'); |
| 175 |
| 176 writeln('<h1>Dart Documentation</h1>'); |
| 177 writeln('<h3>Libraries</h3>'); |
| 178 |
| 179 for (final library in orderByName(world.libraries)) { |
| 180 writeln( |
| 181 ''' |
| 182 <h4>${a(libraryUrl(library), "Library ${library.name}")}</h4> |
| 183 '''); |
| 184 } |
| 185 |
| 186 writeFooter(); |
| 187 endFile(); |
| 188 } |
| 189 |
178 docNavigation() { | 190 docNavigation() { |
179 writeln( | 191 writeln( |
180 ''' | 192 ''' |
181 <div class="nav"> | 193 <div class="nav"> |
182 <h1>Libraries</h1> | 194 <h1>${a("index.html", "Dart Documentation")}</h1> |
183 '''); | 195 '''); |
184 | 196 |
185 for (final library in orderValuesByKeys(world.libraries)) { | 197 for (final library in orderByName(world.libraries)) { |
186 write('<h2><div class="icon-library"></div> '); | 198 write('<h2><div class="icon-library"></div>'); |
187 | 199 |
188 if ((_currentLibrary == library) && (_currentType == null)) { | 200 if ((_currentLibrary == library) && (_currentType == null)) { |
189 write('<strong>${library.name}</strong>'); | 201 write('<strong>${library.name}</strong>'); |
190 } else { | 202 } else { |
191 write('${a(libraryUrl(library), library.name)}'); | 203 write('${a(libraryUrl(library), library.name)}'); |
192 } | 204 } |
193 write('</h2>'); | 205 write('</h2>'); |
194 | 206 |
195 final types = orderValuesByKeys(library.types); | 207 // Only expand classes in navigation for current library. |
196 if (types.length > 0) { | 208 if (_currentLibrary == library) docLibraryNavigation(library); |
197 writeln('<ul>'); | |
198 for (final type in types) { | |
199 if (type.isTop) continue; | |
200 if (type.name.startsWith('_')) continue; | |
201 | |
202 var icon = type.isClass ? 'icon-class' : 'icon-interface'; | |
203 write('<li><div class="$icon"></div> '); | |
204 | |
205 if (_currentType == type) { | |
206 write('<strong>${type.name}</strong>'); | |
207 } else { | |
208 write('${a(typeUrl(type), type.name)}'); | |
209 } | |
210 | |
211 writeln('</li>'); | |
212 } | |
213 | |
214 writeln('</ul>'); | |
215 } | |
216 } | 209 } |
217 | 210 |
218 writeln('</div>'); | 211 writeln('</div>'); |
219 } | 212 } |
220 | 213 |
| 214 /** Writes the navigation for the types contained by the given library. */ |
| 215 docLibraryNavigation(Library library) { |
| 216 final types = orderByName(library.types).filter( |
| 217 (type) => !type.isTop && !type.name.startsWith('_')); |
| 218 |
| 219 if (types.length == 0) return; |
| 220 |
| 221 writeln('<ul>'); |
| 222 for (final type in types) { |
| 223 var icon = type.isClass ? 'icon-class' : 'icon-interface'; |
| 224 write('<li><div class="$icon"></div>'); |
| 225 |
| 226 if (_currentType == type) { |
| 227 write('<strong>${typeName(type)}</strong>'); |
| 228 } else { |
| 229 write('${a(typeUrl(type), typeName(type))}'); |
| 230 } |
| 231 |
| 232 writeln('</li>'); |
| 233 } |
| 234 writeln('</ul>'); |
| 235 } |
| 236 |
221 docLibrary(Library library) { | 237 docLibrary(Library library) { |
222 _totalLibraries++; | 238 _totalLibraries++; |
223 _currentLibrary = library; | 239 _currentLibrary = library; |
224 _currentType = null; | 240 _currentType = null; |
225 | 241 |
226 startFile(libraryUrl(library)); | 242 startFile(libraryUrl(library)); |
227 writeHeader(library.name); | 243 writeHeader(library.name); |
228 writeln('<h1>Library <strong>${library.name}</strong></h1>'); | 244 writeln('<h1>Library <strong>${library.name}</strong></h1>'); |
229 | 245 |
230 // Look for a comment for the entire library. | 246 // Look for a comment for the entire library. |
231 final comment = findCommentInFile(library.baseSource, _libraryDoc); | 247 final comment = findCommentInFile(library.baseSource, _libraryDoc); |
232 if (comment != null) { | 248 if (comment != null) { |
233 final html = md.markdownToHtml(comment); | 249 final html = md.markdownToHtml(comment); |
234 writeln('<div class="doc">$html</div>'); | 250 writeln('<div class="doc">$html</div>'); |
235 } | 251 } |
236 | 252 |
237 // Document the top-level members. | 253 // Document the top-level members. |
238 docMembers(library.topType); | 254 docMembers(library.topType); |
239 | 255 |
240 // TODO(rnystrom): Link to types. | |
241 writeln('<h3>Types</h3>'); | 256 writeln('<h3>Types</h3>'); |
242 | 257 |
243 for (final type in orderValuesByKeys(library.types)) { | 258 for (final type in orderByName(library.types)) { |
244 if (type.isTop) continue; | 259 if (type.isTop) continue; |
245 if (type.name.startsWith('_')) continue; | 260 if (type.name.startsWith('_')) continue; |
246 writeln( | 261 writeln( |
247 ''' | 262 ''' |
248 <div class="type"> | 263 <div class="type"> |
249 <h4> | 264 <h4> |
250 ${type.isClass ? "class" : "interface"} | 265 ${type.isClass ? "class" : "interface"} |
251 ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")} | 266 ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")} |
252 </h4> | 267 </h4> |
253 </div> | 268 </div> |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 | 300 |
286 writeFooter(); | 301 writeFooter(); |
287 endFile(); | 302 endFile(); |
288 } | 303 } |
289 | 304 |
290 void docMembers(Type type) { | 305 void docMembers(Type type) { |
291 // Collect the different kinds of members. | 306 // Collect the different kinds of members. |
292 final methods = []; | 307 final methods = []; |
293 final fields = []; | 308 final fields = []; |
294 | 309 |
295 for (final member in orderValuesByKeys(type.members)) { | 310 for (final member in orderByName(type.members)) { |
296 if (member.name.startsWith('_')) continue; | 311 if (member.name.startsWith('_')) continue; |
297 | 312 |
298 if (member.isProperty) { | 313 if (member.isProperty) { |
299 if (member.canGet) methods.add(member.getter); | 314 if (member.canGet) methods.add(member.getter); |
300 if (member.canSet) methods.add(member.setter); | 315 if (member.canSet) methods.add(member.setter); |
301 } else if (member.isMethod) { | 316 } else if (member.isMethod) { |
302 methods.add(member); | 317 methods.add(member); |
303 } else if (member.isField) { | 318 } else if (member.isField) { |
304 fields.add(member); | 319 fields.add(member); |
305 } | 320 } |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 } else if (line.startsWith('*')) { | 743 } else if (line.startsWith('*')) { |
729 line = line.substring(1, line.length); | 744 line = line.substring(1, line.length); |
730 } | 745 } |
731 | 746 |
732 buf.add(line); | 747 buf.add(line); |
733 buf.add('\n'); | 748 buf.add('\n'); |
734 } | 749 } |
735 | 750 |
736 return buf.toString(); | 751 return buf.toString(); |
737 } | 752 } |
OLD | NEW |