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

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

Issue 10701091: Dartdoc and Apidoc updated to use dart2js through the mirror system. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixed cf. rnystrom's comments. Created 8 years, 5 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 * A script to assist in documenting the difference between the dart:html API 6 * A script to assist in documenting the difference between the dart:html API
7 * and the old DOM API. 7 * and the old DOM API.
8 */ 8 */
9 #library('html_diff'); 9 #library('html_diff');
10 10
11 #import('dart:coreimpl'); 11 #import('dart:coreimpl');
12 12
13 #import('../../lib/dartdoc/frog/lang.dart');
14 #import('../../lib/dartdoc/frog/file_system_vm.dart');
15 #import('../../lib/dartdoc/frog/file_system.dart');
16 #import('../../lib/dartdoc/dartdoc.dart'); 13 #import('../../lib/dartdoc/dartdoc.dart');
14 #import('../../lib/dartdoc/mirrors/mirrors.dart');
15 #import('../../lib/dartdoc/mirrors/mirrors_util.dart');
17 16
18 /** 17 /**
19 * A class for computing a many-to-many mapping between the types and 18 * A class for computing a many-to-many mapping between the types and
20 * members in `dart:dom_deprecated` and `dart:html`. This mapping is 19 * members in `dart:dom_deprecated` and `dart:html`. This mapping is
21 * based on two indicators: 20 * based on two indicators:
22 * 21 *
23 * 1. Auto-detected wrappers. Most `dart:html` types correspond 22 * 1. Auto-detected wrappers. Most `dart:html` types correspond
24 * straightforwardly to a single `dart:dom_deprecated` type, and 23 * straightforwardly to a single `dart:dom_deprecated` type, and
25 * have the same name. In addition, most `dart:html` methods 24 * have the same name. In addition, most `dart:html` methods
26 * just call a single `dart:dom_deprecated` method. This class 25 * just call a single `dart:dom_deprecated` method. This class
(...skipping 10 matching lines...) Expand all
37 * annotated `dart:html` type/member. `NAME`s on member annotations 36 * annotated `dart:html` type/member. `NAME`s on member annotations
38 * can refer to either fully-qualified member names (e.g. 37 * can refer to either fully-qualified member names (e.g.
39 * `Document.createElement`) or unqualified member names 38 * `Document.createElement`) or unqualified member names
40 * (e.g. `createElement`). Unqualified member names are assumed to 39 * (e.g. `createElement`). Unqualified member names are assumed to
41 * refer to members of one of the corresponding `dart:dom_deprecated` 40 * refer to members of one of the corresponding `dart:dom_deprecated`
42 * types. 41 * types.
43 */ 42 */
44 class HtmlDiff { 43 class HtmlDiff {
45 /** A map from `dart:dom_deprecated` members to corresponding 44 /** A map from `dart:dom_deprecated` members to corresponding
46 * `dart:html` members. */ 45 * `dart:html` members. */
47 final Map<Member, Set<Member>> domToHtml; 46 final Map<MemberMirror, Set<MemberMirror>> domToHtml;
48 47
49 /** A map from `dart:html` members to corresponding 48 /** A map from `dart:html` members to corresponding
50 * `dart:dom_deprecated` members. */ 49 * `dart:dom_deprecated` members. */
51 final Map<Member, Set<Member>> htmlToDom; 50 final Map<MemberMirror, Set<MemberMirror>> htmlToDom;
52 51
53 /** A map from `dart:dom_deprecated` types to corresponding 52 /** A map from `dart:dom_deprecated` types to corresponding
54 * `dart:html` types. */ 53 * `dart:html` types.
55 final Map<Type, Set<Type>> domTypesToHtml; 54 * TODO(johnniwinther): We use qualified names as keys, since mirrors
55 * (currently) are not equal between different mirror systems.
56 */
57 final Map<String, Set<InterfaceMirror>> domTypesToHtml;
56 58
57 /** A map from `dart:html` types to corresponding 59 /** A map from `dart:html` types to corresponding
58 * `dart:dom_deprecated` types. */ 60 * `dart:dom_deprecated` types.
59 final Map<Type, Set<Type>> htmlTypesToDom; 61 * TODO(johnniwinther): We use qualified names as keys, since mirrors
62 * (currently) are not equal between different mirror systems.
63 */
64 final Map<String, Set<InterfaceMirror>> htmlTypesToDom;
60 65
61 final CommentMap comments; 66 final CommentMap comments;
62 67
63 /** If true, then print warning messages. */ 68 /** If true, then print warning messages. */
64 final bool _printWarnings; 69 final bool _printWarnings;
65 70
66 static Library dom; 71 static Compilation _compilation;
72 static MirrorSystem _mirrors;
73 static LibraryMirror dom;
67 74
68 /** 75 /**
69 * Perform static initialization of [world]. This should be run before 76 * Perform static initialization of [world]. This should be run before
70 * calling [HtmlDiff.run]. 77 * calling [HtmlDiff.run].
71 */ 78 */
72 static void initialize() { 79 static void initialize(String libDir) {
73 world.getOrAddLibrary('dart:dom_deprecated'); 80 _compilation = new Compilation.library(
74 world.getOrAddLibrary('dart:html'); 81 const <String>['dart:dom_deprecated', 'dart:html'], libDir);
75 world.process(); 82 _mirrors = _compilation.mirrors();
76 83
77 dom = world.libraries['dart:dom_deprecated']; 84 // Find 'dart:dom_deprecated' by its library tag 'dom'.
85 dom = findMirror(_mirrors.libraries(), 'dom');
78 } 86 }
79 87
80 HtmlDiff([bool printWarnings = false]) : 88 HtmlDiff([bool printWarnings = false]) :
81 _printWarnings = printWarnings, 89 _printWarnings = printWarnings,
82 domToHtml = new Map<Member, Set<Member>>(), 90 domToHtml = new Map<MemberMirror, Set<MemberMirror>>(),
83 htmlToDom = new Map<Member, Set<Member>>(), 91 htmlToDom = new Map<MemberMirror, Set<MemberMirror>>(),
84 domTypesToHtml = new Map<Type, Set<Type>>(), 92 domTypesToHtml = new Map<String, Set<InterfaceMirror>>(),
85 htmlTypesToDom = new Map<Type, Set<Type>>(), 93 htmlTypesToDom = new Map<String, Set<InterfaceMirror>>(),
86 comments = new CommentMap(); 94 comments = new CommentMap();
87 95
88 void warn(String s) { 96 void warn(String s) {
89 if (_printWarnings) { 97 if (_printWarnings) {
90 print('Warning: $s'); 98 print('Warning: $s');
91 } 99 }
92 } 100 }
93 101
94 /** 102 /**
95 * Computes the `dart:dom_deprecated` to `dart:html` mapping, and 103 * Computes the `dart:dom_deprecated` to `dart:html` mapping, and
96 * places it in [domToHtml], [htmlToDom], [domTypesToHtml], and 104 * places it in [domToHtml], [htmlToDom], [domTypesToHtml], and
97 * [htmlTypesToDom]. Before this is run, Frog should be initialized 105 * [htmlTypesToDom]. Before this is run, Frog should be initialized
98 * (via [parseOptions] and [initializeWorld]) and 106 * (via [parseOptions] and [initializeWorld]) and
99 * [HtmlDiff.initialize] should be called. 107 * [HtmlDiff.initialize] should be called.
100 */ 108 */
101 void run() { 109 void run() {
102 final htmlLib = world.libraries['dart:html']; 110 LibraryMirror htmlLib = findMirror(_mirrors.libraries(), 'html');
103 for (Type htmlType in htmlLib.types.getValues()) { 111 if (htmlLib === null) {
112 warn('Could not find dart:html');
113 return;
114 }
115 for (InterfaceMirror htmlType in htmlLib.types().getValues()) {
104 final domTypes = htmlToDomTypes(htmlType); 116 final domTypes = htmlToDomTypes(htmlType);
105 if (domTypes.isEmpty()) continue; 117 if (domTypes.isEmpty()) continue;
106 118
107 htmlTypesToDom.putIfAbsent(htmlType, 119 htmlTypesToDom.putIfAbsent(htmlType.qualifiedName(),
108 () => new Set()).addAll(domTypes); 120 () => new Set()).addAll(domTypes);
109 domTypes.forEach((t) => 121 domTypes.forEach((t) =>
110 domTypesToHtml.putIfAbsent(t, () => new Set()).add(htmlType)); 122 domTypesToHtml.putIfAbsent(t.qualifiedName(),
123 () => new Set()).add(htmlType));
111 124
112 final members = new List.from(htmlType.members.getValues()); 125 htmlType.declaredMembers().forEach(
113 members.addAll(htmlType.constructors.getValues()); 126 (_, m) => _addMemberDiff(m, domTypes));
114 htmlType.factories.forEach((f) => members.add(f));
115 members.forEach((m) => _addMemberDiff(m, domTypes));
116 } 127 }
117 } 128 }
118 129
119 /** 130 /**
120 * Records the `dart:dom_deprecated` to `dart:html` mapping for 131 * Records the `dart:dom_deprecated` to `dart:html` mapping for
121 * [implMember] (from `dart:html`). [domTypes] are the 132 * [implMember] (from `dart:html`). [domTypes] are the
122 * `dart:dom_deprecated` [Type]s that correspond to [implMember]'s 133 * `dart:dom_deprecated` [Type]s that correspond to [implMember]'s
123 * defining [Type]. 134 * defining [Type].
124 */ 135 */
125 void _addMemberDiff(Member htmlMember, List<Type> domTypes) { 136 void _addMemberDiff(MemberMirror htmlMember, List<TypeMirror> domTypes) {
126 if (htmlMember.isProperty) {
127 if (htmlMember.canGet) _addMemberDiff(htmlMember.getter, domTypes);
128 if (htmlMember.canSet) _addMemberDiff(htmlMember.setter, domTypes);
129 }
130
131 var domMembers = htmlToDomMembers(htmlMember, domTypes); 137 var domMembers = htmlToDomMembers(htmlMember, domTypes);
132 if (htmlMember == null && !domMembers.isEmpty()) { 138 if (htmlMember == null && !domMembers.isEmpty()) {
133 warn('dart:html member ${htmlMember.declaringType.name}.' 139 warn('dart:html member '
134 '${htmlMember.name} has no corresponding dart:html member.'); 140 '${htmlMember.surroundingDeclaration().simpleName()}.'
141 '${htmlMember.simpleName()} has no corresponding dart:html member.');
135 } 142 }
136 143
137 if (htmlMember == null) return; 144 if (htmlMember == null) return;
138 if (!domMembers.isEmpty()) htmlToDom[htmlMember] = domMembers; 145 if (!domMembers.isEmpty()) htmlToDom[htmlMember] = domMembers;
139 domMembers.forEach((m) => 146 domMembers.forEach((m) =>
140 domToHtml.putIfAbsent(m, () => new Set()).add(htmlMember)); 147 domToHtml.putIfAbsent(m, () => new Set()).add(htmlMember));
141 } 148 }
142 149
143 /** 150 /**
144 * Returns the `dart:dom_deprecated` [Type]s that correspond to 151 * Returns the `dart:dom_deprecated` [Type]s that correspond to
145 * [htmlType] from `dart:html`. This can be the empty list if no 152 * [htmlType] from `dart:html`. This can be the empty list if no
146 * correspondence is found. 153 * correspondence is found.
147 */ 154 */
148 List<Type> htmlToDomTypes(Type htmlType) { 155 List<InterfaceMirror> htmlToDomTypes(InterfaceMirror htmlType) {
149 if (htmlType.name == null) return []; 156 if (htmlType.simpleName() == null) return [];
150 final tags = _getTags(comments.find(htmlType.span)); 157 final tags = _getTags(comments.find(htmlType.location()));
151
152 if (tags.containsKey('domName')) { 158 if (tags.containsKey('domName')) {
153 var domNames = map(tags['domName'].split(','), (s) => s.trim()); 159 var domNames = <String>[];
160 for (var s in tags['domName'].split(',')) {
161 domNames.add(s.trim());
162 }
154 if (domNames.length == 1 && domNames[0] == 'none') return []; 163 if (domNames.length == 1 && domNames[0] == 'none') return [];
155 return map(domNames, (domName) { 164 var domTypes = <InterfaceMirror>[];
156 final domType = dom.types[domName]; 165 for (var domName in domNames) {
157 if (domType == null) warn('no dart:dom_deprecated type named $domName'); 166 final domType = findMirror(dom.types(), domName);
158 return domType; 167 if (domType == null) {
159 }); 168 warn('no dart:dom_deprecated type named $domName');
169 } else {
170 domTypes.add(domType);
171 }
172 }
173 return domTypes;
160 } 174 }
161 return <Type>[]; 175 return <InterfaceMirror>[];
162 } 176 }
163 177
164 /** 178 /**
165 * Returns the `dart:dom_deprecated` [Member]s that correspond to 179 * Returns the `dart:dom_deprecated` [Member]s that correspond to
166 * [htmlMember] from `dart:html`. This can be the empty set if no 180 * [htmlMember] from `dart:html`. This can be the empty set if no
167 * correspondence is found. [domTypes] are the 181 * correspondence is found. [domTypes] are the
168 * `dart:dom_deprecated` [Type]s that correspond to [implMember]'s 182 * `dart:dom_deprecated` [Type]s that correspond to [implMember]'s
169 * defining [Type]. 183 * defining [Type].
170 */ 184 */
171 Set<Member> htmlToDomMembers(Member htmlMember, List<Type> domTypes) { 185 Set<MemberMirror> htmlToDomMembers(MemberMirror htmlMember,
186 List<InterfaceMirror> domTypes) {
172 if (htmlMember.isPrivate) return new Set(); 187 if (htmlMember.isPrivate) return new Set();
173 final tags = _getTags(comments.find(htmlMember.span)); 188 final tags = _getTags(comments.find(htmlMember.location()));
174 if (tags.containsKey('domName')) { 189 if (tags.containsKey('domName')) {
175 final domNames = map(tags['domName'].split(','), (s) => s.trim()); 190 var domNames = <String>[];
191 for (var s in tags['domName'].split(',')) {
192 domNames.add(s.trim());
193 }
176 if (domNames.length == 1 && domNames[0] == 'none') return new Set(); 194 if (domNames.length == 1 && domNames[0] == 'none') return new Set();
177 final members = new Set(); 195 final members = new Set();
178 domNames.forEach((name) { 196 domNames.forEach((name) {
179 var nameMembers = _membersFromName(name, domTypes); 197 var nameMembers = _membersFromName(name, domTypes);
180 if (nameMembers.isEmpty()) { 198 if (nameMembers.isEmpty()) {
181 if (name.contains('.')) { 199 if (name.contains('.')) {
182 warn('no member $name'); 200 warn('no member $name');
183 } else { 201 } else {
184 final options = Strings.join( 202 final options = <String>[];
185 map(domTypes, (t) => "${t.name}.$name"), ' or '); 203 for (var t in domTypes) {
204 options.add('${t.simpleName()}.${name}');
205 }
206 Strings.join(options, ' or ');
186 warn('no member $options'); 207 warn('no member $options');
187 } 208 }
188 } 209 }
189 members.addAll(nameMembers); 210 members.addAll(nameMembers);
190 }); 211 });
191 return members; 212 return members;
192 } 213 }
193 214
194 return new Set(); 215 return new Set();
195 } 216 }
196 217
197 /** 218 /**
198 * Returns the `dart:dom_deprecated` [Member]s that are indicated by 219 * Returns the `dart:dom_deprecated` [Member]s that are indicated by
199 * [name]. [name] can be either an unqualified member name 220 * [name]. [name] can be either an unqualified member name
200 * (e.g. `createElement`), in which case it's treated as the name of 221 * (e.g. `createElement`), in which case it's treated as the name of
201 * a member of one of [defaultTypes], or a fully-qualified member 222 * a member of one of [defaultTypes], or a fully-qualified member
202 * name (e.g. `Document.createElement`), in which case it's looked 223 * name (e.g. `Document.createElement`), in which case it's looked
203 * up in `dart:dom_deprecated` and [defaultTypes] is ignored. 224 * up in `dart:dom_deprecated` and [defaultTypes] is ignored.
204 */ 225 */
205 Set<Member> _membersFromName(String name, List<Type> defaultTypes) { 226 Set<MemberMirror> _membersFromName(String name,
227 List<InterfaceMirror> defaultTypes) {
206 if (!name.contains('.', 0)) { 228 if (!name.contains('.', 0)) {
207 if (defaultTypes.isEmpty()) { 229 if (defaultTypes.isEmpty()) {
208 warn('no default type for ${name}'); 230 warn('no default type for ${name}');
209 return new Set(); 231 return new Set();
210 } 232 }
211 final members = new Set<Member>(); 233 final members = new Set<MemberMirror>();
212 defaultTypes.forEach((t) { 234 defaultTypes.forEach((t) {
213 if (t.members.containsKey(name)) members.add(t.members[name]); 235 MemberMirror member = findMirror(t.declaredMembers(), name);
236 if (member !== null) {
237 members.add(member);
238 }
214 }); 239 });
215 return members; 240 return members;
216 } 241 }
217 242
218 final splitName = name.split('.'); 243 final splitName = name.split('.');
219 if (splitName.length != 2) { 244 if (splitName.length != 2) {
220 warn('invalid member name ${name}'); 245 warn('invalid member name ${name}');
221 return new Set(); 246 return new Set();
222 } 247 }
223 248
224 var typeName = splitName[0]; 249 var typeName = splitName[0];
225 250
226 final type = dom.types[typeName]; 251 InterfaceMirror type = findMirror(dom.types(), typeName);
227 if (type == null) return new Set(); 252 if (type == null) return new Set();
228 253
229 final member = type.members[splitName[1]]; 254 MemberMirror member = findMirror(type.declaredMembers(), splitName[1]);
230 if (member == null) return new Set(); 255 if (member == null) return new Set();
231 256
232 return new Set.from([member]); 257 return new Set.from([member]);
233 } 258 }
234 259
235 /** 260 /**
236 * Extracts a [Map] from tag names to values from [comment], which is parsed 261 * Extracts a [Map] from tag names to values from [comment], which is parsed
237 * from a Dart source file via dartdoc. Tags are of the form `@NAME VALUE`, 262 * from a Dart source file via dartdoc. Tags are of the form `@NAME VALUE`,
238 * where `NAME` is alphabetic and `VALUE` can contain any character other than 263 * where `NAME` is alphabetic and `VALUE` can contain any character other than
239 * `;`. Multiple tags can be separated by semicolons. 264 * `;`. Multiple tags can be separated by semicolons.
240 * 265 *
241 * At time of writing, the only tag that's used is `@domName`. 266 * At time of writing, the only tag that's used is `@domName`.
242 */ 267 */
243 Map<String, String> _getTags(String comment) { 268 Map<String, String> _getTags(String comment) {
244 if (comment == null) return const <String>{}; 269 if (comment == null) return const <String>{};
245 final re = const RegExp("@([a-zA-Z]+) ([^;]+)(?:;|\$)"); 270 final re = const RegExp("@([a-zA-Z]+) ([^;]+)(?:;|\$)");
246 final tags = <String>{}; 271 final tags = <String>{};
247 for (var m in re.allMatches(comment.trim())) { 272 for (var m in re.allMatches(comment.trim())) {
248 tags[m[1]] = m[2]; 273 tags[m[1]] = m[2];
249 } 274 }
250 return tags; 275 return tags;
251 } 276 }
252 } 277 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698