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

Side by Side Diff: client/html/scripts/html-diff.dart

Issue 8771054: Add a script to generate HTML and DOM docs with cross-links to one another. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: More code review changes. Created 9 years 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * A script to assist in documenting the difference between the dart:html API
7 * and the old DOM API.
8 */
9 #library('renames');
10
11 #import('../../../frog/lang.dart');
12 #import('../../../frog/file_system_node.dart');
13 #import('../../../frog/file_system.dart');
14 #import('../../../utils/dartdoc/dartdoc.dart');
15
16 void main() {
17 HtmlDiff.initWorld('../../frog', new NodeFileSystem());
18 initializeDartDoc();
19 var diff = new HtmlDiff();
20 diff.run();
21
22 diff.domToDart.forEach((domMember, htmlMember) {
23 var domTypeName = domMember.declaringType.name;
24 if (domTypeName == 'DOMWindow') domTypeName = 'Window';
25 var htmlTypeName = htmlMember.declaringType.name.
26 replaceFirst('WrappingImplementation', '');
27 if (domMember.name != htmlMember.name ||
28 domTypeName.replaceFirst(new RegExp('^(HTML|WebKit)'), '') !=
29 htmlTypeName) {
30 var htmlName = '$htmlTypeName.${htmlMember.name}';
31 if (htmlMember.isConstructor || htmlMember.isFactory) {
32 final separator = htmlMember.name == '' ? '' : '.';
33 htmlName = 'new $htmlTypeName$separator${htmlMember.name}';
34 }
35 print('$domTypeName.${domMember.name} -> ${htmlName}');
36 }
37 });
38
39 for (var type in world.dom.types.getValues()) {
40 if (type.name == null) continue;
41 if (type.definition is FunctionTypeDefinition) continue;
42 for (var member in type.members.getValues()) {
43 if (!member.isPrivate && member.name != 'typeName' &&
44 !diff.domToDart.containsKey(member) &&
45 (member is MethodMember || member is PropertyMember)) {
46 print('No dart:html wrapper for ${type.name}.${member.name}');
47 }
48 }
49 }
50 }
51
52 class HtmlDiff {
53 final Map<Member, Member> domToDart;
54
55 static void initWorld(String frogDir, FileSystem files) {
56 parseOptions(frogDir, [] /* args */, files);
57 initializeWorld(files);
58 world.processDartScript('dart:htmlimpl');
59 world.resolveAll();
60 }
61
62 HtmlDiff() : domToDart = <Member, Member>{};
63
64 void run() {
65 final htmlLib = world.libraries['dart:htmlimpl'];
66 for (var htmlType in htmlLib.types.getValues()) {
67 final domType = htmlToDomType(htmlType);
68 final members = new List.from(htmlType.members.getValues());
69 members.addAll(htmlType.constructors.getValues());
70 htmlType.factories.forEach((f) => members.add(f));
71 for (var member in members) {
72 var members = htmlToDomMembers(member, domType);
73 members.forEach((m) => domToDart[m] = member);
74 }
75 }
76 }
77
78 Type htmlToDomType(Type htmlType) {
79 if (htmlType.name == null) return;
80 final tags = _getTags(findComment(htmlType.span));
81
82 if (tags.containsKey('domName')) {
83 var domName = tags['domName'];
84 if (domName == 'none') return;
85 // DOMWindow is Chrome-specific, so we don't use it in our annotations.
86 if (domName == 'Window') domName = 'DOMWindow';
87 final domType = world.dom.types[domName];
88 if (domType == null) print('Warning: no dart:dom type named $domName');
89 return domType;
90 } else {
91 if (!htmlType.name.endsWith('WrappingImplementation')) return;
92 final domName = htmlType.name.replaceFirst('WrappingImplementation', '');
93 var domType = world.dom.types[domName];
94 if (domType == null && domName.endsWith('Element')) {
95 domType = world.dom.types['HTML$domName'];
96 }
97 if (domType == null) domType = world.dom.types['WebKit$domName'];
98 if (domType == null) {
99 print('Warning: no dart:dom type matches dart:htmlimpl ' +
100 htmlType.name);
101 }
102 return domType;
103 }
104 }
105
106 Set<Member> htmlToDomMembers(Member htmlMember, Type domType) {
107 if (htmlMember.isPrivate) return new Set();
108 if (htmlMember is MethodMember) {
109 final tags = _getTags(findComment(htmlMember.span));
110 if (tags.containsKey('domName')) {
111 final domName = tags['domName'];
112 if (domName == 'none') return new Set();
113 return _membersFromName(domName, domType, world.dom);
114 }
115 if (domType == null) return new Set();
116 if (htmlMember.definition == null) return new Set();
117 if (htmlMember.name == 'get:on') {
118 final members = _members(domType.members['addEventListener']);
119 members.addAll(_members(domType.members['dispatchEvent']));
120 members.addAll(_members(domType.members['removeEventListener']));
121 return members;
122 }
123 if (htmlMember.isFactory && htmlMember.name == '' &&
124 domType.name.endsWith('Event')) {
125 return _members(domType.members['init${domType.name}']);
126 }
127 return _members(_getDomMember(htmlMember.definition.body, domType));
128 } else if (htmlMember is PropertyMember) {
129 final members = new Set();
130 if (htmlMember.getter != null) {
131 members.addAll(htmlToDomMembers(htmlMember.getter, domType));
132 }
133 if (htmlMember.setter != null) {
134 members.addAll(htmlToDomMembers(htmlMember.setter, domType));
135 }
136 return members;
137 } else {
138 return new Set();
139 }
140 }
141
142 Set<Member> _membersFromName(String name, Type defaultType, Library library) {
143 if (!name.contains('.', 0)) {
144 if (defaultType == null) {
145 print('Warning: no default type for ${name}');
146 return new Set();
147 }
148 final member = defaultType.members[name];
149 if (member == null) {
150 print('Warning: no member ${defaultType.name}.${name}');
151 }
152 return _members(member);
153 }
154
155 final splitName = name.split('.');
156 if (splitName.length != 2) {
157 print('Warning: invalid member name ${name}');
158 return new Set();
159 }
160 var typeName = splitName[0];
161 if (typeName == 'Window') typeName = 'DOMWindow';
162 final type = library.types[typeName];
163 if (type == null) {
164 print('Warning: no ${library.name} type named ${splitName[0]}');
165 return new Set();
166 }
167 final member = type.members[splitName[1]];
168 if (member == null) {
169 print('Warning: no ${library.name} member named $name');
170 }
171 return _members(member);
172 }
173
174 Set<Member> _members(Member m) => m == null ? new Set() : new Set.from([m]);
175
176 Member _getDomMember(Statement stmt, Type domType) {
177 if (stmt is BlockStatement) {
178 final body = stmt.body.filter((s) => !_ignorableStatement(s));
179 if (body.length != 1) return;
180 return _getDomMember(stmt.body[0], domType);
181 } else if (stmt is ReturnStatement) {
182 return _domMemberFromExpression(stmt.value, domType);
183 } else if (stmt is ExpressionStatement) {
184 return _domMemberFromExpression(stmt.body, domType);
185 } else if (stmt is TryStatement) {
186 return _getDomMember(stmt.body, domType);
187 } else if (stmt is IfStatement) {
188 final trueMember = _getDomMember(stmt.trueBranch, domType);
189 final falseMember = _getDomMember(stmt.falseBranch, domType);
190 if (stmt.falseBranch == null || trueMember == falseMember) {
191 return trueMember;
192 }
193 }
194 }
195
196 /**
197 * Whether a statement can be ignored for the purpose of determining the DOM
198 * name of the enclosing method. The Webkit-to-Dart conversion process leaves
199 * behind various throws and returns that we want to ignore.
200 */
201 bool _ignorableStatement(Statement stmt) {
202 if (stmt is BlockStatement) {
203 return Collections.every(stmt.body, (s) => _ignorableStatement(s));
204 } else if (stmt is TryStatement) {
205 return _ignorableStatement(stmt.body);
206 } else if (stmt is IfStatement) {
207 return _ignorableStatement(stmt.trueBranch) &&
208 _ignorableStatement(stmt.falseBranch);
209 } else if (stmt is ReturnStatement) {
210 return stmt.value == null || stmt.value is ThisExpression;
211 } else {
212 return stmt is ThrowStatement;
213 }
214 }
215
216 Member _domMemberFromExpression(Expression expr, Type domType) {
217 if (expr is BinaryExpression && expr.op.kind == TokenKind.ASSIGN) {
218 return _domMemberFromExpression(expr.x, domType);
219 } else if (expr is CallExpression) {
220 if (expr.target is DotExpression && expr.target.self is VarExpression &&
221 expr.target.self.name.name == 'LevelDom' &&
222 (expr.target.name.name.startsWith('wrap') ||
223 expr.target.name.name == 'unwrap')) {
224 return _domMemberFromExpression(expr.arguments[0].value, domType);
225 }
226 return _domMemberFromExpression(expr.target, domType);
227 } else if (expr is DotExpression) {
228 if (expr.self is NewExpression && expr.name.name == '_wrap' &&
229 expr.self.arguments.length == 1) {
230 return _domMemberFromExpression(expr.self.arguments[0].value, domType);
231 } else if (expr.self is VarExpression && expr.self.name.name == '_ptr') {
232 return domType.members[expr.name.name];
233 }
234 final base = _domMemberFromExpression(expr.self, domType);
235 if (base != null && base.returnType != null) {
236 return base.returnType.members[expr.name.name];
237 }
238 } else if (expr is NewExpression && expr.arguments.length == 1) {
239 return _domMemberFromExpression(expr.arguments[0].value, domType);
240 } else {
241 return null;
242 }
243 }
244
245 Map<String, String> _getTags(String comment) {
246 if (comment == null) return const <String, String>{};
247 final re = new RegExp("@([a-zA-Z]+) ([^;]+)(?:;|\$)");
248 final tags = <String, String>{};
249 for (var m in re.allMatches(comment.trim())) {
250 tags[m[1]] = m[2];
251 }
252 return tags;
253 }
254 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698