OLD | NEW |
---|---|
(Empty) | |
1 #library("dump"); | |
nweiz
2012/02/01 00:10:39
Should probably have the same name as the file.
Jacob
2012/02/01 07:48:26
Done.
Jacob
2012/02/02 05:26:38
Added a class level comment to clarify that this f
| |
2 | |
3 #import("../../../frog/lib/node/node.dart"); | |
4 #import('../../../frog/lib/node/fs.dart'); | |
5 #import("dart:json"); | |
6 | |
7 Map database; | |
8 Map allProps; | |
9 Set matchedTypes; | |
nweiz
2012/02/01 00:10:39
These should have generic parameters.
Jacob
2012/02/01 07:48:26
I don't find that helpful when dealing with JSON.
nweiz
2012/02/01 21:23:02
I find it helpful as a reader of the code. I want
Jacob
2012/02/02 05:26:38
I don't want to write
Map<String, Map<String, Map<
nweiz
2012/02/02 19:54:34
A single-level declaration is okay, I suppose, as
| |
10 | |
11 String orEmpty(String str) { | |
12 return str == null ? "" : str; | |
13 } | |
14 | |
15 /** Returns whether the type has any property matching the specified name. */ | |
nweiz
2012/02/01 00:10:39
s/property/member/
Jacob
2012/02/02 05:26:38
Done.
| |
16 bool hasAny(String type, String prop) { | |
17 Map data = allProps[type]; | |
nweiz
2012/02/01 00:10:39
This type declaration would be unnecessary if allP
Jacob
2012/02/02 05:26:38
Done.
| |
18 return data['properties'].containsKey(prop) || | |
19 data['methods'].containsKey(prop) || | |
20 data['constants'].containsKey(prop); | |
21 } | |
22 | |
23 List<String> sortStringCollection(Collection<String> collection) { | |
nweiz
2012/02/01 00:10:39
I'd call this sortCollection and type it as "Colle
Jacob
2012/02/02 05:26:38
There is little value in being generic when I only
nweiz
2012/02/02 19:54:34
There's little value in being String-specific, eit
Jacob
2012/02/02 22:03:14
having a sortCollection method would be reasonable
| |
24 List<String> out = new List<String>(); | |
25 out.addAll(collection); | |
26 out.sort((String a, String b) => a.compareTo(b)); | |
27 return out; | |
28 } | |
29 | |
30 /** Switch from a List of members to a Map of members. */ | |
31 Map getMembersMap(Map entry) { | |
nweiz
2012/02/01 00:10:39
Either change the docstring or make this take a Li
Jacob
2012/02/02 05:26:38
removed comment as it was confusing
| |
32 List rawMembers = entry["members"]; | |
33 Map members = new Map<String, Object>(); | |
nweiz
2012/02/01 00:10:39
s/Object/Dynamic/. Also use a map literal. I guess
Jacob
2012/02/02 05:26:38
Done.
| |
34 for (Map entry in rawMembers) { | |
35 members[entry['name']] = entry; | |
36 } | |
37 return members; | |
38 } | |
39 | |
40 /** | |
41 * Add all missing members to the string output and return the number of | |
42 * missing members. | |
43 */ | |
44 int addMissingHelper(StringBuffer sb, String type, Map members, | |
45 String propType) { | |
nweiz
2012/02/01 00:10:39
Helper methods should be declared within the funct
Jacob
2012/02/02 05:26:38
agreed.
done.
| |
46 int total = 0; | |
47 Map expected = allProps[type][propType]; | |
48 if (expected == null) return total; | |
49 for(String name in sortStringCollection(expected.getKeys())) { | |
50 if (!members.containsKey(name)) { | |
51 total++; | |
52 sb.add(""" | |
nweiz
2012/02/01 00:10:39
Style nit: incorrect indentation.
Jacob
2012/02/02 05:26:38
this is the correct indentation so that the output
nweiz
2012/02/02 19:54:34
"<tr>" and "</tr>" should have the same indentatio
Jacob
2012/02/02 22:03:14
fixed
| |
53 <tr class="missing"> | |
54 <td>$name</td> | |
55 <td></td> | |
56 <td>Could not find documentation for $propType</td> | |
57 </tr> | |
58 """); | |
59 } | |
60 } | |
61 return total; | |
62 } | |
63 | |
64 int addMissing(StringBuffer sb, String type, Map members) { | |
65 int total = 0; | |
66 total += addMissingHelper(sb, type, members, 'properties'); | |
67 total += addMissingHelper(sb, type, members, 'methods'); | |
68 total += addMissingHelper(sb, type, members, 'constants'); | |
69 return total; | |
70 } | |
71 | |
72 /** | |
73 * Score an entry using heuristics to determine how well a entry | |
nweiz
2012/02/01 00:10:39
Grammar nit: "an entry".
Jacob
2012/02/02 05:26:38
Done.
| |
74 * matches the expected list of matching members. | |
75 * We could be much less naive and penalize spurious methods, prefer entries | |
76 * with class level comments, etc. | |
nweiz
2012/02/01 00:10:39
It'd be nice to have an example here of where we g
Jacob
2012/02/02 05:26:38
added a big comment
/**
* Score entries using si
nweiz
2012/02/02 19:54:34
This is great.
| |
77 */ | |
78 num scoreEntry(Map entry, String type) { | |
nweiz
2012/02/01 00:10:39
s/num/int/
Jacob
2012/02/02 05:26:38
there isn't any reason why the score won't be a fl
| |
79 num score = 0; | |
80 if (!entry.containsKey('skipped')) { | |
81 score++; | |
nweiz
2012/02/01 00:10:39
Why would we ever want to choose a skipped entry?
Jacob
2012/02/02 22:03:14
I doubt we would. Added a TODO to consider removin
| |
82 } | |
83 if (entry.containsKey("members")) { | |
84 Map members = getMembersMap(entry); | |
85 for (String name in members.getKeys()) { | |
nweiz
2012/02/01 00:10:39
Why are we converting the members list into a map,
Jacob
2012/02/02 05:26:38
to remove any possible duplicates from the origina
| |
86 if (hasAny(type, name)) { | |
87 score++; | |
88 } | |
89 } | |
90 } | |
91 return score; | |
92 } | |
93 | |
94 /** | |
95 * Given a list of candidates for the documentation for a type, find the one | |
96 * that is the best. | |
97 */ | |
98 Map pickBestEntry(List entries, String type) { | |
99 num bestScore = -1; | |
100 Map bestEntry; | |
101 for (Map entry in entries) { | |
102 if (entry != null) { | |
103 num score = scoreEntry(entry, type); | |
nweiz
2012/02/01 00:10:39
Indentation.
Alternately, "if (entry == null) con
Jacob
2012/02/02 05:26:38
control flow with continue is less readable in gen
nweiz
2012/02/02 19:54:34
It seems to me like it's the same case as "if (...
Jacob
2012/02/02 22:03:14
Some people go so far as to prohibit
if (...) ret
| |
104 if (score > bestScore) { | |
105 bestScore = score; | |
106 bestEntry = entry; | |
107 } | |
108 } | |
109 } | |
110 return bestEntry; | |
111 } | |
112 | |
113 void main() { | |
114 // Database of code documentation. | |
115 database = JSON.parse(fs.readFileSync('output/database.json', 'utf8')); | |
116 // Database of expected property names for each type in WebKit. | |
117 allProps = JSON.parse(fs.readFileSync('data/dartIdl.json', 'utf8')); | |
118 // Types we have documentation for. | |
119 matchedTypes = new Set<String>(); | |
120 int numMissingMethods = 0; | |
121 int numFoundMethods = 0; | |
122 int numExtraMethods = 0; | |
123 int numGen = 0; | |
124 int numSkipped = 0; | |
125 final sbSkipped = new StringBuffer(); | |
126 final sbAllExamples = new StringBuffer(); | |
127 final filteredDb = {}; | |
128 | |
129 // Table rows for all obsolete members. | |
130 final sbObsolete = new StringBuffer(); | |
131 // Main documentation file. | |
132 final sb = new StringBuffer(); | |
nweiz
2012/02/01 00:10:39
The vast number of string buffers being used in th
Jacob
2012/02/02 05:26:38
I agree that this code is ugly due to the lack of
nweiz
2012/02/02 19:54:34
When will the debugging code be removed?
Jacob
2012/02/02 22:03:14
in my copious free time. If you think it is a pri
| |
133 | |
134 sb.add(""" | |
nweiz
2012/02/01 00:10:39
Maybe add a TODO here for using a template system
Jacob
2012/02/02 05:26:38
Done.
| |
135 <html> | |
136 <head> | |
137 <style type="text/css"> | |
138 body { | |
139 background-color: #eee; | |
140 margin: 10px; | |
141 font: 14px/1.428 "Lucida Grande", "Lucida Sans Unicode", Lucida, Arial, Helvetica, sans-serif; | |
nweiz
2012/02/01 00:10:39
Line length.
Jacob
2012/02/02 05:26:38
Done.
| |
142 } | |
143 | |
144 .debug { | |
145 color: #888; | |
146 } | |
147 | |
148 .compatibility, .links, .see-also, .summary, .members, .example { | |
149 border: 1px solid #CCC; | |
150 margin: 5px; | |
151 padding: 5px; | |
152 } | |
153 | |
154 .type, #dart_summary { | |
155 border: 1px solid; | |
156 margin-top: 10px; | |
157 margin-bottom: 10px; | |
158 padding: 10px; | |
159 overflow: hidden; | |
160 background-color: white; | |
161 -moz-box-shadow: 5px 5px 5px #888; | |
162 -webkit-box-shadow: 5px 5px 5px #888; | |
163 box-shadow: 5px 5px 5px #888; | |
164 } | |
165 | |
166 #dart_summary { | |
167 border: 2px solid #00F; | |
168 margin: 5px; | |
169 padding: 5px; | |
170 } | |
171 | |
172 th { | |
173 background-color:#ccc; | |
174 font-weight: bold; | |
175 } | |
176 | |
177 tr:nth-child(odd) { | |
178 background-color:#eee; | |
179 } | |
180 tr:nth-child(even) { | |
181 background-color:#fff; | |
182 } | |
183 | |
184 tr:nth-child(odd).unknown { | |
185 background-color:#dd0; | |
186 } | |
187 tr:nth-child(even).unknown { | |
188 background-color:#ff0; | |
189 } | |
190 | |
191 tr:nth-child(odd).missing { | |
192 background-color:#d88; | |
193 } | |
194 tr:nth-child(even).missing { | |
195 background-color:#faa; | |
196 } | |
197 | |
198 li.unknown { | |
199 color: #f00; | |
200 } | |
201 | |
202 td, th { | |
203 vertical-align: top; | |
204 } | |
205 </style> | |
206 <title>Doc Dump</title> | |
207 </head> | |
208 <body> | |
209 <h1>Doc Dump</h1> | |
210 <ul> | |
211 <li><a href="#dart_summary">Summary</a></li> | |
212 </li> | |
213 """); | |
214 | |
215 for (String type in sortStringCollection(database.getKeys())) { | |
216 Map entry = pickBestEntry(database[type], type); | |
217 filteredDb[type] = entry; | |
218 if (entry == null || entry.containsKey('skipped')) { | |
219 numSkipped++; | |
220 sbSkipped.add(""" | |
221 <li id="$type"> | |
222 <a target="_blank" href="http://www.google.com/cse?cx=01719397256594783026 6%3Awpqsk6dy6ee&ie=UTF-8&q=$type"> | |
223 $type | |
224 </a> -- Title: ${entry == null ? "???" : entry["title"]} -- Issue: ${entry == null ? "???" : entry['cause']} | |
225 -- <a target="_blank" href="${entry == null ? "???" : entry["srcUrl"]}">sc raped url</a> | |
nweiz
2012/02/01 00:10:39
Line lengths.
Jacob
2012/02/02 05:26:38
Done.
| |
226 </li>"""); | |
227 continue; | |
228 } | |
229 matchedTypes.add(type); | |
230 numGen++; | |
231 StringBuffer sbSections = new StringBuffer(); | |
232 StringBuffer sbMembers = new StringBuffer(); | |
233 StringBuffer sbExamples = new StringBuffer(); | |
234 if (entry.containsKey("members")) { | |
235 Map members = getMembersMap(entry); | |
nweiz
2012/02/01 00:10:39
Indentation, here and many other places below
Jacob
2012/02/02 05:26:38
Done.
| |
236 sbMembers.add(""" | |
237 <div class="members"> | |
238 <h3><span class="debug">[dart]</span> Members</h3> | |
239 <table> | |
240 <tbody> | |
241 <tr> | |
242 <th>Name</th><th>Description</th><th>IDL</th><th>Status</th> | |
243 </tr> | |
244 """); | |
245 for (String name in sortStringCollection(members.getKeys())) { | |
246 Map memberData = members[name]; | |
247 bool unknown = !hasAny(type, name); | |
248 StringBuffer classes = new StringBuffer(); | |
249 if (unknown) classes.add("unknown "); | |
250 if (unknown) { | |
251 numExtraMethods++; | |
252 } else { | |
253 numFoundMethods++; | |
254 } | |
255 | |
256 final sbMember = new StringBuffer(); | |
257 | |
258 if (memberData.containsKey('url')) { | |
259 sbMember.add(""" | |
260 <td><a href="${memberData['url']}">$name</a></td> | |
261 """); | |
262 } else { | |
263 sbMember.add(""" | |
264 <td>$name</td> | |
265 """); | |
266 } | |
267 sbMember.add(""" | |
268 <td>${memberData['help']}</td> | |
269 <td> | |
270 <pre>${orEmpty(memberData['idl'])}</pre> | |
271 </td> | |
272 <td>${memberData['obsolete'] == true ? "Obsolete" : ""}</td> | |
273 """); | |
274 if (memberData['obsolete'] == true) { | |
275 sbObsolete.add("<tr class='$classes'><td>$type</td>$sbMember</tr>"); | |
276 } | |
277 sbMembers.add("<tr class='$classes'>$sbMember</tr>"); | |
278 } | |
279 | |
280 numMissingMethods += addMissing(sbMembers, type, members); | |
281 | |
282 sbMembers.add(""" | |
283 </tbody> | |
284 </table> | |
285 </div> | |
286 """); | |
287 } | |
288 for (String sectionName in | |
289 ["summary", "constructor", "compatibility", "specification", "seeAlso"]) | |
nweiz
2012/02/01 00:10:39
Where's the opening { for this loop?
Jacob
2012/02/02 05:26:38
wow... i wish that was a compile warning or at lea
| |
290 if (entry.containsKey(sectionName)) { | |
291 sbSections.add(""" | |
292 <div class="$sectionName"> | |
293 <h3><span class="debug">[Dart]</span> $sectionName</h3> | |
294 ${entry[sectionName]} | |
295 </div> | |
296 """); | |
297 } | |
298 if (entry.containsKey("links")) { | |
299 sbSections.add(""" | |
300 <div class="links"> | |
301 <h3><span class="debug">[Dart]</span> Specification</h3> | |
302 <ul> | |
303 """); | |
304 List links = entry["links"]; | |
305 for (Map link in links) { | |
306 sbSections.add(""" | |
307 <li><a href="${link['href']}">${link['title']}</a></li> | |
308 """); | |
309 } | |
310 sbSections.add(""" | |
311 </ul> | |
312 </div> | |
313 """); | |
314 } | |
315 if (entry.containsKey("examples")) { | |
316 for (String example in entry["examples"]) { | |
317 sbExamples.add(""" | |
318 <div class="example"> | |
319 <h3><span class="debug">[Dart]</span> Example</h3> | |
320 $example | |
321 </div> | |
322 """); | |
323 } | |
324 } | |
325 | |
326 String title = entry['title']; | |
327 if (title != type) { | |
328 title = '<h4>Dart type: $type</h4><h2>${title}</h2>'; | |
nweiz
2012/02/01 00:10:39
Style nit: $title, here and line 330.
Jacob
2012/02/02 05:26:38
Done.
| |
329 } else { | |
330 title = '<h2>${title}</h2>'; | |
331 } | |
332 sb.add(""" | |
333 <div class='type' id="$type"> | |
334 <a href='${entry['srcUrl']}'>$title</a> | |
335 $sbSections | |
336 $sbExamples | |
337 $sbMembers | |
338 </div> | |
339 """); | |
340 if (sbExamples.length > 0) { | |
341 sbAllExamples.add(""" | |
342 <div class='type' id="$type"> | |
343 <a href='${entry['srcUrl']}'>$title</a> | |
344 ${sbExamples.toString()} | |
nweiz
2012/02/01 00:10:39
Style nit: $sbExamples
Jacob
2012/02/02 05:26:38
Done.
| |
345 </div> | |
346 """); | |
347 } | |
348 } | |
349 | |
350 for (String type in sortStringCollection(allProps.getKeys())) { | |
351 if (!matchedTypes.contains(type) && | |
352 !database.containsKey(type)) { | |
353 numSkipped++; | |
354 sbSkipped.add(""" | |
355 <li class="unknown" id="$type"> | |
356 <a target="_blank" href="http://www.google.com/cse?cx=01719397256594783026 6%3Awpqsk6dy6ee&ie=UTF-8&q=$type"> | |
357 $type | |
358 </a> | |
359 </li> | |
360 """); | |
361 } | |
362 } | |
363 | |
364 sb.add(""" | |
365 <div id="#dart_summary"> | |
366 <h2>Summary</h2> | |
367 <h3>Generated docs for ${numGen} classes out of a possible ${allProps.getKeys( ).length}</h3> | |
368 <h3>Found documentation for $numFoundMethods methods listed in WebKit</h3> | |
369 <h3>Found documentation for $numExtraMethods methods not listed in WebKit</h3> | |
370 <h3>Unable to find documentation for $numMissingMethods methods not present in WebKit</h3> | |
371 <h3>Skipped generating documentation for $numSkipped classes due to no plausib le matching files</h3> | |
nweiz
2012/02/01 00:10:39
Line lengths
Jacob
2012/02/02 05:26:38
Done.
| |
372 <ul> | |
373 $sbSkipped | |
374 </ul> | |
375 </div> | |
376 """); | |
377 sb.add(""" | |
378 </body> | |
379 </html> | |
380 """); | |
381 | |
382 fs.writeFileSync("output/database.html", sb.toString()); | |
383 | |
384 fs.writeFileSync("output/examples.html", """ | |
385 <html> | |
386 <head> | |
387 <style type="text/css"> | |
388 body { | |
389 background-color: #eee; | |
390 margin: 10px; | |
391 font: 14px/1.428 "Lucida Grande", "Lucida Sans Unicode", Lucida, Arial, Helvetica, sans-serif; | |
nweiz
2012/02/01 00:10:39
Line length
Jacob
2012/02/02 05:26:38
Done.
| |
392 } | |
393 | |
394 .debug { | |
395 color: #888; | |
396 } | |
397 | |
398 .example { | |
399 border: 1px solid #CCC; | |
400 margin: 5px; | |
401 padding: 5px; | |
402 } | |
403 | |
404 .type { | |
405 border: 1px solid; | |
406 margin-top: 10px; | |
407 margin-bottom: 10px; | |
408 padding: 10px; | |
409 overflow: hidden; | |
410 background-color: white; | |
411 -moz-box-shadow: 5px 5px 5px #888; | |
412 -webkit-box-shadow: 5px 5px 5px #888; | |
413 box-shadow: 5px 5px 5px #888; | |
414 } | |
415 </style> | |
416 <title>All examples</title> | |
417 </head> | |
418 <body> | |
419 <h1>All examples</h1> | |
420 $sbAllExamples | |
421 </body> | |
422 </html> | |
423 """); | |
424 | |
425 fs.writeFileSync("output/obsolete.html", """ | |
426 <html> | |
427 <head> | |
428 <style type="text/css"> | |
429 body { | |
430 background-color: #eee; | |
431 margin: 10px; | |
432 font: 14px/1.428 "Lucida Grande", "Lucida Sans Unicode", Lucida, Arial, Helvetica, sans-serif; | |
nweiz
2012/02/01 00:10:39
Line length
Jacob
2012/02/02 05:26:38
Done.
| |
433 } | |
434 | |
435 .debug { | |
436 color: #888; | |
437 } | |
438 | |
439 .type { | |
440 border: 1px solid; | |
441 margin-top: 10px; | |
442 margin-bottom: 10px; | |
443 padding: 10px; | |
444 overflow: hidden; | |
445 background-color: white; | |
446 -moz-box-shadow: 5px 5px 5px #888; | |
447 -webkit-box-shadow: 5px 5px 5px #888; | |
448 box-shadow: 5px 5px 5px #888; | |
449 } | |
450 </style> | |
451 <title>Methods marked as obsolete</title> | |
452 </head> | |
453 <body> | |
454 <h1>Methods marked as obsolete</h1> | |
455 <table> | |
nweiz
2012/02/01 00:10:39
Indentation
Jacob
2012/02/02 05:26:38
Done.
| |
456 <tbody> | |
457 <tr> | |
458 <th>Type</th><th>Name</th><th>Description</th><th>IDL</th><th>St atus</th> | |
nweiz
2012/02/01 00:10:39
Line length
Jacob
2012/02/02 05:26:38
Done.
| |
459 </tr> | |
460 $sbObsolete | |
461 </tbody> | |
462 </table> | |
463 </body> | |
464 </html> | |
465 """); | |
466 | |
467 fs.writeFileSync("output/database.filtered.json", JSON.stringify(filteredDb)); | |
468 } | |
OLD | NEW |