OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 /** | |
6 * A library for extracting the documentation from the various HTML libraries | |
7 * ([dart:html], [dart:svg], [dart:web_audio], [dart:indexed_db]) and saving | |
8 * those documentation comments to a JSON file. | |
9 */ | |
10 | |
11 library docs; | |
12 | |
13 import '../../../../sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart'; | |
14 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mir
rors.dart'; | |
15 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_ut
il.dart'; | |
16 import '../../../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart'; | |
17 import '../../../../sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart'; | |
18 import '../../../../utils/apidoc/lib/metadata.dart'; | |
19 import 'dart:async'; | |
20 import 'dart:io'; | |
21 | |
22 /// The various HTML libraries. | |
23 const List<String> HTML_LIBRARY_NAMES = const ['dart:html', | |
24 'dart:indexed_db', | |
25 'dart:svg', | |
26 'dart:web_audio', | |
27 'dart:web_gl', | |
28 'dart:web_sql']; | |
29 /** | |
30 * Converts the libraries in [HTML_LIBRARY_NAMES] to a json file at [jsonPath] | |
31 * given the library path at [libUri]. | |
32 * | |
33 * The json output looks like: | |
34 * { | |
35 * $library_name: { | |
36 * $interface_name: { | |
37 * comment: "$comment" | |
38 * members: { | |
39 * $member: [ | |
40 * [$comment1line1, | |
41 * $comment1line2, | |
42 * ...], | |
43 * ... | |
44 * ], | |
45 * ... | |
46 * } | |
47 * }, | |
48 * ... | |
49 * }, | |
50 * ... | |
51 * } | |
52 * | |
53 * Completes to true if any errors were encountered, false otherwise. | |
54 */ | |
55 Future<bool> convert(String libUri, String jsonPath) { | |
56 var paths = <String>[]; | |
57 for (var libraryName in HTML_LIBRARY_NAMES) { | |
58 paths.add(libraryName); | |
59 } | |
60 | |
61 return analyze(paths, libUri, options: ['--preserve-comments']) | |
62 .then((MirrorSystem mirrors) { | |
63 var convertedJson = _generateJsonFromLibraries(mirrors); | |
64 return _exportJsonToFile(convertedJson, jsonPath); | |
65 }); | |
66 } | |
67 | |
68 Future<bool> _exportJsonToFile(Map convertedJson, String jsonPath) { | |
69 return new Future.sync(() { | |
70 final jsonFile = new File(jsonPath); | |
71 var writeJson = prettySerialize(convertedJson); | |
72 | |
73 var outputStream = jsonFile.openWrite(); | |
74 outputStream.writeln(writeJson); | |
75 outputStream.close(); | |
76 return outputStream.done.then((_) => false); | |
77 }); | |
78 } | |
79 | |
80 Map _generateJsonFromLibraries(MirrorSystem mirrors) { | |
81 var convertedJson = {}; | |
82 | |
83 // Sort the libraries by name (not key). | |
84 var sortedLibraries = new List<LibraryMirror>.from( | |
85 mirrors.libraries.values.where( | |
86 (e) => HTML_LIBRARY_NAMES.indexOf(e.uri.toString()) >= 0)) | |
87 ..sort((x, y) => | |
88 x.uri.toString().toUpperCase().compareTo( | |
89 y.uri.toString().toUpperCase())); | |
90 | |
91 for (LibraryMirror libMirror in sortedLibraries) { | |
92 print('Extracting documentation from ${libMirror.simpleName}.'); | |
93 | |
94 var libraryJson = {}; | |
95 var sortedClasses = _sortAndFilterMirrors( | |
96 classesOf(libMirror.declarations).toList(), ignoreDocsEditable: true); | |
97 | |
98 for (ClassMirror classMirror in sortedClasses) { | |
99 print(' class: $classMirror'); | |
100 var classJson = {}; | |
101 var sortedMembers = _sortAndFilterMirrors( | |
102 membersOf(classMirror.declarations).toList()); | |
103 | |
104 var membersJson = {}; | |
105 for (var memberMirror in sortedMembers) { | |
106 print(' member: $memberMirror'); | |
107 var memberDomName = domNames(memberMirror)[0]; | |
108 var memberComment = _splitCommentsByNewline( | |
109 computeUntrimmedCommentAsList(memberMirror)); | |
110 | |
111 // Remove interface name from Dom Name. | |
112 if (memberDomName.indexOf('.') >= 0) { | |
113 memberDomName = | |
114 memberDomName.substring(memberDomName.indexOf('.') + 1); | |
115 } | |
116 | |
117 if (!memberComment.isEmpty) { | |
118 membersJson.putIfAbsent(memberDomName, () => memberComment); | |
119 } | |
120 } | |
121 | |
122 // Only include the comment if DocsEditable is set. | |
123 var classComment = _splitCommentsByNewline( | |
124 computeUntrimmedCommentAsList(classMirror)); | |
125 if (!classComment.isEmpty && | |
126 findMetadata(classMirror.metadata, 'DocsEditable') != null) { | |
127 classJson.putIfAbsent('comment', () => classComment); | |
128 } | |
129 if (!membersJson.isEmpty) { | |
130 classJson.putIfAbsent('members', () => | |
131 membersJson); | |
132 } | |
133 | |
134 if (!classJson.isEmpty) { | |
135 libraryJson.putIfAbsent(domNames(classMirror)[0], () => | |
136 classJson); | |
137 } | |
138 } | |
139 | |
140 if (!libraryJson.isEmpty) { | |
141 convertedJson.putIfAbsent(nameOf(libMirror), () => | |
142 libraryJson); | |
143 } | |
144 } | |
145 | |
146 return convertedJson; | |
147 } | |
148 | |
149 /// Filter out mirrors that are private, or which are not part of this docs | |
150 /// process. That is, ones without the DocsEditable annotation. | |
151 /// If [ignoreDocsEditable] is true, relax the restriction on @DocsEditable(). | |
152 /// This is to account for classes that are defined in a template, but whose | |
153 /// members are generated. | |
154 List<DeclarationMirror> _sortAndFilterMirrors(List<DeclarationMirror> mirrors, | |
155 {ignoreDocsEditable: false}) { | |
156 | |
157 var filteredMirrors = mirrors.where((DeclarationMirror c) => | |
158 !domNames(c).isEmpty && | |
159 !displayName(c).startsWith('_') && | |
160 (!ignoreDocsEditable ? (findMetadata(c.metadata, 'DocsEditable') != null) | |
161 : true)) | |
162 .toList(); | |
163 | |
164 filteredMirrors.sort((x, y) => | |
165 domNames(x)[0].toUpperCase().compareTo( | |
166 domNames(y)[0].toUpperCase())); | |
167 | |
168 return filteredMirrors; | |
169 } | |
170 | |
171 List<String> _splitCommentsByNewline(List<String> comments) { | |
172 var out = []; | |
173 | |
174 comments.forEach((c) { | |
175 out.addAll(c.split(new RegExp('\n'))); | |
176 }); | |
177 | |
178 return out; | |
179 } | |
180 | |
181 /// Given the class mirror, returns the names found or an empty list. | |
182 List<String> domNames(DeclarationMirror mirror) { | |
183 var domNameMetadata = findMetadata(mirror.metadata, 'DomName'); | |
184 | |
185 if (domNameMetadata != null) { | |
186 var domNames = <String>[]; | |
187 var tags = domNameMetadata.getField(#name); | |
188 for (var s in tags.reflectee.split(',')) { | |
189 domNames.add(s.trim()); | |
190 } | |
191 | |
192 if (domNames.length == 1 && domNames[0] == 'none') return <String>[]; | |
193 return domNames; | |
194 } else { | |
195 return <String>[]; | |
196 } | |
197 } | |
OLD | NEW |