Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: utils/apidoc/apidoc.dart

Issue 9225039: Integrate MDN content into API documentation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Respond to review. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/apidoc/apidoc ('k') | utils/apidoc/mdn/README.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 * Generates the complete set of corelib reference documentation. 6 * Generates the complete set of corelib reference documentation.
7 */ 7 */
8 #library('apidoc'); 8 #library('apidoc');
9 9
10 #import('dart:json');
10 #import('html_diff.dart'); 11 #import('html_diff.dart');
11 #import('../../frog/lang.dart'); 12 #import('../../frog/lang.dart');
12 #import('../../frog/file_system_node.dart'); 13 #import('../../frog/file_system_node.dart');
13 #import('../../frog/file_system.dart'); 14 #import('../../frog/file_system.dart');
14 #import('../dartdoc/dartdoc.dart', prefix: 'doc'); 15 #import('../dartdoc/dartdoc.dart', prefix: 'doc');
15 16
16 HtmlDiff _diff; 17 HtmlDiff _diff;
17 18
18 void main() { 19 void main() {
19 var files = new NodeFileSystem(); 20 var files = new NodeFileSystem();
20 parseOptions('../../frog', [] /* args */, files); 21 parseOptions('../../frog', [] /* args */, files);
21 initializeWorld(files); 22 initializeWorld(files);
22 final apidoc = new Apidoc();
23 23
24 print('Parsing MDN data...');
25 final mdn = JSON.parse(files.readAll('mdn/database.json'));
26
27 print('Cross-referencing dart:dom and dart:html...');
24 HtmlDiff.initialize(); 28 HtmlDiff.initialize();
25
26 _diff = new HtmlDiff(); 29 _diff = new HtmlDiff();
27 _diff.run(); 30 _diff.run();
28 world.reset(); 31 world.reset();
29 32
33 print('Generating docs...');
34 final apidoc = new Apidoc(mdn);
30 apidoc.document('html'); 35 apidoc.document('html');
31 } 36 }
32 37
33 class Apidoc extends doc.Dartdoc { 38 class Apidoc extends doc.Dartdoc {
34 Apidoc() { 39 /** Big ball of JSON containing the scraped MDN documentation. */
40 final Map mdn;
41
42 /**
43 * The URL to the page on MDN that content was pulled from for the current
44 * type being documented. Will be `null` if the type doesn't use any MDN
45 * content.
46 */
47 String mdnUrl;
48
49 Apidoc(this.mdn) {
35 mainTitle = 'Dart API Reference'; 50 mainTitle = 'Dart API Reference';
36 mainUrl = 'http://dartlang.org'; 51 mainUrl = 'http://dartlang.org';
37 52
38 final note = 'http://code.google.com/policies.html#restrictions'; 53 final note = 'http://code.google.com/policies.html#restrictions';
39 final cca = 'http://creativecommons.org/licenses/by/3.0/'; 54 final cca = 'http://creativecommons.org/licenses/by/3.0/';
40 final bsd = 'http://code.google.com/google_bsd_license.html'; 55 final bsd = 'http://code.google.com/google_bsd_license.html';
41 final tos = 'http://www.dartlang.org/tos.html'; 56 final tos = 'http://www.dartlang.org/tos.html';
42 final privacy = 'http://www.google.com/intl/en/privacy/privacy-policy.html'; 57 final privacy = 'http://www.google.com/intl/en/privacy/privacy-policy.html';
43 58
44 footerText = 59 footerText =
45 ''' 60 '''
46 <p>Except as otherwise <a href="$note">noted</a>, the content of this 61 <p>Except as otherwise <a href="$note">noted</a>, the content of this
47 page is licensed under the <a href="$cca">Creative Commons Attribution 62 page is licensed under the <a href="$cca">Creative Commons Attribution
48 3.0 License</a>, and code samples are licensed under the 63 3.0 License</a>, and code samples are licensed under the
49 <a href="$bsd">BSD License</a>.</p> 64 <a href="$bsd">BSD License</a>.</p>
50 <p><a href="$tos">Terms of Service</a> | 65 <p><a href="$tos">Terms of Service</a> |
51 <a href="$privacy">Privacy Policy</a></p> 66 <a href="$privacy">Privacy Policy</a></p>
52 '''; 67 ''';
53 } 68 }
54 69
55 void writeHeadContents(String title) { 70 void writeHeadContents(String title) {
56 super.writeHeadContents(title); 71 super.writeHeadContents(title);
57 72
73 // Include the apidoc-specific CSS.
74 // TODO(rnystrom): Use our CSS pre-processor to combine these.
75 writeln(
76 '''
77 <link rel="stylesheet" type="text/css"
78 href="${relativePath('apidoc-styles.css')}" />
79 ''');
80
58 // Add the analytics code. 81 // Add the analytics code.
59 doc.writeln( 82 writeln(
60 ''' 83 '''
61 <script type="text/javascript"> 84 <script type="text/javascript">
62 var _gaq = _gaq || []; 85 var _gaq = _gaq || [];
63 _gaq.push(['_setAccount', 'UA-26406144-4']); 86 _gaq.push(["_setAccount", "UA-26406144-4"]);
64 _gaq.push(['_setDomainName', 'dartlang.org']); 87 _gaq.push(["_setDomainName", "dartlang.org"]);
65 _gaq.push(['_trackPageview']); 88 _gaq.push(["_trackPageview"]);
66 89
67 (function() { 90 (function() {
68 var ga = document.createElement('script'); ga.type = 'text/javascrip t'; ga.async = true; 91 var ga = document.createElement("script");
69 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : ' http://www') + '.google-analytics.com/ga.js'; 92 ga.type = "text/javascript"; ga.async = true;
70 var s = document.getElementsByTagName('script')[0]; s.parentNode.ins ertBefore(ga, s); 93 ga.src = ("https:" == document.location.protocol ?
94 "https://ssl" : "http://www") + ".google-analytics.com/ga.js";
95 var s = document.getElementsByTagName("script")[0];
96 s.parentNode.insertBefore(ga, s);
71 })(); 97 })();
72 </script> 98 </script>
73 '''); 99 ''');
74 } 100 }
75 101
76 getTypeComment(Type type) { 102 String getTypeComment(Type type) {
77 return _mergeComments(super.getTypeComment(type), getTypeDoc(type)); 103 return _mergeDocs(
78 } 104 includeMdnTypeComment(type),
79 105 super.getTypeComment(type),
80 getMethodComment(MethodMember method) { 106 getTypeDoc(type));
81 return _mergeComments(super.getMethodComment(method), getMemberDoc(method)); 107 }
82 } 108
83 109 String getMethodComment(MethodMember method) {
84 getFieldComment(FieldMember field) { 110 // TODO(rnystrom): Disabling cross-linking between individual members.
85 return _mergeComments(super.getFieldComment(field), getMemberDoc(field)); 111 // Now that we include MDN content for most members, it doesn't add much
86 } 112 // value and adds a lot of clutter. Once we're sure we want to do this,
87 113 // we can delete this code entirely.
88 String _mergeComments(String comment, String extra) { 114 return _mergeDocs(
89 if (comment == null) return extra; 115 includeMdnMemberComment(method),
90 return '$comment\n\n$extra'; 116 super.getMethodComment(method),
117 /* getMemberDoc(method) */ null);
118 }
119
120 String getFieldComment(FieldMember field) {
121 // TODO(rnystrom): Disabling cross-linking between individual members.
122 // Now that we include MDN content for most members, it doesn't add much
123 // value and adds a lot of clutter. Once we're sure we want to do this,
124 // we can delete this code entirely.
125 return _mergeDocs(
126 includeMdnMemberComment(field),
127 super.getFieldComment(field),
128 /* getMemberDoc(field) */ null);
129 }
130
131 bool isNonEmpty(String string) => (string != null) && (string.trim() != '');
132
133 String _mergeDocs(String mdnComment, String dartComment, String diffComment) {
134 // Prefer hand-written Dart comments over stuff from MDN.
135 if (isNonEmpty(dartComment)) {
136 // Also include the diff comment if provided.
137 if (isNonEmpty(diffComment)) return dartComment + diffComment;
138 return dartComment;
139 } else if (isNonEmpty(mdnComment)) {
140 // Wrap it so we can highlight it and so we handle MDN scraped content
141 // that lacks a top-level block tag.
142 mdnComment =
143 '''
144 <div class="mdn">
145 $mdnComment
146 <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
147 </div>
148 ''';
149
150 // Also include the diff comment if provided.
151 if (isNonEmpty(diffComment)) return mdnComment + diffComment;
152 return mdnComment;
153 } else if (isNonEmpty(diffComment)) {
154 // All we have is the diff comment.
155 return diffComment;
156 } else {
157 // We got nothing!
158 return '';
159 }
160 }
161
162 void docType(Type type) {
163 // Track whether we've inserted MDN content into this page.
164 mdnUrl = null;
165
166 super.docType(type);
167 }
168
169 void writeTypeFooter() {
170 if (mdnUrl != null) {
171 final MOZ = 'http://www.mozilla.org/';
172 final MDN = 'https://developer.mozilla.org';
173 final CCA = 'http://creativecommons.org/licenses/by-sa/2.5/';
174 final CONTRIB = 'https://developer.mozilla.org/Project:en/How_to_Help';
175 writeln(
176 '''
177 <p class="mdn-attribution">
178 <a href="$MDN">
179 <img src="${relativePath('mdn-logo-tiny.png')}" class="mdn-logo" />
180 </a>
181 This page includes <a href="$mdnUrl">content</a> from the
182 <a href="$MOZ">Mozilla Foundation</a> that is graciously
183 <a href="$MDN/Project:Copyrights">licensed</a> under a
184 <a href="$CCA">Creative Commons: Attribution-Sharealike license</a>.
185 Mozilla has no other association with Dart or dartlang.org. We
186 encourage you to improve the web by
187 <a href="$CONTRIB">contributing</a> to
188 <a href="$MDN">The Mozilla Developer Network</a>.
189 </p>
190 ''');
191 }
192 }
193
194 /**
195 * Gets the MDN-scraped docs for [type], or `null` if this type isn't
196 * scraped from MDN.
197 */
198 includeMdnTypeComment(Type type) {
199 if (type.library.name == 'html') {
200 // If it's an HTML type, try to map it to a base DOM type so we can find
201 // the MDN docs.
202 final domTypes = _diff.htmlTypesToDom[type];
203
204 // Couldn't find a DOM type.
205 if ((domTypes == null) || (domTypes.length != 1)) return null;
206
207 // Use the corresponding DOM type when searching MDN.
208 // TODO(rnystrom): Shame there isn't a simpler way to get the one item
209 // out of a singleton Set.
210 type = domTypes.iterator().next();
211 } else if (type.library.name != 'dom') {
212 // Not a DOM type.
213 return null;
214 }
215
216 final mdnType = mdn[type.name];
217 if (mdnType == null) return null;
218 if (mdnType['skipped'] != null) return null;
219
220 // Remember which MDN page we're using so we can attribute it.
221 mdnUrl = mdnType['srcUrl'];
222 return mdnType['summary'];
223 }
224
225 /**
226 * Gets the MDN-scraped docs for [member], or `null` if this type isn't
227 * scraped from MDN.
228 */
229 includeMdnMemberComment(Member member) {
230 if (member.library.name == 'html') {
231 // If it's an HTML type, try to map it to a base DOM type so we can find
232 // the MDN docs.
233 final domMembers = _diff.htmlToDom[member];
234
235 // Couldn't find a DOM type.
236 if ((domMembers == null) || (domMembers.length != 1)) return null;
237
238 // Use the corresponding DOM member when searching MDN.
239 // TODO(rnystrom): Shame there isn't a simpler way to get the one item
240 // out of a singleton Set.
241 member = domMembers.iterator().next();
242 } else if (member.library.name != 'dom') {
243 // Not a DOM type.
244 return null;
245 }
246
247 // Ignore top-level functions.
248 if (member.declaringType.isTop) return null;
249
250 final mdnType = mdn[member.declaringType.name];
251 if (mdnType == null) return null;
252
253 var mdnMember = null;
254 for (final thisMember in mdnType['members']) {
255 if (thisMember['name'] == member.name) {
256 mdnMember = thisMember;
257 break;
258 }
259 }
260
261 if (mdnMember == null) return null;
262
263 // Remember which MDN page we're using so we can attribute it.
264 mdnUrl = mdnType['srcUrl'];
265 return mdnMember['help'];
266 }
267
268 /**
269 * Returns a link to [member], relative to a type page that may be in a
270 * different library than [member].
271 */
272 String _linkMember(Member member) {
273 final GET_PREFIX = 'get:';
274
275 final typeName = member.declaringType.name;
276 var memberName = '$typeName.${member.name}';
277 if (member.isConstructor || member.isFactory) {
278 final separator = member.constructorName == '' ? '' : '.';
279 memberName = 'new $typeName$separator${member.constructorName}';
280 } else if (member.name.startsWith(GET_PREFIX)) {
281 memberName = '$typeName.${member.name.substring(GET_PREFIX.length)}';
282 }
283
284 return a(memberUrl(member), memberName);
285 }
286
287 /**
288 * Unify getters and setters of the same property. We only want to print
289 * explicit setters if no getter exists.
290 *
291 * If [members] contains no setters, returns it unmodified.
292 */
293 Set<Member> _unifyProperties(Set<Member> members) {
294 // Only print setters if the getter doesn't exist.
295 return members.filter((m) {
296 if (!m.name.startsWith('set:')) return true;
297 var getName = m.name.replaceFirst('set:', 'get:');
298 return !members.some((maybeGet) => maybeGet.name == getName);
299 });
300 }
301
302 /**
303 * Returns additional documentation for [member], linking it to the
304 * corresponding `dart:html` or `dart:dom` [Member](s). If [member] is not in
305 * `dart:html` or `dart:dom`, returns no additional documentation.
306 */
307 String getMemberDoc(Member member) {
308 if (_diff.domToHtml.containsKey(member)) {
309 final htmlMemberSet = _unifyProperties(_diff.domToHtml[member]);
310 final allSameName = htmlMemberSet.every((m) => _diff.sameName(member, m));
311 final phrase = allSameName ? 'available as' : 'renamed to';
312 final htmlMembers = doc.joinWithCommas(map(htmlMemberSet, _linkMember));
313 return
314 '''<p class="correspond">This is $phrase $htmlMembers in the
315 ${a("html.html", "dart:html")} library.</p>
316 ''';
317 } else if (_diff.htmlToDom.containsKey(member)) {
318 final domMemberSet = _unifyProperties(_diff.htmlToDom[member]);
319 final allSameName = domMemberSet.every((m) => _diff.sameName(m, member));
320 final phrase = allSameName ? 'is the same as' : 'renames';
321 final domMembers = doc.joinWithCommas(map(domMemberSet, _linkMember));
322 return
323 '''
324 <p class="correspond">This $phrase $domMembers in the
325 ${a("dom.html", "dart:dom")} library.</p>
326 ''';
327 } else {
328 return '';
329 }
330 }
331
332 /**
333 * Returns additional Markdown-formatted documentation for [type], linking it
334 * to the corresponding `dart:html` or `dart:dom` [Type](s). If [type] is not
335 * in `dart:html` or `dart:dom`, returns no additional documentation.
336 */
337 String getTypeDoc(Type type) {
338 final htmlTypes = _diff.domTypesToHtml[type];
339 if ((htmlTypes != null) && (htmlTypes.length > 0)) {
340 var htmlTypesText = doc.joinWithCommas(map(htmlTypes, typeReference));
341 return
342 '''
343 <p class="correspond">This corresponds to $htmlTypesText in the
344 ${a("html.html", "dart:html")} library.</p>
345 ''';
346 }
347
348 final domTypes = _diff.htmlTypesToDom[type];
349 if ((domTypes != null) && (domTypes.length > 0)) {
350 var domTypesText = doc.joinWithCommas(map(domTypes, typeReference));
351 return
352 '''
353 <p class="correspond">This corresponds to $domTypesText in the
354 ${a("dom.html", "dart:dom")} library.</p>
355 ''';
356 }
357
358 return '';
91 } 359 }
92 } 360 }
93
94 /**
95 * Returns a Markdown-formatted link to [member], relative to a type page that
96 * may be in a different library than [member].
97 */
98 String _linkMember(Member member) {
99 final typeName = member.declaringType.name;
100 var memberName = "$typeName.${member.name}";
101 if (member.isConstructor || member.isFactory) {
102 final separator = member.constructorName == '' ? '' : '.';
103 memberName = 'new $typeName$separator${member.constructorName}';
104 } else if (member.name.startsWith('get:')) {
105 memberName = "$typeName.${member.name.substring(4)}";
106 }
107
108 return "[$memberName](../${doc.memberUrl(member)})";
109 }
110
111 /**
112 * Returns a Markdown-formatted link to [type], relative to a type page that
113 * may be in a different library than [type].
114 */
115 String _linkType(Type type) => "[${type.name}](../${doc.typeUrl(type)})";
116
117 /**
118 * Unify getters and setters of the same property. We only want to print
119 * explicit setters if no getter exists.
120 *
121 * If [members] contains no setters, returns it unmodified.
122 */
123 Set<Member> _unifyProperties(Set<Member> members) {
124 // Only print setters if the getter doesn't exist.
125 return members.filter((m) {
126 if (!m.name.startsWith('set:')) return true;
127 var getName = m.name.replaceFirst('set:', 'get:');
128 return !members.some((maybeGet) => maybeGet.name == getName);
129 });
130 }
131
132 /**
133 * Returns additional Markdown-formatted documentation for [member], linking it
134 * to the corresponding `dart:html` or `dart:dom` [Member](s). If [member] is
135 * not in `dart:html` or `dart:dom`, returns no additional documentation.
136 */
137 String getMemberDoc(Member member) {
138 if (_diff.domToHtml.containsKey(member)) {
139 final htmlMemberSet = _unifyProperties(_diff.domToHtml[member]);
140 final allSameName = htmlMemberSet.every((m) => _diff.sameName(member, m));
141 final phrase = allSameName ? "available as" : "renamed to";
142 final htmlMembers = doc.joinWithCommas(map(htmlMemberSet, _linkMember));
143 return "_This is $phrase $htmlMembers in the " +
144 "[dart:html](../html.html) library._";
145 } else if (_diff.htmlToDom.containsKey(member)) {
146 final domMemberSet = _unifyProperties(_diff.htmlToDom[member]);
147 final allSameName = domMemberSet.every((m) => _diff.sameName(m, member));
148 final phrase = allSameName ? "is the same as" : "renames";
149 final domMembers = doc.joinWithCommas(map(domMemberSet, _linkMember));
150 return "_This $phrase $domMembers in the [dart:dom](../dom.html) " +
151 "library._";
152 } else {
153 return "";
154 }
155 }
156
157 /**
158 * Returns additional Markdown-formatted documentation for [type], linking it to
159 * the corresponding `dart:html` or `dart:dom` [Type](s). If [type] is not in
160 * `dart:html` or `dart:dom`, returns no additional documentation.
161 */
162 String getTypeDoc(Type type) {
163 var types = _diff.domTypesToHtml[type];
164 if (types != null && types.length > 0) {
165 final text = doc.joinWithCommas(map(types, _linkType));
166 return '_This corresponds to $text in the [dart:html](../html.html) ' +
167 'library._';
168 }
169
170 types = _diff.htmlTypesToDom[type];
171 if (types != null && types.length > 0) {
172 final text = doc.joinWithCommas(map(types, _linkType));
173 return '_This corresponds to $text in the [dart:dom](../dom.html) ' +
174 'library._';
175 }
176
177 return '';
178 }
OLDNEW
« no previous file with comments | « utils/apidoc/apidoc ('k') | utils/apidoc/mdn/README.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698