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

Side by Side Diff: client/web/ast.dart

Issue 11636011: Web components based app to view dart docs. Still has rough edges. (Closed) Base URL: https://github.com/dart-lang/dart-api-app.git@master
Patch Set: Code review fixes Created 7 years, 11 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
« no previous file with comments | « no previous file | client/web/doc_link.html » ('j') | client/web/element_summary.html » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
Siggi Cherem (dart-lang) 2013/01/02 21:40:55 2013 =)
Jacob 2013/01/03 00:09:33 noooo! that's what i get for taking too long to co
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 * AST describing all information about Dart libraries required to render
7 * Dart documentation.
8 */
1 library ast; 9 library ast;
2 10
3 import 'package:web_ui/safe_html.dart'; 11 import 'package:web_ui/safe_html.dart';
4 import 'markdown.dart' as md; 12 import 'markdown.dart' as md;
5 13
6 /** 14 /**
7 * Top level data model for the app. 15 * Top level data model for the app.
8 * Mapping from String ids to [LibraryElement] objects describing all currently 16 * Mapping from String ids to [LibraryElement] objects describing all currently
9 * loaded libraries. All code must be written to work properly if more libraries 17 * loaded libraries. All code must be written to work properly if more libraries
10 * are loaded incrementally. 18 * are loaded incrementally.
11 */ 19 */
12 Map<String, LibraryElement> libraries = <LibraryElement>{}; 20 Map<String, LibraryElement> libraries = <LibraryElement>{};
13 21
14 List<String> LIBRARY_KINDS = ['variable', 'property', 'method', 'class', 'except ion', 'typedef']; 22 /**
15 List<String> CLASS_KINDS = ['constructor', 'variable', 'property', 'method', 'op erator']; 23 * Children of a library are shown in the UI grouped by type sorted in the order
24 * specified by this list.
25 */
26 List<String> LIBRARY_ITEMS = ['variable', 'property', 'method', 'class',
27 'exception', 'typedef'];
28 /**
29 * Children of a class are shown in the UI grouped by type sorted in the order
30 * specified by this list.
31 */
32 List<String> CLASS_ITEMS = ['constructor', 'variable', 'property', 'method',
33 'operator'];
16 // TODO(jacobr): add package kinds? 34 // TODO(jacobr): add package kinds?
17 35
18 // TODO(jacobr): i18n 36 // TODO(jacobr): i18n
19 /** 37 /**
20 * Pretty names for the various kinds displayed. 38 * Pretty names for the various kinds displayed.
21 */ 39 */
22 final KIND_TITLES = {'property': 'Properties', 40 final KIND_TITLES = {
23 'variable': 'Variables', 41 'property': 'Properties',
24 'method': 'Functions', 42 'variable': 'Variables',
25 'constructor': 'Constructors', 43 'method': 'Functions',
26 'class': 'Classes', 44 'constructor': 'Constructors',
27 'operator': 'Operators', 45 'class': 'Classes',
28 'typedef': 'Typedefs', 46 'operator': 'Operators',
29 'exception': 'Exceptions' 47 'typedef': 'Typedefs',
48 'exception': 'Exceptions'
30 }; 49 };
31 50
32 /** 51 /**
33 * Block of elements to render summary documentation for that all share the
34 * same kind.
35 *
36 * For example, all properties, all functions, or all constructors.
37 */
38 class ElementBlock {
39 String kind;
40 List<Element> elements;
41
42 ElementBlock(this.kind, this.elements);
43
44 String get kindTitle => KIND_TITLES[kind];
45 }
46
47 Reference jsonDeserializeReference(Map json) {
48 return json != null ? new Reference(json) : null;
49 }
50
51 /**
52 * Deserializes JSON into [Element] or [Reference] objects.
53 */
54 Element jsonDeserialize(Map json, Element parent) {
55 if (json == null) return null;
56 if (!json.containsKey('kind')) {
57 throw "Unable to deserialize $json";
58 }
59
60 switch (json['kind']) {
61 case 'class':
62 return new ClassElement(json, parent);
63 case 'typedef':
64 return new TypedefElement(json, parent);
65 case 'typeparam':
66 return new TypeParameterElement(json, parent);
67 case 'library':
68 return new LibraryElement(json, parent);
69 case 'method':
70 return new MethodElement(json, parent);
71 case 'property':
72 return new PropertyElement(json, parent);
73 case 'constructor':
74 return new ConstructorElement(json, parent);
75 case 'variable':
76 return new VariableElement(json, parent);
77 case 'param':
78 return new ParameterElement(json, parent);
79 default:
80 return new Element(json, parent);
81 }
82 }
83
84 List<Element> jsonDeserializeArray(List json, Element parent) {
85 var ret = <Element>[];
86 if (json != null) {
87 for (Map elementJson in json) {
88 ret.add(jsonDeserialize(elementJson, parent));
89 }
90 }
91 return ret;
92 }
93
94 List<Reference> jsonDeserializeReferenceArray(List json) {
95 var ret = <Reference>[];
96 if (json != null) {
97 for (Map referenceJson in json) {
98 ret.add(new Reference(referenceJson));
99 }
100 }
101 return ret;
102 }
103
104 /**
105 * Reference to an [Element]. 52 * Reference to an [Element].
106 */ 53 */
107 class Reference { 54 class Reference {
108 final String refId; 55 final String refId;
109 final String name; 56 final String name;
57 final List<Reference> arguments;
58
110 Reference(Map json) : 59 Reference(Map json) :
111 name = json['name'], 60 name = json['name'],
112 refId = json['refId']; 61 refId = json['refId'],
62 arguments = _jsonDeserializeReferenceArray(json['arguments']);
63
64 /**
65 * Short description appropriate for displaying in a tree control or other
66 * situtation where a short description is required.
67 */
68 String get shortDescription {
69 if (arguments.isEmpty) {
70 return name;
71 } else {
72 var params = Strings.join(
73 arguments.map((param) => param.shortDescription), ', ');
74 return '$name<$params>';
75 }
76 }
113 } 77 }
114 78
115 /** 79 /**
116 * Lookup a library based on the [libraryId]. 80 * Lookup a library based on the [libraryId].
117 *
118 * If the library cannot be found, a stub dummy [Library] will be returned.
119 */ 81 */
120 LibraryElement lookupLibrary(String libraryId) { 82 LibraryElement lookupLibrary(String libraryId) {
121 var library = libraries[libraryId]; 83 return libraries[libraryId];
122 if (library == null) {
123 library = new LibraryElement.stub(libraryId, null);
124 }
125 return library;
126 } 84 }
127 85
128 /** 86 /**
129 * Resolve the [Element] matching the [referenceId]. 87 * Resolve the [Element] matching the [referenceId].
130 * 88 *
131 * If the Element cannot be found, a stub dummy [Element] will be returned. 89 * If the Element cannot be found, a stub dummy [Element] will be returned.
132 */ 90 */
133 Element lookupReferenceId(String referenceId) { 91 Element lookupReferenceId(String referenceId) {
134 var parts = referenceId.split(new RegExp('/')); 92 var parts = referenceId.split(new RegExp('/'));
135 Element current = lookupLibrary(parts.first); 93 Element current = lookupLibrary(parts.first);
136 var result = <Element>[current]; 94 for (var i = 1; i < parts.length && current != null; i++) {
137 for (var i = 1; i < parts.length; i++) {
138 var id = parts[i]; 95 var id = parts[i];
139 var next = null; 96 var next = null;
140 for (var child in current.children) { 97 for (var child in current.children) {
141 if (child.id == id) { 98 if (child.id == id) {
142 next = child; 99 next = child;
143 break; 100 break;
144 } 101 }
145 } 102 }
146 if (next == null) {
147 next = new Element.stub(id, current);
148 }
149 current = next; 103 current = next;
150 } 104 }
151 return current; 105 return current;
152 } 106 }
153 107
154 /** 108 /**
155 * Invoke [callback] on every [Element] in the ast. 109 * Invoke [callback] on every [Element] in the ast.
156 */ 110 */
157 _traverseWorld(void callback(Element)) { 111 _traverseWorld(void callback(Element)) {
158 for (var library in libraries.values) { 112 for (var library in libraries.values) {
159 library.traverse(callback); 113 library.traverse(callback);
160 } 114 }
161 } 115 }
162 116
163 // TODO(jacobr): remove this method when templates handle safe HTML containing 117 // TODO(jacobr): remove this method when templates handle [SafeHTML] containing
118 // multiple top level nodes correct.
164 SafeHtml _markdownToSafeHtml(String text) { 119 SafeHtml _markdownToSafeHtml(String text) {
165 // We currently have to insert an extra span for now because of 120 // We currently have to insert an extra span for now because of
166 // https://github.com/dart-lang/dart-web-components/issues/212 121 // https://github.com/dart-lang/web-ui/issues/212
167 return new SafeHtml.unsafe(text != null && !text.isEmpty ? 122 return new SafeHtml.unsafe(text != null && !text.isEmpty ?
168 '<span>${md.markdownToHtml(text)}</span>' : '<span><span>'); 123 '<span>${md.markdownToHtml(text)}</span>' : '<span><span>');
169 } 124 }
170 125
171 /** 126 /**
172 * Specifies the order elements should appear in the UI.
173 */
174 int elementUiOrder(Element a, Element b) {
175 if (a.isPrivate != b.isPrivate) {
176 return a.isPrivate == true ? 1 : -1;
177 }
178 return a.name.compareTo(b.name);
179 }
180
181 /**
182 * Base class for all elements in the AST. 127 * Base class for all elements in the AST.
183 */ 128 */
184 class Element { 129 class Element implements Comparable {
185 final Element parent; 130 final Element parent;
131
186 /** Human readable type name for the node. */ 132 /** Human readable type name for the node. */
187 final String rawKind; 133 final String rawKind;
134
188 /** Human readable name for the element. */ 135 /** Human readable name for the element. */
189 final String name; 136 final String name;
137
190 /** Id for the node that is unique within its parent's children. */ 138 /** Id for the node that is unique within its parent's children. */
191 final String id; 139 final String id;
140
192 /** Raw text of the comment associated with the Element if any. */ 141 /** Raw text of the comment associated with the Element if any. */
193 final String comment; 142 final String comment;
143
194 /** Whether the node is private. */ 144 /** Whether the node is private. */
195 final bool isPrivate; 145 final bool isPrivate;
196 146
197 final String _uri;
198 final String _line;
199
200 /** Children of the node. */ 147 /** Children of the node. */
201 List<Element> children; 148 List<Element> children;
202 149
203 /** Whether the [Element] is currently being loaded. */ 150 /** Whether the [Element] is currently being loaded. */
204 final bool loading; 151 final bool loading;
205 152
153 final String _uri;
154 final String _line;
206 String _refId; 155 String _refId;
207
208 Map _members;
209 SafeHtml _commentHtml; 156 SafeHtml _commentHtml;
210 List<Element> _references; 157 List<Element> _references;
158 List<Element> _typeParameters;
211 159
212 Element(Map json, this.parent) : 160 Element(Map json, this.parent) :
213 name = json['name'], 161 name = json['name'],
214 rawKind = json['kind'], 162 rawKind = json['kind'],
215 id = json['id'], 163 id = json['id'],
216 comment = json['comment'], 164 comment = json['comment'],
217 isPrivate = json['isPrivate'], 165 isPrivate = json['isPrivate'] == true,
218 _uri = json['uri'], 166 _uri = json['uri'],
219 _line = json['line'], 167 _line = json['line'],
220 loading = false { 168 loading = false {
221 children = jsonDeserializeArray(json['children'], this); 169 children = _jsonDeserializeArray(json['children'], this);
222 } 170 }
223 171
224 /** 172 /**
225 * Returns a kind name that make sense for the UI rather than the AST 173 * Returns a kind name that make sense for the UI rather than the AST
226 * kinds. For example, setters are considered properties instead of 174 * kinds. For example, setters are considered properties instead of
227 * methods. 175 * methods in the UI but not the AST.
228 */ 176 */
229 String get uiKind => kind; 177 String get uiKind => kind;
230 178
179 /**
180 * Longer possibly multiple word description of the [kind].
181 */
182 String get kindDescription => uiKind;
183
231 /** Invoke [callback] on this [Element] and all descendants. */ 184 /** Invoke [callback] on this [Element] and all descendants. */
232 void traverse(void callback(Element)) { 185 void traverse(void callback(Element)) {
233 callback(this); 186 callback(this);
234 for (var child in children) { 187 for (var child in children) {
235 callback(child); 188 callback(child);
236 } 189 }
237 } 190 }
238 191
239 /** 192 /**
240 * Uri containing the definition of the element. 193 * Uri containing the source code for the definition of the element.
241 */ 194 */
242 String get uri { 195 String get uri => _uri != null ? _uri : (parent != null ? parent.uri : null);
243 Element current = this;
244 while (current != null) {
245 if (current._uri != null) return current._uri;
246 current = current.parent;
247 }
248 return null;
249 }
250 196
251 /** 197 /**
252 * Line in the original source file that starts the definition of the element. 198 * Line in the original source file that begins the definition of the element.
253 */ 199 */
254 String get line { 200 String get line => _line != null ?
255 Element current = this; 201 _line : (parent != null ? parent.line : null);
256 while (current != null) {
257 if (current._line != null) return current._line;
258 current = current.parent;
259 }
260 return null;
261 }
262
263 Element.stub(this.id, this.parent) :
264 name = '???', // TODO(jacobr): remove/add
265 _uri = null,
266 _line = null,
267 comment = null,
268 rawKind = null,
269 children = <Element>[],
270 isPrivate = null,
271 loading = true;
272 202
273 /** 203 /**
274 * Globally unique identifier for this element. 204 * Globally unique identifier for this element.
275 */ 205 */
276 String get refId { 206 String get refId {
277 if (_refId == null) { 207 if (_refId == null) {
278 if (parent == null) { 208 _refId = (parent == null) ? id : '${parent.refId}/$id';
279 _refId = id;
280 } else {
281 _refId = '${parent.refId}/$id';
282 }
283 } 209 }
284 return _refId; 210 return _refId;
285 } 211 }
286 212
287 /** 213 /**
288 * Whether this [Element] references the specified [referenceId]. 214 * Whether this [Element] references the specified [referenceId].
289 */ 215 */
290 bool hasReference(String referenceId) { 216 bool hasReference(String referenceId) =>
291 for (var child in children) { 217 children.some((child) => child.hasReference(referenceId));
292 if (child.hasReference(referenceId)) {
293 return true;
294 }
295 }
296 return false;
297 }
298 218
299 /** Returns all [Element]s that reference this [Element]. */ 219 /** Returns all [Element]s that reference this [Element]. */
300 List<Element> get references { 220 List<Element> get references {
301 if (_references == null) { 221 if (_references == null) {
302 _references = <Element>[]; 222 _references = <Element>[];
303 // TODO(jacobr): change to filterWorld and tweak meaning.
304 _traverseWorld((element) { 223 _traverseWorld((element) {
305 if (element.hasReference(refId)) { 224 if (element.hasReference(refId)) {
306 _references.add(element); 225 _references.add(element);
307 } 226 }
308 }); 227 });
309 } 228 }
310 return _references; 229 return _references;
311 } 230 }
312 231
313 // TODO(jacobr): write without recursion. 232 /** Path from the root of the tree to this [Element]. */
314 /** 233 List<Element> get path =>
315 * Path from this [Element] to the root of the tree starting at the root. 234 parent == null ? <Element>[this] : parent.path..add(this);
316 */ 235
317 List<Element> get path { 236 List<Element> get typeParameters {
318 if (parent == null) { 237 if (_typeParameters == null) {
319 return <Element>[this]; 238 _typeParameters = _filterByKind('typeparam');
320 } else {
321 return parent.path..add(this);
322 } 239 }
240 return _typeParameters;
323 } 241 }
324 242
325 /** 243 /**
326 * [SafeHtml] for the comment associated with this [Element] generated from 244 * [SafeHtml] for the comment associated with this [Element] generated from
327 * the markdow comment associated with the element. 245 * the markdow comment associated with the element.
328 */ 246 */
329 SafeHtml get commentHtml { 247 SafeHtml get commentHtml {
330 if (_commentHtml == null) { 248 if (_commentHtml == null) {
331 _commentHtml = _markdownToSafeHtml(comment); 249 _commentHtml = _markdownToSafeHtml(comment);
332 } 250 }
333 return _commentHtml; 251 return _commentHtml;
334 } 252 }
335 253
336 /** 254 /**
337 * Short description appropriate for displaying in a tree control or other 255 * Short description appropriate for displaying in a tree control or other
338 * situtation where a short description is required. 256 * situtation where a short description is required.
339 */ 257 */
340 String get shortDescription => name; 258 String get shortDescription {
259 if (typeParameters.isEmpty) {
260 return name;
261 } else {
262 var params = Strings.join(
263 typeParameters.map((param) => param.shortDescription),
264 ', ');
265 return '$name<$params>';
266 }
267 }
341 268
342 /** Possibly normalized representation of the node kind. */ 269 /**
270 * Ui specific representation of the node kind.
271 * For example, currently operators are considered their own kind even though
272 * they aren't their own kind in the AST.
273 */
343 String get kind => rawKind; 274 String get kind => rawKind;
344 275
345 /** 276 /**
346 * Generate blocks of Elements for each kind in the list of [desiredKinds]. 277 * Generate blocks of Elements for each kind in the list of [desiredKinds].
347 * 278 *
348 * This is helpful when rendering UI that segments members into blocks. 279 * This is helpful when rendering UI that segments members into blocks.
349 * Uses the kind types that make sense for the UI rather than the AST 280 * Uses the kind types that make sense for the UI rather than the AST
350 * kinds. For example, setters are considered properties instead of methods. 281 * kinds. For example, setters are considered properties instead of methods.
351 */ 282 */
352 List<ElementBlock> _createElementBlocks(List<String> desiredKinds) { 283 List<ElementBlock> _createElementBlocks(List<String> desiredKinds) {
353 var blockMap = new Map<String, List<Element>>(); 284 var blockMap = new Map<String, List<Element>>();
354 for (var child in children) { 285 for (var child in children) {
355 if (desiredKinds.contains(child.uiKind)) { 286 if (desiredKinds.contains(child.uiKind)) {
356 blockMap.putIfAbsent(child.uiKind, () => <Element>[]).add(child); 287 blockMap.putIfAbsent(child.uiKind, () => <Element>[]).add(child);
357 } 288 }
358 } 289 }
359 290
360 var blocks = <ElementBlock>[]; 291 var blocks = <ElementBlock>[];
361 for (var kind in desiredKinds) { 292 for (var kind in desiredKinds) {
362 var elements = blockMap[kind]; 293 var elements = blockMap[kind];
363 if (elements != null) { 294 if (elements != null) {
364 blocks.add(new ElementBlock(kind, elements..sort(elementUiOrder))); 295 blocks.add(new ElementBlock(kind, elements..sort()));
365 } 296 }
366 } 297 }
367 return blocks; 298 return blocks;
368 } 299 }
369 300
370 List<Element> _filterByKind(String kind) => 301 List<Element> _filterByKind(String kind) =>
371 children.filter((child) => child.kind == kind); 302 children.filter((child) => child.kind == kind);
372 303
373 Map<String, Element> _mapForKind(String kind) { 304 Map<String, Element> _mapForKind(String kind) {
374 Map ret = {}; 305 Map ret = {};
375 if (children != null) { 306 if (children == null) return ret;
376 for (var child in children) { 307
377 if (child.kind == kind) { 308 for (var child in children) {
378 ret[child.id] = child; 309 if (child.kind == kind) {
379 } 310 ret[child.id] = child;
380 } 311 }
381 } 312 }
382 return ret; 313 return ret;
383 } 314 }
384 315
385 Map<String, Element> _mapForKinds(Map<String, Element> kinds) { 316 /**
386 Map ret = {}; 317 * Specifies the order elements should appear in the UI.
387 if (children != null) { 318 */
388 for (var child in children) { 319 int compareTo(Element other) {
389 if (kinds.containsKey(child.kind)) { 320 if (isPrivate != other.isPrivate) {
390 ret[child.id] = child; 321 return other.isPrivate ? 1 : -1;
391 }
392 }
393 } 322 }
394 return ret; 323 return name.compareTo(other.name);
395 }
396
397 Map<String, Element> get members {
398 if (_members == null) {
399 // TODO(jacobr): include properties???!?
400 _members = _mapForKinds({'method': true, 'property' : true});
401 }
402 return _members;
403 } 324 }
404 } 325 }
405 326
406 /** 327 /**
407 * [Element] describing a Dart library. 328 * [Element] describing a Dart library.
408 * 329 *
409 * Adds convenience helpers for quickly accessing data about libraries. 330 * Adds convenience helpers for quickly accessing data about libraries.
410 */ 331 */
411 class LibraryElement extends Element { 332 class LibraryElement extends Element {
412 Map<String, ClassElement> _classes; 333 Map<String, ClassElement> _classes;
413 List<ClassElement> _sortedClasses; 334 List<ClassElement> _sortedClasses;
414 List<ElementBlock> _childBlocks; 335 List<ElementBlock> _childBlocks;
415 336
416 LibraryElement(json, Element parent) : super(json, parent); 337 LibraryElement(json, Element parent) : super(json, parent);
417 LibraryElement.stub(String id, Element parent) : super.stub(id, parent);
418 338
419 /** Returns all classes defined by the library. */ 339 /** Returns all classes defined by the library. */
420 Map<String, ClassElement> get classes { 340 Map<String, ClassElement> get classes {
421 if (_classes == null) { 341 if (_classes == null) {
422 _classes = _mapForKind('class'); 342 _classes = _mapForKind('class');
423 } 343 }
424 return _classes; 344 return _classes;
425 } 345 }
426 346
427 /** 347 /**
428 * Returns all classes defined by the library sorted name and whether they 348 * Returns all classes defined by the library sorted name and whether they
429 * are private. 349 * are private.
430 */ 350 */
431 List<ClassElement> get sortedClasses { 351 List<ClassElement> get sortedClasses {
432 if (_sortedClasses == null) { 352 if (_sortedClasses == null) {
433 _sortedClasses = []..addAll(classes.values)..sort(elementUiOrder); 353 _sortedClasses = []..addAll(classes.values)..sort();
434 } 354 }
435 return _sortedClasses; 355 return _sortedClasses;
436 } 356 }
437 357
438 /** 358 /**
439 * Returns all blocks of elements that should be rendered by UI summarizing 359 * Returns all blocks of elements that should be rendered by UI summarizing
440 * the Library. 360 * the Library.
441 */ 361 */
442 List<ElementBlock> get childBlocks { 362 List<ElementBlock> get childBlocks {
443 if (_childBlocks == null) _childBlocks = _createElementBlocks(LIBRARY_KINDS) ; 363 if (_childBlocks == null) {
364 _childBlocks = _createElementBlocks(LIBRARY_ITEMS);
365 }
444 return _childBlocks; 366 return _childBlocks;
445 } 367 }
446 } 368 }
447 369
448 /** 370 /**
449 * [Element] describing a Dart class. 371 * [Element] describing a Dart class.
450 */ 372 */
451 class ClassElement extends Element { 373 class ClassElement extends Element {
374
452 /** Members of the class grouped into logical blocks. */ 375 /** Members of the class grouped into logical blocks. */
453 List<ElementBlock> _childBlocks; 376 List<ElementBlock> _childBlocks;
377
454 /** Interfaces the class implements. */ 378 /** Interfaces the class implements. */
455 final List<Reference> interfaces; 379 final List<Reference> interfaces;
380
456 /** Superclass of this class. */ 381 /** Superclass of this class. */
457 final Reference superclass; 382 final Reference superclass;
458 383
384 /** Whether the class is abstract. */
385 final bool isAbstract;
386
459 List<ClassElement> _superclasses; 387 List<ClassElement> _superclasses;
460 List<ClassElement> _subclasses; 388 List<ClassElement> _subclasses;
461 389
462 ClassElement(Map json, Element parent) 390 ClassElement(Map json, Element parent)
463 : super(json, parent), 391 : super(json, parent),
464 interfaces = jsonDeserializeReferenceArray(json['interfaces']), 392 interfaces = _jsonDeserializeReferenceArray(json['interfaces']),
465 superclass = jsonDeserializeReference(json['superclass']); 393 superclass = jsonDeserializeReference(json['superclass']),
466 394 isAbstract = json['isAbstract'] == true;
467 ClassElement.stub(String id, Element parent)
468 : super.stub(id, parent),
469 interfaces = [],
470 superclass = null;
471 395
472 /** Returns all superclasses of this class. */ 396 /** Returns all superclasses of this class. */
473 List<ClassElement> get superclasses { 397 List<ClassElement> get superclasses {
474 if (_superclasses == null) { 398 if (_superclasses == null) {
475 _superclasses = <ClassElement>[]; 399 _superclasses = <ClassElement>[];
476 addSuperclasses(clazz) { 400 addSuperclasses(clazz) {
477 if (clazz.superclass != null) { 401 if (clazz.superclass != null) {
478 ClassElement superclassElement = 402 ClassElement superclassElement =
479 lookupReferenceId(clazz.superclass.refId); 403 lookupReferenceId(clazz.superclass.refId);
480 addSuperclasses(superclassElement); 404 addSuperclasses(superclassElement);
481 _superclasses.add(superclassElement); 405 _superclasses.add(superclassElement);
482 } 406 }
483 } 407 }
484 addSuperclasses(this); 408 addSuperclasses(this);
485 } 409 }
486 return _superclasses; 410 return _superclasses;
487 } 411 }
488 412
413 String get kindDescription =>
414 isAbstract ? 'abstract $uiKind' : uiKind;
415
489 /** 416 /**
490 * Returns classes that directly extend or implement this class. 417 * Returns classes that directly extend or implement this class.
491 */ 418 */
492 List<ClassElement> get subclasses { 419 List<ClassElement> get subclasses {
493 if (_subclasses == null) { 420 if (_subclasses == null) {
494 _subclasses = <ClassElement>[]; 421 _subclasses = <ClassElement>[];
495 for (var library in libraries.values) { 422 for (var library in libraries.values) {
496 for (ClassElement candidateClass in library.sortedClasses) { 423 for (ClassElement candidateClass in library.sortedClasses) {
497 if (candidateClass.implementsOrExtends(refId)) { 424 if (candidateClass.implementsOrExtends(refId)) {
498 _subclasses.add(candidateClass); 425 _subclasses.add(candidateClass);
(...skipping 13 matching lines...) Expand all
512 if (interface.refId == referenceId) return true; 439 if (interface.refId == referenceId) return true;
513 } 440 }
514 return superclass != null && superclass.refId == referenceId; 441 return superclass != null && superclass.refId == referenceId;
515 } 442 }
516 443
517 /** 444 /**
518 * Returns blocks of elements clustered by kind ordered in the desired 445 * Returns blocks of elements clustered by kind ordered in the desired
519 * order for describing a class definition. 446 * order for describing a class definition.
520 */ 447 */
521 List<ElementBlock> get childBlocks { 448 List<ElementBlock> get childBlocks {
522 if (_childBlocks == null) _childBlocks = _createElementBlocks(CLASS_KINDS); 449 if (_childBlocks == null) _childBlocks = _createElementBlocks(CLASS_ITEMS);
523 return _childBlocks; 450 return _childBlocks;
524 } 451 }
525 } 452 }
526 453
454 /**
455 * Element describing a typedef.
456 */
527 class TypedefElement extends Element { 457 class TypedefElement extends Element {
528 final Reference returnType; 458 final Reference returnType;
529 List<ParameterElement> _parameters; 459 List<Element> _parameters;
530 460
531 TypedefElement(Map json, Element parent) : super(json, parent), 461 TypedefElement(Map json, Element parent) : super(json, parent),
532 returnType = jsonDeserializeReference(json['returnType']); 462 returnType = jsonDeserializeReference(json['returnType']);
533 463
534 /** 464 /**
535 * Returns a list of the parameters of the typedef. 465 * Returns a list of the parameters of the typedef.
536 */ 466 */
537 List<ParameterElement> get parameters { 467 List<Element> get parameters {
538 if (_parameters == null) { 468 if (_parameters == null) {
539 _parameters = _filterByKind('param'); 469 _parameters = _filterByKind('param');
540 } 470 }
541 return _parameters; 471 return _parameters;
542 } 472 }
543 } 473 }
544 474
545 /** 475 /**
546 * [Element] describing a method which may be a regular method, a setter, or an 476 * [Element] describing a method which may be a regular method, a setter, or an
547 * operator. 477 * operator.
(...skipping 16 matching lines...) Expand all
564 } 494 }
565 495
566 String get uiKind => isSetter ? 'property' : kind; 496 String get uiKind => isSetter ? 'property' : kind;
567 497
568 /** 498 /**
569 * Returns a plain text short description of the method suitable for rendering 499 * Returns a plain text short description of the method suitable for rendering
570 * in a tree control or other case where a short method description is 500 * in a tree control or other case where a short method description is
571 * required. 501 * required.
572 */ 502 */
573 String get shortDescription { 503 String get shortDescription {
574 if (isSetter == true) { 504 if (isSetter) {
575 var sb = new StringBuffer('${name.substring(0, name.length-1)}'); 505 var sb = new StringBuffer('${name.substring(0, name.length - 1)}');
576 if (!parameters.isEmpty && parameters.first != null 506 if (!parameters.isEmpty && parameters.first != null
577 && parameters.first.type != null) { 507 && parameters.first.type != null) {
578 sb..add(' ')..add(parameters.first.type.name); 508 sb..add(' ')..add(parameters.first.type.name);
579 } 509 }
580 return sb.toString(); 510 return sb.toString();
581 } 511 }
582 return '$name(${Strings.join(parameters.map( 512 return '$name(${Strings.join(parameters.map(
583 (arg) => arg.type != null ? arg.type.name : ''), ', ')})'; 513 (arg) => arg.type != null ? arg.type.name : ''), ', ')})';
584 } 514 }
585 515
586 Reference get returnType; 516 Reference get returnType;
587 List<ParameterElement> _parameters; 517 List<Element> _parameters;
588 518
589 /** 519 /**
590 * Returns a list of the parameters of the Method. 520 * Returns a list of the parameters of the Method.
591 */ 521 */
592 List<ParameterElement> get parameters { 522 List<Element> get parameters {
593 if (_parameters == null) { 523 if (_parameters == null) {
594 _parameters = _filterByKind('param'); 524 _parameters = _filterByKind('param');
595 } 525 }
596 return _parameters; 526 return _parameters;
597 } 527 }
598 528
599 // For UI purposes we want to treat operators as their own kind. 529 /// For UI purposes we want to treat operators as their own kind.
600 String get kind => isOperator ? 'operator' : rawKind; 530 String get kind => isOperator ? 'operator' : rawKind;
601 } 531 }
602 532
603 /** 533 /**
604 * Element describing a parameter. 534 * Element describing a parameter.
605 */ 535 */
606 class ParameterElement extends Element { 536 class ParameterElement extends Element {
607 /** Type of the parameter. */ 537 /** Type of the parameter. */
608 final Reference type; 538 final Reference type;
609 /** Whether the parameter is optional. */ 539 /** Whether the parameter is optional. */
(...skipping 14 matching lines...) Expand all
624 * Element describing a generic type parameter. 554 * Element describing a generic type parameter.
625 */ 555 */
626 class TypeParameterElement extends Element { 556 class TypeParameterElement extends Element {
627 /** Upper bound for the parameter. */ 557 /** Upper bound for the parameter. */
628 Reference upperBound; 558 Reference upperBound;
629 559
630 TypeParameterElement(Map json, Element parent) : 560 TypeParameterElement(Map json, Element parent) :
631 super(json, parent), 561 super(json, parent),
632 upperBound = jsonDeserializeReference(json['upperBound']); 562 upperBound = jsonDeserializeReference(json['upperBound']);
633 563
564 String get shortDescription {
565 if (upperBound == null) {
566 return name;
567 } else {
568 return '$name extends ${upperBound.shortDescription}';
569 }
570 }
571
634 bool hasReference(String referenceId) { 572 bool hasReference(String referenceId) {
635 if (super.hasReference(referenceId)) return true; 573 if (super.hasReference(referenceId)) return true;
636 return upperBound != null && upperBound.refId == referenceId; 574 return upperBound != null && upperBound.refId == referenceId;
637 } 575 }
638 } 576 }
639 577
578 /**
579 * Element describing a method.
580 */
640 class MethodElement extends MethodElementBase { 581 class MethodElement extends MethodElementBase {
641 582
642 final Reference returnType; 583 final Reference returnType;
643 584
644 MethodElement(Map json, Element parent) : super(json, parent), 585 MethodElement(Map json, Element parent) : super(json, parent),
645 returnType = jsonDeserializeReference(json['returnType']); 586 returnType = jsonDeserializeReference(json['returnType']);
646 } 587 }
647 588
589 /**
590 * Element describing a property getter.
591 */
648 class PropertyElement extends MethodElementBase { 592 class PropertyElement extends MethodElementBase {
649 final Reference returnType; 593 final Reference returnType;
650 594
651 String get shortDescription => name; 595 String get shortDescription => name;
652 596
653 PropertyElement(Map json, Element parent) : super(json, parent), 597 PropertyElement(Map json, Element parent) : super(json, parent),
654 returnType = jsonDeserializeReference(json['ref']); 598 returnType = jsonDeserializeReference(json['ref']);
655 } 599 }
656 600
601 /**
602 * Element describing a variable.
603 */
657 class VariableElement extends MethodElementBase { 604 class VariableElement extends MethodElementBase {
658 final Reference returnType; 605 final Reference returnType;
659 /** Whether this variable is final. */ 606 /** Whether this variable is final. */
660 final bool isFinal; 607 final bool isFinal;
661 608
662 String get shortDescription => name; 609 String get shortDescription => name;
663 610
664 VariableElement(Map json, Element parent) : super(json, parent), 611 VariableElement(Map json, Element parent) : super(json, parent),
665 returnType = jsonDeserializeReference(json['ref']), 612 returnType = jsonDeserializeReference(json['ref']),
666 isFinal = json['isFinal']; 613 isFinal = json['isFinal'];
667 } 614 }
668 615
616 /**
617 * Element describing a constructor.
618 */
669 class ConstructorElement extends MethodElementBase { 619 class ConstructorElement extends MethodElementBase {
670 ConstructorElement(json, Element parent) : super(json, parent); 620 ConstructorElement(json, Element parent) : super(json, parent);
671 621
672 Reference get returnType => null; 622 Reference get returnType => null;
673 } 623 }
624
625 /**
626 * Block of elements to render summary documentation for all elements that share
627 * the same kind.
628 *
629 * For example, all properties, all functions, or all constructors.
630 */
631 class ElementBlock {
632 String kind;
633 List<Element> elements;
634
635 ElementBlock(this.kind, this.elements);
636
637 String get kindTitle => KIND_TITLES[kind];
638 }
639
640 Reference jsonDeserializeReference(Map json) {
641 return json != null ? new Reference(json) : null;
642 }
643
644 /**
645 * Deserializes JSON into an [Element] object.
646 */
647 Element jsonDeserialize(Map json, Element parent) {
648 if (json == null) return null;
649
650 var kind = json['kind'];
651 if (kind == null) {
652 throw "Unable to deserialize $json";
653 }
654
655 switch (kind) {
656 case 'class':
657 return new ClassElement(json, parent);
658 case 'typedef':
659 return new TypedefElement(json, parent);
660 case 'typeparam':
661 return new TypeParameterElement(json, parent);
662 case 'library':
663 return new LibraryElement(json, parent);
664 case 'method':
665 return new MethodElement(json, parent);
666 case 'property':
667 return new PropertyElement(json, parent);
668 case 'constructor':
669 return new ConstructorElement(json, parent);
670 case 'variable':
671 return new VariableElement(json, parent);
672 case 'param':
673 return new ParameterElement(json, parent);
674 default:
675 return new Element(json, parent);
676 }
677 }
678
679 List<Element> _jsonDeserializeArray(List json, Element parent) {
680 var ret = <Element>[];
681 if (json == null) return ret;
682
683 for (Map elementJson in json) {
684 ret.add(jsonDeserialize(elementJson, parent));
685 }
686 return ret;
687 }
688
689 List<Reference> _jsonDeserializeReferenceArray(List json) {
690 var ret = <Reference>[];
691 if (json == null) return ret;
692
693 for (Map referenceJson in json) {
694 ret.add(new Reference(referenceJson));
695 }
696 return ret;
697 }
OLDNEW
« no previous file with comments | « no previous file | client/web/doc_link.html » ('j') | client/web/element_summary.html » ('J')

Powered by Google App Engine
This is Rietveld 408576698