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

Side by Side Diff: utils/dartdoc/dartdoc.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/dartdoc/client-live-nav.dart ('k') | utils/dartdoc/static/external-link.png » ('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 * 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
11 * create these beautiful docs, dartdoc parses your library and every library 11 * create these beautiful docs, dartdoc parses your library and every library
12 * it imports (recursively). From each library, it parses all classes and 12 * it imports (recursively). From each library, it parses all classes and
13 * members, finds the associated doc comments and builds crosslinked docs from 13 * members, finds the associated doc comments and builds crosslinked docs from
14 * them. 14 * them.
15 */ 15 */
16 #library('dartdoc'); 16 #library('dartdoc');
17 17
18 #import('dart:json'); 18 #import('dart:json');
19 #import('../../frog/lang.dart'); 19 #import('../../frog/lang.dart');
20 #import('../../frog/file_system.dart'); 20 #import('../../frog/file_system.dart');
21 #import('../../frog/file_system_node.dart'); 21 #import('../../frog/file_system_node.dart');
22 #import('../../frog/lib/node/node.dart'); 22 #import('../../frog/lib/node/node.dart');
23 #import('classify.dart'); 23 #import('classify.dart');
24 #import('markdown.dart', prefix: 'md'); 24 #import('markdown.dart', prefix: 'md');
25 25
26 #source('comment_map.dart'); 26 #source('comment_map.dart');
27 #source('files.dart');
28 #source('utils.dart'); 27 #source('utils.dart');
29 28
29 /** Path to generate HTML files into. */
30 final _outdir = 'docs';
31
30 /** 32 /**
31 * Generates completely static HTML containing everything you need to browse 33 * Generates completely static HTML containing everything you need to browse
32 * the docs. The only client side behavior is trivial stuff like syntax 34 * the docs. The only client side behavior is trivial stuff like syntax
33 * highlighting code. 35 * highlighting code.
34 */ 36 */
35 final MODE_STATIC = 0; 37 final MODE_STATIC = 0;
36 38
37 /** 39 /**
38 * Generated docs do not include baked HTML navigation. Instead, a single 40 * Generated docs do not include baked HTML navigation. Instead, a single
39 * `nav.json` file is created and the appropriate navigation is generated 41 * `nav.json` file is created and the appropriate navigation is generated
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 128
127 /** The library that we're currently generating docs for. */ 129 /** The library that we're currently generating docs for. */
128 Library _currentLibrary; 130 Library _currentLibrary;
129 131
130 /** The type that we're currently generating docs for. */ 132 /** The type that we're currently generating docs for. */
131 Type _currentType; 133 Type _currentType;
132 134
133 /** The member that we're currently generating docs for. */ 135 /** The member that we're currently generating docs for. */
134 Member _currentMember; 136 Member _currentMember;
135 137
138 /** The path to the file currently being written to, relative to [outdir]. */
139 String _filePath;
140
141 /** The file currently being written to. */
142 StringBuffer _file;
143
136 int _totalLibraries = 0; 144 int _totalLibraries = 0;
137 int _totalTypes = 0; 145 int _totalTypes = 0;
138 int _totalMembers = 0; 146 int _totalMembers = 0;
139 147
140 Dartdoc() 148 Dartdoc()
141 : _comments = new CommentMap() { 149 : _comments = new CommentMap() {
142 // Patch in support for [:...:]-style code to the markdown parser. 150 // Patch in support for [:...:]-style code to the markdown parser.
143 // TODO(rnystrom): Markdown already has syntax for this. Phase this out? 151 // TODO(rnystrom): Markdown already has syntax for this. Phase this out?
144 md.InlineParser.syntaxes.insertRange(0, 1, 152 md.InlineParser.syntaxes.insertRange(0, 1,
145 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]')); 153 new md.CodeSyntax(@'\[\:((?:.|\n)*?)\:\]'));
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 200
193 docIndex(); 201 docIndex();
194 for (final library in world.libraries.getValues()) { 202 for (final library in world.libraries.getValues()) {
195 docLibrary(library); 203 docLibrary(library);
196 } 204 }
197 } finally { 205 } finally {
198 options.dietParse = oldDietParse; 206 options.dietParse = oldDietParse;
199 } 207 }
200 } 208 }
201 209
210 startFile(String path) {
211 _filePath = path;
212 _file = new StringBuffer();
213 }
214
215 endFile() {
216 String outPath = '$_outdir/$_filePath';
217 world.files.createDirectory(dirname(outPath), recursive: true);
218
219 world.files.writeString(outPath, _file.toString());
220 _filePath = null;
221 _file = null;
222 }
223
224 write(String s) {
225 _file.add(s);
226 }
227
228 writeln(String s) {
229 write(s);
230 write('\n');
231 }
232
202 /** 233 /**
203 * Writes the page header with the given [title] and [breadcrumbs]. The 234 * Writes the page header with the given [title] and [breadcrumbs]. The
204 * breadcrumbs are an interleaved list of links and titles. If a link is null, 235 * breadcrumbs are an interleaved list of links and titles. If a link is null,
205 * then no link will be generated. For example, given: 236 * then no link will be generated. For example, given:
206 * 237 *
207 * ['foo', 'foo.html', 'bar', null] 238 * ['foo', 'foo.html', 'bar', null]
208 * 239 *
209 * It will output: 240 * It will output:
210 * 241 *
211 * <a href="foo.html">foo</a> &rsaquo; bar 242 * <a href="foo.html">foo</a> &rsaquo; bar
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 ''' 514 '''
484 <h2>${type.isClass ? "Class" : "Interface"} 515 <h2>${type.isClass ? "Class" : "Interface"}
485 <strong>${typeName(type, showBounds: true)}</strong></h2> 516 <strong>${typeName(type, showBounds: true)}</strong></h2>
486 '''); 517 ''');
487 518
488 docCode(type.span, getTypeComment(type)); 519 docCode(type.span, getTypeComment(type));
489 docInheritance(type); 520 docInheritance(type);
490 docConstructors(type); 521 docConstructors(type);
491 docMembers(type); 522 docMembers(type);
492 523
524 writeTypeFooter();
493 writeFooter(); 525 writeFooter();
494 endFile(); 526 endFile();
495 } 527 }
496 528
529 /** Override this to write additional content at the end of a type's page. */
530 void writeTypeFooter() {
531 // Do nothing.
532 }
533
497 /** 534 /**
498 * Writes an inline type span for the given type. This is a little box with 535 * Writes an inline type span for the given type. This is a little box with
499 * an icon and the type's name. It's similar to how types appear in the 536 * an icon and the type's name. It's similar to how types appear in the
500 * navigation, but is suitable for inline (as opposed to in a `<ul>`) use. 537 * navigation, but is suitable for inline (as opposed to in a `<ul>`) use.
501 */ 538 */
502 typeSpan(Type type) { 539 typeSpan(Type type) {
503 var icon = 'interface'; 540 var icon = 'interface';
504 if (type.name.endsWith('Exception')) { 541 if (type.name.endsWith('Exception')) {
505 icon = 'exception'; 542 icon = 'exception';
506 } else if (type.isClass) { 543 } else if (type.isClass) {
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 var name = method.name; 736 var name = method.name;
700 if (name.startsWith('get:')) { 737 if (name.startsWith('get:')) {
701 // Getter. 738 // Getter.
702 name = 'get ${name.substring(4)}'; 739 name = 'get ${name.substring(4)}';
703 } else if (name.startsWith('set:')) { 740 } else if (name.startsWith('set:')) {
704 // Setter. 741 // Setter.
705 name = 'set ${name.substring(4)}'; 742 name = 'set ${name.substring(4)}';
706 } else if (name == ':negate') { 743 } else if (name == ':negate') {
707 // Dart uses 'negate' for prefix negate operators, not '!'. 744 // Dart uses 'negate' for prefix negate operators, not '!'.
708 name = 'operator negate'; 745 name = 'operator negate';
746 } else if (name == ':call') {
747 name = 'operator call';
709 } else { 748 } else {
710 // See if it's an operator. 749 // See if it's an operator.
711 name = TokenKind.rawOperatorFromMethod(name); 750 name = TokenKind.rawOperatorFromMethod(name);
712 if (name == null) { 751 if (name == null) {
713 name = method.name; 752 name = method.name;
714 } else { 753 } else {
715 name = 'operator $name'; 754 name = 'operator $name';
716 } 755 }
717 } 756 }
718 757
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 write(')'); 837 write(')');
799 } 838 }
800 839
801 /** 840 /**
802 * Documents the code contained within [span] with [comment]. If [showCode] 841 * Documents the code contained within [span] with [comment]. If [showCode]
803 * is `true` (and [includeSource] is set), also includes the source code. 842 * is `true` (and [includeSource] is set), also includes the source code.
804 */ 843 */
805 docCode(SourceSpan span, String comment, [bool showCode = false]) { 844 docCode(SourceSpan span, String comment, [bool showCode = false]) {
806 writeln('<div class="doc">'); 845 writeln('<div class="doc">');
807 if (comment != null) { 846 if (comment != null) {
808 writeln(md.markdownToHtml(comment)); 847 writeln(comment);
809 } 848 }
810 849
811 if (includeSource && showCode) { 850 if (includeSource && showCode) {
812 writeln('<pre class="source">'); 851 writeln('<pre class="source">');
813 writeln(md.escapeHtml(unindentCode(span))); 852 writeln(md.escapeHtml(unindentCode(span)));
814 writeln('</pre>'); 853 writeln('</pre>');
815 } 854 }
816 855
817 writeln('</div>'); 856 writeln('</div>');
818 } 857 }
819 858
820 /** Get the doc comment associated with the given type. */ 859 /** Get the doc comment associated with the given type. */
821 String getTypeComment(Type type) => _comments.find(type.span); 860 String getTypeComment(Type type) {
861 String comment = _comments.find(type.span);
862 if (comment == null) return null;
863 return md.markdownToHtml(comment);
864 }
822 865
823 /** Get the doc comment associated with the given method. */ 866 /** Get the doc comment associated with the given method. */
824 String getMethodComment(MethodMember method) => _comments.find(method.span); 867 String getMethodComment(MethodMember method) {
868 String comment = _comments.find(method.span);
869 if (comment == null) return null;
870 return md.markdownToHtml(comment);
871 }
825 872
826 /** Get the doc comment associated with the given field. */ 873 /** Get the doc comment associated with the given field. */
827 String getFieldComment(FieldMember field) => _comments.find(field.span); 874 String getFieldComment(FieldMember field) {
875 String comment = _comments.find(field.span);
876 if (comment == null) return null;
877 return md.markdownToHtml(comment);
878 }
879
880 /**
881 * Converts [fullPath] which is understood to be a full path from the root of
882 * the generated docs to one relative to the current file.
883 */
884 String relativePath(String fullPath) {
885 // Don't make it relative if it's an absolute path.
886 if (isAbsolute(fullPath)) return fullPath;
887
888 // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do
889 // this if the paths overlap.
890 return repeat('../', countOccurrences(_filePath, '/')) + fullPath;
891 }
892
893 /** Gets whether or not the given URL is absolute or relative. */
894 bool isAbsolute(String url) {
895 // TODO(rnystrom): Why don't we have a nice type in the platform for this?
896 // TODO(rnystrom): This is a bit hackish. We consider any URL that lacks
897 // a scheme to be relative.
898 return const RegExp(@'^\w+:').hasMatch(url);
899 }
900
901 /** Gets the URL to the documentation for [library]. */
902 String libraryUrl(Library library) {
903 return '${sanitize(library.name)}.html';
904 }
905
906 /** Gets the URL for the documentation for [type]. */
907 String typeUrl(Type type) {
908 // Always get the generic type to strip off any type parameters or
909 // arguments. If the type isn't generic, genericType returns `this`, so it
910 // works for non-generic types too.
911 return '${sanitize(type.library.name)}/${type.genericType.name}.html';
912 }
913
914 /** Gets the URL for the documentation for [member]. */
915 String memberUrl(Member member) {
916 return '${typeUrl(member.declaringType)}#${member.name}';
917 }
918
919 /** Gets the anchor id for the document for [member]. */
920 String memberAnchor(Member member) {
921 return '${member.name}';
922 }
828 923
829 /** 924 /**
830 * Creates a hyperlink. Handles turning the [href] into an appropriate 925 * Creates a hyperlink. Handles turning the [href] into an appropriate
831 * relative path from the current file. 926 * relative path from the current file.
832 */ 927 */
833 String a(String href, String contents, [String css]) { 928 String a(String href, String contents, [String css]) {
929 // Mark outgoing external links, mainly so we can style them.
930 final rel = isAbsolute(href) ? ' ref="external"' : '';
834 final cssClass = css == null ? '' : ' class="$css"'; 931 final cssClass = css == null ? '' : ' class="$css"';
835 return '<a href="${relativePath(href)}"$cssClass>$contents</a>'; 932 return '<a href="${relativePath(href)}"$cssClass$rel>$contents</a>';
836 } 933 }
837 934
838 /** 935 /**
839 * Writes a type annotation for the given type and (optional) parameter name. 936 * Writes a type annotation for the given type and (optional) parameter name.
840 */ 937 */
841 annotateType(Type enclosingType, Type type, [String paramName = null]) { 938 annotateType(Type enclosingType, Type type, [String paramName = null]) {
842 // Don't bother explicitly displaying Dynamic. 939 // Don't bother explicitly displaying Dynamic.
843 if (type.isVar) { 940 if (type.isVar) {
844 if (paramName !== null) write(paramName); 941 if (paramName !== null) write(paramName);
845 return; 942 return;
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
1056 1153
1057 return new md.Element.text('code', name); 1154 return new md.Element.text('code', name);
1058 } 1155 }
1059 1156
1060 // TODO(rnystrom): Move into SourceSpan? 1157 // TODO(rnystrom): Move into SourceSpan?
1061 int getSpanColumn(SourceSpan span) { 1158 int getSpanColumn(SourceSpan span) {
1062 final line = span.file.getLine(span.start); 1159 final line = span.file.getLine(span.start);
1063 return span.file.getColumn(line, span.start); 1160 return span.file.getColumn(line, span.start);
1064 } 1161 }
1065 } 1162 }
OLDNEW
« no previous file with comments | « utils/dartdoc/client-live-nav.dart ('k') | utils/dartdoc/static/external-link.png » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698