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

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: more 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') | 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) 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 * 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 /**
315 * Path from this [Element] to the root of the tree starting at the root.
316 */
317 List<Element> get path { 233 List<Element> get path {
318 if (parent == null) { 234 if (parent == null) {
319 return <Element>[this]; 235 return <Element>[this];
320 } else { 236 } else {
321 return parent.path..add(this); 237 return parent.path..add(this);
322 } 238 }
239 // TODO(jacobr): replace this code with:
240 // return parent == null ? <Element>[this]) : parent.path..add(this);
241 // once http://code.google.com/p/dart/issues/detail?id=7665 is fixed.
242 }
243
244 List<Element> get typeParameters {
245 if (_typeParameters == null) {
246 _typeParameters = _filterByKind('typeparam');
247 }
248 return _typeParameters;
323 } 249 }
324 250
325 /** 251 /**
326 * [SafeHtml] for the comment associated with this [Element] generated from 252 * [SafeHtml] for the comment associated with this [Element] generated from
327 * the markdow comment associated with the element. 253 * the markdow comment associated with the element.
328 */ 254 */
329 SafeHtml get commentHtml { 255 SafeHtml get commentHtml {
330 if (_commentHtml == null) { 256 if (_commentHtml == null) {
331 _commentHtml = _markdownToSafeHtml(comment); 257 _commentHtml = _markdownToSafeHtml(comment);
332 } 258 }
333 return _commentHtml; 259 return _commentHtml;
334 } 260 }
335 261
336 /** 262 /**
337 * Short description appropriate for displaying in a tree control or other 263 * Short description appropriate for displaying in a tree control or other
338 * situtation where a short description is required. 264 * situtation where a short description is required.
339 */ 265 */
340 String get shortDescription => name; 266 String get shortDescription {
267 if (typeParameters.isEmpty) {
268 return name;
269 } else {
270 var params = Strings.join(
271 typeParameters.map((param) => param.shortDescription),
272 ', ');
273 return '$name<$params>';
274 }
275 }
341 276
342 /** Possibly normalized representation of the node kind. */ 277 /**
278 * Ui specific representation of the node kind.
279 * For example, currently operators are considered their own kind even though
280 * they aren't their own kind in the AST.
281 */
343 String get kind => rawKind; 282 String get kind => rawKind;
344 283
345 /** 284 /**
346 * Generate blocks of Elements for each kind in the list of [desiredKinds]. 285 * Generate blocks of Elements for each kind in the list of [desiredKinds].
347 * 286 *
348 * This is helpful when rendering UI that segments members into blocks. 287 * 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 288 * 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. 289 * kinds. For example, setters are considered properties instead of methods.
351 */ 290 */
352 List<ElementBlock> _createElementBlocks(List<String> desiredKinds) { 291 List<ElementBlock> _createElementBlocks(List<String> desiredKinds) {
353 var blockMap = new Map<String, List<Element>>(); 292 var blockMap = new Map<String, List<Element>>();
354 for (var child in children) { 293 for (var child in children) {
355 if (desiredKinds.contains(child.uiKind)) { 294 if (desiredKinds.contains(child.uiKind)) {
356 blockMap.putIfAbsent(child.uiKind, () => <Element>[]).add(child); 295 blockMap.putIfAbsent(child.uiKind, () => <Element>[]).add(child);
357 } 296 }
358 } 297 }
359 298
360 var blocks = <ElementBlock>[]; 299 var blocks = <ElementBlock>[];
361 for (var kind in desiredKinds) { 300 for (var kind in desiredKinds) {
362 var elements = blockMap[kind]; 301 var elements = blockMap[kind];
363 if (elements != null) { 302 if (elements != null) {
364 blocks.add(new ElementBlock(kind, elements..sort(elementUiOrder))); 303 blocks.add(new ElementBlock(kind, elements..sort()));
365 } 304 }
366 } 305 }
367 return blocks; 306 return blocks;
368 } 307 }
369 308
370 List<Element> _filterByKind(String kind) => 309 List<Element> _filterByKind(String kind) =>
371 children.filter((child) => child.kind == kind); 310 children.filter((child) => child.kind == kind);
372 311
373 Map<String, Element> _mapForKind(String kind) { 312 Map<String, Element> _mapForKind(String kind) {
374 Map ret = {}; 313 Map ret = {};
375 if (children != null) { 314 if (children == null) return ret;
376 for (var child in children) { 315
377 if (child.kind == kind) { 316 for (var child in children) {
378 ret[child.id] = child; 317 if (child.kind == kind) {
379 } 318 ret[child.id] = child;
380 } 319 }
381 } 320 }
382 return ret; 321 return ret;
383 } 322 }
384 323
385 Map<String, Element> _mapForKinds(Map<String, Element> kinds) { 324 /**
386 Map ret = {}; 325 * Specifies the order elements should appear in the UI.
387 if (children != null) { 326 */
388 for (var child in children) { 327 int compareTo(Element other) {
389 if (kinds.containsKey(child.kind)) { 328 if (isPrivate != other.isPrivate) {
390 ret[child.id] = child; 329 return other.isPrivate ? 1 : -1;
391 }
392 }
393 } 330 }
394 return ret; 331 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 } 332 }
404 } 333 }
405 334
406 /** 335 /**
407 * [Element] describing a Dart library. 336 * [Element] describing a Dart library.
408 * 337 *
409 * Adds convenience helpers for quickly accessing data about libraries. 338 * Adds convenience helpers for quickly accessing data about libraries.
410 */ 339 */
411 class LibraryElement extends Element { 340 class LibraryElement extends Element {
412 Map<String, ClassElement> _classes; 341 Map<String, ClassElement> _classes;
413 List<ClassElement> _sortedClasses; 342 List<ClassElement> _sortedClasses;
414 List<ElementBlock> _childBlocks; 343 List<ElementBlock> _childBlocks;
415 344
416 LibraryElement(json, Element parent) : super(json, parent); 345 LibraryElement(json, Element parent) : super(json, parent);
417 LibraryElement.stub(String id, Element parent) : super.stub(id, parent);
418 346
419 /** Returns all classes defined by the library. */ 347 /** Returns all classes defined by the library. */
420 Map<String, ClassElement> get classes { 348 Map<String, ClassElement> get classes {
421 if (_classes == null) { 349 if (_classes == null) {
422 _classes = _mapForKind('class'); 350 _classes = _mapForKind('class');
423 } 351 }
424 return _classes; 352 return _classes;
425 } 353 }
426 354
427 /** 355 /**
428 * Returns all classes defined by the library sorted name and whether they 356 * Returns all classes defined by the library sorted name and whether they
429 * are private. 357 * are private.
430 */ 358 */
431 List<ClassElement> get sortedClasses { 359 List<ClassElement> get sortedClasses {
432 if (_sortedClasses == null) { 360 if (_sortedClasses == null) {
433 _sortedClasses = []..addAll(classes.values)..sort(elementUiOrder); 361 _sortedClasses = []..addAll(classes.values)..sort();
434 } 362 }
435 return _sortedClasses; 363 return _sortedClasses;
436 } 364 }
437 365
438 /** 366 /**
439 * Returns all blocks of elements that should be rendered by UI summarizing 367 * Returns all blocks of elements that should be rendered by UI summarizing
440 * the Library. 368 * the Library.
441 */ 369 */
442 List<ElementBlock> get childBlocks { 370 List<ElementBlock> get childBlocks {
443 if (_childBlocks == null) _childBlocks = _createElementBlocks(LIBRARY_KINDS) ; 371 if (_childBlocks == null) {
372 _childBlocks = _createElementBlocks(LIBRARY_ITEMS);
373 }
444 return _childBlocks; 374 return _childBlocks;
445 } 375 }
446 } 376 }
447 377
448 /** 378 /**
449 * [Element] describing a Dart class. 379 * [Element] describing a Dart class.
450 */ 380 */
451 class ClassElement extends Element { 381 class ClassElement extends Element {
382
452 /** Members of the class grouped into logical blocks. */ 383 /** Members of the class grouped into logical blocks. */
453 List<ElementBlock> _childBlocks; 384 List<ElementBlock> _childBlocks;
385
454 /** Interfaces the class implements. */ 386 /** Interfaces the class implements. */
455 final List<Reference> interfaces; 387 final List<Reference> interfaces;
388
456 /** Superclass of this class. */ 389 /** Superclass of this class. */
457 final Reference superclass; 390 final Reference superclass;
458 391
392 /** Whether the class is abstract. */
393 final bool isAbstract;
394
459 List<ClassElement> _superclasses; 395 List<ClassElement> _superclasses;
460 List<ClassElement> _subclasses; 396 List<ClassElement> _subclasses;
461 397
462 ClassElement(Map json, Element parent) 398 ClassElement(Map json, Element parent)
463 : super(json, parent), 399 : super(json, parent),
464 interfaces = jsonDeserializeReferenceArray(json['interfaces']), 400 interfaces = _jsonDeserializeReferenceArray(json['interfaces']),
465 superclass = jsonDeserializeReference(json['superclass']); 401 superclass = jsonDeserializeReference(json['superclass']),
466 402 isAbstract = json['isAbstract'] == true;
467 ClassElement.stub(String id, Element parent)
468 : super.stub(id, parent),
469 interfaces = [],
470 superclass = null;
471 403
472 /** Returns all superclasses of this class. */ 404 /** Returns all superclasses of this class. */
473 List<ClassElement> get superclasses { 405 List<ClassElement> get superclasses {
474 if (_superclasses == null) { 406 if (_superclasses == null) {
475 _superclasses = <ClassElement>[]; 407 _superclasses = <ClassElement>[];
476 addSuperclasses(clazz) { 408 addSuperclasses(clazz) {
477 if (clazz.superclass != null) { 409 if (clazz.superclass != null) {
478 ClassElement superclassElement = 410 var superclassElement = lookupReferenceId(clazz.superclass.refId);
479 lookupReferenceId(clazz.superclass.refId);
480 addSuperclasses(superclassElement); 411 addSuperclasses(superclassElement);
481 _superclasses.add(superclassElement); 412 _superclasses.add(superclassElement);
482 } 413 }
483 } 414 }
484 addSuperclasses(this); 415 addSuperclasses(this);
485 } 416 }
486 return _superclasses; 417 return _superclasses;
487 } 418 }
488 419
420 String get kindDescription =>
421 isAbstract ? 'abstract $uiKind' : uiKind;
422
489 /** 423 /**
490 * Returns classes that directly extend or implement this class. 424 * Returns classes that directly extend or implement this class.
491 */ 425 */
492 List<ClassElement> get subclasses { 426 List<ClassElement> get subclasses {
493 if (_subclasses == null) { 427 if (_subclasses == null) {
494 _subclasses = <ClassElement>[]; 428 _subclasses = <ClassElement>[];
495 for (var library in libraries.values) { 429 for (var library in libraries.values) {
496 for (ClassElement candidateClass in library.sortedClasses) { 430 for (ClassElement candidateClass in library.sortedClasses) {
497 if (candidateClass.implementsOrExtends(refId)) { 431 if (candidateClass.implementsOrExtends(refId)) {
498 _subclasses.add(candidateClass); 432 _subclasses.add(candidateClass);
(...skipping 13 matching lines...) Expand all
512 if (interface.refId == referenceId) return true; 446 if (interface.refId == referenceId) return true;
513 } 447 }
514 return superclass != null && superclass.refId == referenceId; 448 return superclass != null && superclass.refId == referenceId;
515 } 449 }
516 450
517 /** 451 /**
518 * Returns blocks of elements clustered by kind ordered in the desired 452 * Returns blocks of elements clustered by kind ordered in the desired
519 * order for describing a class definition. 453 * order for describing a class definition.
520 */ 454 */
521 List<ElementBlock> get childBlocks { 455 List<ElementBlock> get childBlocks {
522 if (_childBlocks == null) _childBlocks = _createElementBlocks(CLASS_KINDS); 456 if (_childBlocks == null) _childBlocks = _createElementBlocks(CLASS_ITEMS);
523 return _childBlocks; 457 return _childBlocks;
524 } 458 }
525 } 459 }
526 460
461 /**
462 * Element describing a typedef.
463 */
527 class TypedefElement extends Element { 464 class TypedefElement extends Element {
528 final Reference returnType; 465 final Reference returnType;
529 List<ParameterElement> _parameters; 466 List<Element> _parameters;
530 467
531 TypedefElement(Map json, Element parent) : super(json, parent), 468 TypedefElement(Map json, Element parent) : super(json, parent),
532 returnType = jsonDeserializeReference(json['returnType']); 469 returnType = jsonDeserializeReference(json['returnType']);
533 470
534 /** 471 /**
535 * Returns a list of the parameters of the typedef. 472 * Returns a list of the parameters of the typedef.
536 */ 473 */
537 List<ParameterElement> get parameters { 474 List<Element> get parameters {
538 if (_parameters == null) { 475 if (_parameters == null) {
539 _parameters = _filterByKind('param'); 476 _parameters = _filterByKind('param');
540 } 477 }
541 return _parameters; 478 return _parameters;
542 } 479 }
543 } 480 }
544 481
545 /** 482 /**
546 * [Element] describing a method which may be a regular method, a setter, or an 483 * [Element] describing a method which may be a regular method, a setter, or an
547 * operator. 484 * operator.
548 */ 485 */
549 abstract class MethodElementBase extends Element { 486 abstract class MethodLikeElement extends Element {
550 487
551 final bool isOperator; 488 final bool isOperator;
552 final bool isStatic; 489 final bool isStatic;
553 final bool isSetter; 490 final bool isSetter;
554 491
555 MethodElementBase(Map json, Element parent) 492 MethodLikeElement(Map json, Element parent)
556 : super(json, parent), 493 : super(json, parent),
557 isOperator = json['isOperator'] == true, 494 isOperator = json['isOperator'] == true,
558 isStatic = json['isStatic'] == true, 495 isStatic = json['isStatic'] == true,
559 isSetter = json['isSetter'] == true; 496 isSetter = json['isSetter'] == true;
560 497
561 bool hasReference(String referenceId) { 498 bool hasReference(String referenceId) {
562 if (super.hasReference(referenceId)) return true; 499 if (super.hasReference(referenceId)) return true;
563 return returnType != null && returnType.refId == referenceId; 500 return returnType != null && returnType.refId == referenceId;
564 } 501 }
565 502
566 String get uiKind => isSetter ? 'property' : kind; 503 String get uiKind => isSetter ? 'property' : kind;
567 504
568 /** 505 /**
569 * Returns a plain text short description of the method suitable for rendering 506 * 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 507 * in a tree control or other case where a short method description is
571 * required. 508 * required.
572 */ 509 */
573 String get shortDescription { 510 String get shortDescription {
574 if (isSetter == true) { 511 if (isSetter) {
575 var sb = new StringBuffer('${name.substring(0, name.length-1)}'); 512 var sb = new StringBuffer('${name.substring(0, name.length - 1)}');
576 if (!parameters.isEmpty && parameters.first != null 513 if (!parameters.isEmpty && parameters.first != null
577 && parameters.first.type != null) { 514 && parameters.first.type != null) {
578 sb..add(' ')..add(parameters.first.type.name); 515 sb..add(' ')..add(parameters.first.type.name);
579 } 516 }
580 return sb.toString(); 517 return sb.toString();
581 } 518 }
582 return '$name(${Strings.join(parameters.map( 519 return '$name(${Strings.join(parameters.map(
583 (arg) => arg.type != null ? arg.type.name : ''), ', ')})'; 520 (arg) => arg.type != null ? arg.type.name : ''), ', ')})';
584 } 521 }
585 522
586 Reference get returnType; 523 Reference get returnType;
587 List<ParameterElement> _parameters; 524 List<Element> _parameters;
588 525
589 /** 526 /**
590 * Returns a list of the parameters of the Method. 527 * Returns a list of the parameters of the Method.
591 */ 528 */
592 List<ParameterElement> get parameters { 529 List<Element> get parameters {
593 if (_parameters == null) { 530 if (_parameters == null) {
594 _parameters = _filterByKind('param'); 531 _parameters = _filterByKind('param');
595 } 532 }
596 return _parameters; 533 return _parameters;
597 } 534 }
598 535
599 // For UI purposes we want to treat operators as their own kind. 536 /// For UI purposes we want to treat operators as their own kind.
600 String get kind => isOperator ? 'operator' : rawKind; 537 String get kind => isOperator ? 'operator' : rawKind;
601 } 538 }
602 539
603 /** 540 /**
604 * Element describing a parameter. 541 * Element describing a parameter.
605 */ 542 */
606 class ParameterElement extends Element { 543 class ParameterElement extends Element {
607 /** Type of the parameter. */ 544 /** Type of the parameter. */
608 final Reference type; 545 final Reference type;
609 /** Whether the parameter is optional. */ 546 /** Whether the parameter is optional. */
(...skipping 14 matching lines...) Expand all
624 * Element describing a generic type parameter. 561 * Element describing a generic type parameter.
625 */ 562 */
626 class TypeParameterElement extends Element { 563 class TypeParameterElement extends Element {
627 /** Upper bound for the parameter. */ 564 /** Upper bound for the parameter. */
628 Reference upperBound; 565 Reference upperBound;
629 566
630 TypeParameterElement(Map json, Element parent) : 567 TypeParameterElement(Map json, Element parent) :
631 super(json, parent), 568 super(json, parent),
632 upperBound = jsonDeserializeReference(json['upperBound']); 569 upperBound = jsonDeserializeReference(json['upperBound']);
633 570
571 String get shortDescription {
572 if (upperBound == null) {
573 return name;
574 } else {
575 return '$name extends ${upperBound.shortDescription}';
576 }
577 }
578
634 bool hasReference(String referenceId) { 579 bool hasReference(String referenceId) {
635 if (super.hasReference(referenceId)) return true; 580 if (super.hasReference(referenceId)) return true;
636 return upperBound != null && upperBound.refId == referenceId; 581 return upperBound != null && upperBound.refId == referenceId;
637 } 582 }
638 } 583 }
639 584
640 class MethodElement extends MethodElementBase { 585 /**
586 * Element describing a method.
587 */
588 class MethodElement extends MethodLikeElement {
641 589
642 final Reference returnType; 590 final Reference returnType;
643 591
644 MethodElement(Map json, Element parent) : super(json, parent), 592 MethodElement(Map json, Element parent) : super(json, parent),
645 returnType = jsonDeserializeReference(json['returnType']); 593 returnType = jsonDeserializeReference(json['returnType']);
646 } 594 }
647 595
648 class PropertyElement extends MethodElementBase { 596 /**
597 * Element describing a property getter.
598 */
599 class PropertyElement extends MethodLikeElement {
649 final Reference returnType; 600 final Reference returnType;
650 601
651 String get shortDescription => name; 602 String get shortDescription => name;
652 603
653 PropertyElement(Map json, Element parent) : super(json, parent), 604 PropertyElement(Map json, Element parent) : super(json, parent),
654 returnType = jsonDeserializeReference(json['ref']); 605 returnType = jsonDeserializeReference(json['ref']);
655 } 606 }
656 607
657 class VariableElement extends MethodElementBase { 608 /**
609 * Element describing a variable.
610 */
611 class VariableElement extends MethodLikeElement {
658 final Reference returnType; 612 final Reference returnType;
659 /** Whether this variable is final. */ 613 /** Whether this variable is final. */
660 final bool isFinal; 614 final bool isFinal;
661 615
662 String get shortDescription => name; 616 String get shortDescription => name;
663 617
664 VariableElement(Map json, Element parent) : super(json, parent), 618 VariableElement(Map json, Element parent) : super(json, parent),
665 returnType = jsonDeserializeReference(json['ref']), 619 returnType = jsonDeserializeReference(json['ref']),
666 isFinal = json['isFinal']; 620 isFinal = json['isFinal'];
667 } 621 }
668 622
669 class ConstructorElement extends MethodElementBase { 623 /**
624 * Element describing a constructor.
625 */
626 class ConstructorElement extends MethodLikeElement {
670 ConstructorElement(json, Element parent) : super(json, parent); 627 ConstructorElement(json, Element parent) : super(json, parent);
671 628
672 Reference get returnType => null; 629 Reference get returnType => null;
673 } 630 }
631
632 /**
633 * Block of elements to render summary documentation for all elements that share
634 * the same kind.
635 *
636 * For example, all properties, all functions, or all constructors.
637 */
638 class ElementBlock {
639 String kind;
640 List<Element> elements;
641
642 ElementBlock(this.kind, this.elements);
643
644 String get kindTitle => KIND_TITLES[kind];
645 }
646
647 Reference jsonDeserializeReference(Map json) {
648 return json != null ? new Reference(json) : null;
649 }
650
651 /**
652 * Deserializes JSON into an [Element] object.
653 */
654 Element jsonDeserialize(Map json, Element parent) {
655 if (json == null) return null;
656
657 var kind = json['kind'];
658 if (kind == null) {
659 throw "Unable to deserialize $json";
660 }
661
662 switch (kind) {
663 case 'class':
664 return new ClassElement(json, parent);
665 case 'typedef':
666 return new TypedefElement(json, parent);
667 case 'typeparam':
668 return new TypeParameterElement(json, parent);
669 case 'library':
670 return new LibraryElement(json, parent);
671 case 'method':
672 return new MethodElement(json, parent);
673 case 'property':
674 return new PropertyElement(json, parent);
675 case 'constructor':
676 return new ConstructorElement(json, parent);
677 case 'variable':
678 return new VariableElement(json, parent);
679 case 'param':
680 return new ParameterElement(json, parent);
681 default:
682 return new Element(json, parent);
683 }
684 }
685
686 List<Element> _jsonDeserializeArray(List json, Element parent) {
687 var ret = <Element>[];
688 if (json == null) return ret;
689
690 for (Map elementJson in json) {
691 ret.add(jsonDeserialize(elementJson, parent));
692 }
693 return ret;
694 }
695
696 List<Reference> _jsonDeserializeReferenceArray(List json) {
697 var ret = <Reference>[];
698 if (json == null) return ret;
699
700 for (Map referenceJson in json) {
701 ret.add(new Reference(referenceJson));
702 }
703 return ret;
704 }
OLDNEW
« no previous file with comments | « no previous file | client/web/doc_link.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698