OLD | NEW |
(Empty) | |
| 1 #library("dump"); |
| 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; |
| 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. */ |
| 16 bool hasAny(String type, String prop) { |
| 17 Map data = allProps[type]; |
| 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) { |
| 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) { |
| 32 List rawMembers = entry["members"]; |
| 33 Map members = new Map<String, Object>(); |
| 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) { |
| 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(""" |
| 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 |
| 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. |
| 77 */ |
| 78 num scoreEntry(Map entry, String type) { |
| 79 num score = 0; |
| 80 if (!entry.containsKey('skipped')) { |
| 81 score++; |
| 82 } |
| 83 if (entry.containsKey("members")) { |
| 84 Map members = getMembersMap(entry); |
| 85 for (String name in members.getKeys()) { |
| 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); |
| 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(); |
| 133 |
| 134 sb.add(""" |
| 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; |
| 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> |
| 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); |
| 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"]) |
| 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>'; |
| 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()} |
| 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> |
| 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; |
| 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; |
| 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> |
| 456 <tbody> |
| 457 <tr> |
| 458 <th>Type</th><th>Name</th><th>Description</th><th>IDL</th><th>St
atus</th> |
| 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 |