| Index: utils/apidoc/mdn/postProcess.dart
|
| diff --git a/utils/apidoc/mdn/postProcess.dart b/utils/apidoc/mdn/postProcess.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fb365a9547ef64278076faaa93c37486de95a62c
|
| --- /dev/null
|
| +++ b/utils/apidoc/mdn/postProcess.dart
|
| @@ -0,0 +1,468 @@
|
| +#library("dump");
|
| +
|
| +#import("../../../frog/lib/node/node.dart");
|
| +#import('../../../frog/lib/node/fs.dart');
|
| +#import("dart:json");
|
| +
|
| +Map database;
|
| +Map allProps;
|
| +Set matchedTypes;
|
| +
|
| +String orEmpty(String str) {
|
| + return str == null ? "" : str;
|
| +}
|
| +
|
| +/** Returns whether the type has any property matching the specified name. */
|
| +bool hasAny(String type, String prop) {
|
| + Map data = allProps[type];
|
| + return data['properties'].containsKey(prop) ||
|
| + data['methods'].containsKey(prop) ||
|
| + data['constants'].containsKey(prop);
|
| +}
|
| +
|
| +List<String> sortStringCollection(Collection<String> collection) {
|
| + List<String> out = new List<String>();
|
| + out.addAll(collection);
|
| + out.sort((String a, String b) => a.compareTo(b));
|
| + return out;
|
| +}
|
| +
|
| +/** Switch from a List of members to a Map of members. */
|
| +Map getMembersMap(Map entry) {
|
| + List rawMembers = entry["members"];
|
| + Map members = new Map<String, Object>();
|
| + for (Map entry in rawMembers) {
|
| + members[entry['name']] = entry;
|
| + }
|
| + return members;
|
| +}
|
| +
|
| +/**
|
| + * Add all missing members to the string output and return the number of
|
| + * missing members.
|
| + */
|
| +int addMissingHelper(StringBuffer sb, String type, Map members,
|
| + String propType) {
|
| + int total = 0;
|
| + Map expected = allProps[type][propType];
|
| + if (expected == null) return total;
|
| + for(String name in sortStringCollection(expected.getKeys())) {
|
| + if (!members.containsKey(name)) {
|
| + total++;
|
| + sb.add("""
|
| + <tr class="missing">
|
| + <td>$name</td>
|
| + <td></td>
|
| + <td>Could not find documentation for $propType</td>
|
| + </tr>
|
| +""");
|
| + }
|
| + }
|
| + return total;
|
| +}
|
| +
|
| +int addMissing(StringBuffer sb, String type, Map members) {
|
| + int total = 0;
|
| + total += addMissingHelper(sb, type, members, 'properties');
|
| + total += addMissingHelper(sb, type, members, 'methods');
|
| + total += addMissingHelper(sb, type, members, 'constants');
|
| + return total;
|
| +}
|
| +
|
| +/**
|
| + * Score an entry using heuristics to determine how well a entry
|
| + * matches the expected list of matching members.
|
| + * We could be much less naive and penalize spurious methods, prefer entries
|
| + * with class level comments, etc.
|
| + */
|
| +num scoreEntry(Map entry, String type) {
|
| + num score = 0;
|
| + if (!entry.containsKey('skipped')) {
|
| + score++;
|
| + }
|
| + if (entry.containsKey("members")) {
|
| + Map members = getMembersMap(entry);
|
| + for (String name in members.getKeys()) {
|
| + if (hasAny(type, name)) {
|
| + score++;
|
| + }
|
| + }
|
| + }
|
| + return score;
|
| +}
|
| +
|
| +/**
|
| + * Given a list of candidates for the documentation for a type, find the one
|
| + * that is the best.
|
| + */
|
| +Map pickBestEntry(List entries, String type) {
|
| + num bestScore = -1;
|
| + Map bestEntry;
|
| + for (Map entry in entries) {
|
| + if (entry != null) {
|
| + num score = scoreEntry(entry, type);
|
| + if (score > bestScore) {
|
| + bestScore = score;
|
| + bestEntry = entry;
|
| + }
|
| + }
|
| + }
|
| + return bestEntry;
|
| +}
|
| +
|
| +void main() {
|
| + // Database of code documentation.
|
| + database = JSON.parse(fs.readFileSync('output/database.json', 'utf8'));
|
| + // Database of expected property names for each type in WebKit.
|
| + allProps = JSON.parse(fs.readFileSync('data/dartIdl.json', 'utf8'));
|
| + // Types we have documentation for.
|
| + matchedTypes = new Set<String>();
|
| + int numMissingMethods = 0;
|
| + int numFoundMethods = 0;
|
| + int numExtraMethods = 0;
|
| + int numGen = 0;
|
| + int numSkipped = 0;
|
| + final sbSkipped = new StringBuffer();
|
| + final sbAllExamples = new StringBuffer();
|
| + final filteredDb = {};
|
| +
|
| + // Table rows for all obsolete members.
|
| + final sbObsolete = new StringBuffer();
|
| + // Main documentation file.
|
| + final sb = new StringBuffer();
|
| +
|
| + sb.add("""
|
| +<html>
|
| + <head>
|
| + <style type="text/css">
|
| + body {
|
| + background-color: #eee;
|
| + margin: 10px;
|
| + font: 14px/1.428 "Lucida Grande", "Lucida Sans Unicode", Lucida, Arial, Helvetica, sans-serif;
|
| + }
|
| +
|
| + .debug {
|
| + color: #888;
|
| + }
|
| +
|
| + .compatibility, .links, .see-also, .summary, .members, .example {
|
| + border: 1px solid #CCC;
|
| + margin: 5px;
|
| + padding: 5px;
|
| + }
|
| +
|
| + .type, #dart_summary {
|
| + border: 1px solid;
|
| + margin-top: 10px;
|
| + margin-bottom: 10px;
|
| + padding: 10px;
|
| + overflow: hidden;
|
| + background-color: white;
|
| + -moz-box-shadow: 5px 5px 5px #888;
|
| + -webkit-box-shadow: 5px 5px 5px #888;
|
| + box-shadow: 5px 5px 5px #888;
|
| + }
|
| +
|
| + #dart_summary {
|
| + border: 2px solid #00F;
|
| + margin: 5px;
|
| + padding: 5px;
|
| + }
|
| +
|
| + th {
|
| + background-color:#ccc;
|
| + font-weight: bold;
|
| + }
|
| +
|
| + tr:nth-child(odd) {
|
| + background-color:#eee;
|
| + }
|
| + tr:nth-child(even) {
|
| + background-color:#fff;
|
| + }
|
| +
|
| + tr:nth-child(odd).unknown {
|
| + background-color:#dd0;
|
| + }
|
| + tr:nth-child(even).unknown {
|
| + background-color:#ff0;
|
| + }
|
| +
|
| + tr:nth-child(odd).missing {
|
| + background-color:#d88;
|
| + }
|
| + tr:nth-child(even).missing {
|
| + background-color:#faa;
|
| + }
|
| +
|
| + li.unknown {
|
| + color: #f00;
|
| + }
|
| +
|
| + td, th {
|
| + vertical-align: top;
|
| + }
|
| + </style>
|
| + <title>Doc Dump</title>
|
| + </head>
|
| + <body>
|
| + <h1>Doc Dump</h1>
|
| + <ul>
|
| + <li><a href="#dart_summary">Summary</a></li>
|
| + </li>
|
| +""");
|
| +
|
| + for (String type in sortStringCollection(database.getKeys())) {
|
| + Map entry = pickBestEntry(database[type], type);
|
| + filteredDb[type] = entry;
|
| + if (entry == null || entry.containsKey('skipped')) {
|
| + numSkipped++;
|
| + sbSkipped.add("""
|
| + <li id="$type">
|
| + <a target="_blank" href="http://www.google.com/cse?cx=017193972565947830266%3Awpqsk6dy6ee&ie=UTF-8&q=$type">
|
| + $type
|
| + </a> -- Title: ${entry == null ? "???" : entry["title"]} -- Issue: ${entry == null ? "???" : entry['cause']}
|
| + -- <a target="_blank" href="${entry == null ? "???" : entry["srcUrl"]}">scraped url</a>
|
| + </li>""");
|
| + continue;
|
| + }
|
| + matchedTypes.add(type);
|
| + numGen++;
|
| + StringBuffer sbSections = new StringBuffer();
|
| + StringBuffer sbMembers = new StringBuffer();
|
| + StringBuffer sbExamples = new StringBuffer();
|
| + if (entry.containsKey("members")) {
|
| + Map members = getMembersMap(entry);
|
| + sbMembers.add("""
|
| + <div class="members">
|
| + <h3><span class="debug">[dart]</span> Members</h3>
|
| + <table>
|
| + <tbody>
|
| + <tr>
|
| + <th>Name</th><th>Description</th><th>IDL</th><th>Status</th>
|
| + </tr>
|
| +""");
|
| + for (String name in sortStringCollection(members.getKeys())) {
|
| + Map memberData = members[name];
|
| + bool unknown = !hasAny(type, name);
|
| + StringBuffer classes = new StringBuffer();
|
| + if (unknown) classes.add("unknown ");
|
| + if (unknown) {
|
| + numExtraMethods++;
|
| + } else {
|
| + numFoundMethods++;
|
| + }
|
| +
|
| + final sbMember = new StringBuffer();
|
| +
|
| + if (memberData.containsKey('url')) {
|
| + sbMember.add("""
|
| + <td><a href="${memberData['url']}">$name</a></td>
|
| +""");
|
| + } else {
|
| + sbMember.add("""
|
| + <td>$name</td>
|
| +""");
|
| + }
|
| + sbMember.add("""
|
| + <td>${memberData['help']}</td>
|
| + <td>
|
| + <pre>${orEmpty(memberData['idl'])}</pre>
|
| + </td>
|
| + <td>${memberData['obsolete'] == true ? "Obsolete" : ""}</td>
|
| +""");
|
| + if (memberData['obsolete'] == true) {
|
| + sbObsolete.add("<tr class='$classes'><td>$type</td>$sbMember</tr>");
|
| + }
|
| + sbMembers.add("<tr class='$classes'>$sbMember</tr>");
|
| + }
|
| +
|
| + numMissingMethods += addMissing(sbMembers, type, members);
|
| +
|
| + sbMembers.add("""
|
| + </tbody>
|
| + </table>
|
| + </div>
|
| +""");
|
| + }
|
| + for (String sectionName in
|
| + ["summary", "constructor", "compatibility", "specification", "seeAlso"])
|
| + if (entry.containsKey(sectionName)) {
|
| + sbSections.add("""
|
| + <div class="$sectionName">
|
| + <h3><span class="debug">[Dart]</span> $sectionName</h3>
|
| + ${entry[sectionName]}
|
| + </div>
|
| +""");
|
| + }
|
| + if (entry.containsKey("links")) {
|
| + sbSections.add("""
|
| + <div class="links">
|
| + <h3><span class="debug">[Dart]</span> Specification</h3>
|
| + <ul>
|
| +""");
|
| + List links = entry["links"];
|
| + for (Map link in links) {
|
| + sbSections.add("""
|
| + <li><a href="${link['href']}">${link['title']}</a></li>
|
| +""");
|
| + }
|
| + sbSections.add("""
|
| + </ul>
|
| + </div>
|
| +""");
|
| + }
|
| + if (entry.containsKey("examples")) {
|
| + for (String example in entry["examples"]) {
|
| + sbExamples.add("""
|
| + <div class="example">
|
| + <h3><span class="debug">[Dart]</span> Example</h3>
|
| + $example
|
| + </div>
|
| +""");
|
| + }
|
| + }
|
| +
|
| + String title = entry['title'];
|
| + if (title != type) {
|
| + title = '<h4>Dart type: $type</h4><h2>${title}</h2>';
|
| + } else {
|
| + title = '<h2>${title}</h2>';
|
| + }
|
| + sb.add("""
|
| + <div class='type' id="$type">
|
| + <a href='${entry['srcUrl']}'>$title</a>
|
| +$sbSections
|
| +$sbExamples
|
| +$sbMembers
|
| + </div>
|
| +""");
|
| + if (sbExamples.length > 0) {
|
| + sbAllExamples.add("""
|
| + <div class='type' id="$type">
|
| + <a href='${entry['srcUrl']}'>$title</a>
|
| + ${sbExamples.toString()}
|
| + </div>
|
| +""");
|
| + }
|
| + }
|
| +
|
| + for (String type in sortStringCollection(allProps.getKeys())) {
|
| + if (!matchedTypes.contains(type) &&
|
| + !database.containsKey(type)) {
|
| + numSkipped++;
|
| + sbSkipped.add("""
|
| + <li class="unknown" id="$type">
|
| + <a target="_blank" href="http://www.google.com/cse?cx=017193972565947830266%3Awpqsk6dy6ee&ie=UTF-8&q=$type">
|
| + $type
|
| + </a>
|
| + </li>
|
| +""");
|
| + }
|
| + }
|
| +
|
| + sb.add("""
|
| +<div id="#dart_summary">
|
| + <h2>Summary</h2>
|
| + <h3>Generated docs for ${numGen} classes out of a possible ${allProps.getKeys().length}</h3>
|
| + <h3>Found documentation for $numFoundMethods methods listed in WebKit</h3>
|
| + <h3>Found documentation for $numExtraMethods methods not listed in WebKit</h3>
|
| + <h3>Unable to find documentation for $numMissingMethods methods not present in WebKit</h3>
|
| + <h3>Skipped generating documentation for $numSkipped classes due to no plausible matching files</h3>
|
| + <ul>
|
| +$sbSkipped
|
| + </ul>
|
| +</div>
|
| +""");
|
| + sb.add("""
|
| + </body>
|
| +</html>
|
| +""");
|
| +
|
| + fs.writeFileSync("output/database.html", sb.toString());
|
| +
|
| + fs.writeFileSync("output/examples.html", """
|
| +<html>
|
| + <head>
|
| + <style type="text/css">
|
| + body {
|
| + background-color: #eee;
|
| + margin: 10px;
|
| + font: 14px/1.428 "Lucida Grande", "Lucida Sans Unicode", Lucida, Arial, Helvetica, sans-serif;
|
| + }
|
| +
|
| + .debug {
|
| + color: #888;
|
| + }
|
| +
|
| + .example {
|
| + border: 1px solid #CCC;
|
| + margin: 5px;
|
| + padding: 5px;
|
| + }
|
| +
|
| + .type {
|
| + border: 1px solid;
|
| + margin-top: 10px;
|
| + margin-bottom: 10px;
|
| + padding: 10px;
|
| + overflow: hidden;
|
| + background-color: white;
|
| + -moz-box-shadow: 5px 5px 5px #888;
|
| + -webkit-box-shadow: 5px 5px 5px #888;
|
| + box-shadow: 5px 5px 5px #888;
|
| + }
|
| + </style>
|
| + <title>All examples</title>
|
| + </head>
|
| + <body>
|
| + <h1>All examples</h1>
|
| +$sbAllExamples
|
| + </body>
|
| + </html>
|
| +""");
|
| +
|
| + fs.writeFileSync("output/obsolete.html", """
|
| +<html>
|
| + <head>
|
| + <style type="text/css">
|
| + body {
|
| + background-color: #eee;
|
| + margin: 10px;
|
| + font: 14px/1.428 "Lucida Grande", "Lucida Sans Unicode", Lucida, Arial, Helvetica, sans-serif;
|
| + }
|
| +
|
| + .debug {
|
| + color: #888;
|
| + }
|
| +
|
| + .type {
|
| + border: 1px solid;
|
| + margin-top: 10px;
|
| + margin-bottom: 10px;
|
| + padding: 10px;
|
| + overflow: hidden;
|
| + background-color: white;
|
| + -moz-box-shadow: 5px 5px 5px #888;
|
| + -webkit-box-shadow: 5px 5px 5px #888;
|
| + box-shadow: 5px 5px 5px #888;
|
| + }
|
| + </style>
|
| + <title>Methods marked as obsolete</title>
|
| + </head>
|
| + <body>
|
| + <h1>Methods marked as obsolete</h1>
|
| + <table>
|
| + <tbody>
|
| + <tr>
|
| + <th>Type</th><th>Name</th><th>Description</th><th>IDL</th><th>Status</th>
|
| + </tr>
|
| +$sbObsolete
|
| + </tbody>
|
| + </table>
|
| + </body>
|
| + </html>
|
| + """);
|
| +
|
| + fs.writeFileSync("output/database.filtered.json", JSON.stringify(filteredDb));
|
| +}
|
|
|