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

Unified 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, 12 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | client/web/doc_link.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/web/ast.dart
diff --git a/client/web/ast.dart b/client/web/ast.dart
index 1a4801c58d00730f0df700dc1065ed13d742319b..02113ec9738fe40ccea15aeb701f2a8890832806 100644
--- a/client/web/ast.dart
+++ b/client/web/ast.dart
@@ -1,3 +1,11 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * AST describing all information about Dart libraries required to render
+ * Dart documentation.
+ */
library ast;
import 'package:web_ui/safe_html.dart';
@@ -11,95 +19,34 @@ import 'markdown.dart' as md;
*/
Map<String, LibraryElement> libraries = <LibraryElement>{};
-List<String> LIBRARY_KINDS = ['variable', 'property', 'method', 'class', 'exception', 'typedef'];
-List<String> CLASS_KINDS = ['constructor', 'variable', 'property', 'method', 'operator'];
-// TODO(jacobr): add package kinds?
-
-// TODO(jacobr): i18n
/**
- * Pretty names for the various kinds displayed.
+ * Children of a library are shown in the UI grouped by type sorted in the order
+ * specified by this list.
*/
-final KIND_TITLES = {'property': 'Properties',
- 'variable': 'Variables',
- 'method': 'Functions',
- 'constructor': 'Constructors',
- 'class': 'Classes',
- 'operator': 'Operators',
- 'typedef': 'Typedefs',
- 'exception': 'Exceptions'
-};
-
+List<String> LIBRARY_ITEMS = ['variable', 'property', 'method', 'class',
+ 'exception', 'typedef'];
/**
- * Block of elements to render summary documentation for that all share the
- * same kind.
- *
- * For example, all properties, all functions, or all constructors.
+ * Children of a class are shown in the UI grouped by type sorted in the order
+ * specified by this list.
*/
-class ElementBlock {
- String kind;
- List<Element> elements;
-
- ElementBlock(this.kind, this.elements);
-
- String get kindTitle => KIND_TITLES[kind];
-}
-
-Reference jsonDeserializeReference(Map json) {
- return json != null ? new Reference(json) : null;
-}
+List<String> CLASS_ITEMS = ['constructor', 'variable', 'property', 'method',
+ 'operator'];
+// TODO(jacobr): add package kinds?
+// TODO(jacobr): i18n
/**
- * Deserializes JSON into [Element] or [Reference] objects.
+ * Pretty names for the various kinds displayed.
*/
-Element jsonDeserialize(Map json, Element parent) {
- if (json == null) return null;
- if (!json.containsKey('kind')) {
- throw "Unable to deserialize $json";
- }
-
- switch (json['kind']) {
- case 'class':
- return new ClassElement(json, parent);
- case 'typedef':
- return new TypedefElement(json, parent);
- case 'typeparam':
- return new TypeParameterElement(json, parent);
- case 'library':
- return new LibraryElement(json, parent);
- case 'method':
- return new MethodElement(json, parent);
- case 'property':
- return new PropertyElement(json, parent);
- case 'constructor':
- return new ConstructorElement(json, parent);
- case 'variable':
- return new VariableElement(json, parent);
- case 'param':
- return new ParameterElement(json, parent);
- default:
- return new Element(json, parent);
- }
-}
-
-List<Element> jsonDeserializeArray(List json, Element parent) {
- var ret = <Element>[];
- if (json != null) {
- for (Map elementJson in json) {
- ret.add(jsonDeserialize(elementJson, parent));
- }
- }
- return ret;
-}
-
-List<Reference> jsonDeserializeReferenceArray(List json) {
- var ret = <Reference>[];
- if (json != null) {
- for (Map referenceJson in json) {
- ret.add(new Reference(referenceJson));
- }
- }
- return ret;
-}
+final KIND_TITLES = {
+ 'property': 'Properties',
+ 'variable': 'Variables',
+ 'method': 'Functions',
+ 'constructor': 'Constructors',
+ 'class': 'Classes',
+ 'operator': 'Operators',
+ 'typedef': 'Typedefs',
+ 'exception': 'Exceptions'
+};
/**
* Reference to an [Element].
@@ -107,22 +54,33 @@ List<Reference> jsonDeserializeReferenceArray(List json) {
class Reference {
final String refId;
final String name;
+ final List<Reference> arguments;
+
Reference(Map json) :
name = json['name'],
- refId = json['refId'];
+ refId = json['refId'],
+ arguments = _jsonDeserializeReferenceArray(json['arguments']);
+
+ /**
+ * Short description appropriate for displaying in a tree control or other
+ * situtation where a short description is required.
+ */
+ String get shortDescription {
+ if (arguments.isEmpty) {
+ return name;
+ } else {
+ var params = Strings.join(
+ arguments.map((param) => param.shortDescription), ', ');
+ return '$name<$params>';
+ }
+ }
}
/**
* Lookup a library based on the [libraryId].
- *
- * If the library cannot be found, a stub dummy [Library] will be returned.
*/
LibraryElement lookupLibrary(String libraryId) {
- var library = libraries[libraryId];
- if (library == null) {
- library = new LibraryElement.stub(libraryId, null);
- }
- return library;
+ return libraries[libraryId];
}
/**
@@ -133,8 +91,7 @@ LibraryElement lookupLibrary(String libraryId) {
Element lookupReferenceId(String referenceId) {
var parts = referenceId.split(new RegExp('/'));
Element current = lookupLibrary(parts.first);
- var result = <Element>[current];
- for (var i = 1; i < parts.length; i++) {
+ for (var i = 1; i < parts.length && current != null; i++) {
var id = parts[i];
var next = null;
for (var child in current.children) {
@@ -143,9 +100,6 @@ Element lookupReferenceId(String referenceId) {
break;
}
}
- if (next == null) {
- next = new Element.stub(id, current);
- }
current = next;
}
return current;
@@ -160,74 +114,73 @@ _traverseWorld(void callback(Element)) {
}
}
-// TODO(jacobr): remove this method when templates handle safe HTML containing
+// TODO(jacobr): remove this method when templates handle [SafeHTML] containing
+// multiple top level nodes correct.
SafeHtml _markdownToSafeHtml(String text) {
// We currently have to insert an extra span for now because of
- // https://github.com/dart-lang/dart-web-components/issues/212
+ // https://github.com/dart-lang/web-ui/issues/212
return new SafeHtml.unsafe(text != null && !text.isEmpty ?
'<span>${md.markdownToHtml(text)}</span>' : '<span><span>');
}
/**
- * Specifies the order elements should appear in the UI.
- */
-int elementUiOrder(Element a, Element b) {
- if (a.isPrivate != b.isPrivate) {
- return a.isPrivate == true ? 1 : -1;
- }
- return a.name.compareTo(b.name);
-}
-
-/**
* Base class for all elements in the AST.
*/
-class Element {
+class Element implements Comparable {
final Element parent;
+
/** Human readable type name for the node. */
final String rawKind;
+
/** Human readable name for the element. */
final String name;
+
/** Id for the node that is unique within its parent's children. */
final String id;
+
/** Raw text of the comment associated with the Element if any. */
final String comment;
+
/** Whether the node is private. */
final bool isPrivate;
- final String _uri;
- final String _line;
-
/** Children of the node. */
List<Element> children;
/** Whether the [Element] is currently being loaded. */
final bool loading;
+ final String _uri;
+ final String _line;
String _refId;
-
- Map _members;
SafeHtml _commentHtml;
List<Element> _references;
+ List<Element> _typeParameters;
Element(Map json, this.parent) :
name = json['name'],
rawKind = json['kind'],
id = json['id'],
comment = json['comment'],
- isPrivate = json['isPrivate'],
+ isPrivate = json['isPrivate'] == true,
_uri = json['uri'],
_line = json['line'],
loading = false {
- children = jsonDeserializeArray(json['children'], this);
+ children = _jsonDeserializeArray(json['children'], this);
}
/**
* Returns a kind name that make sense for the UI rather than the AST
* kinds. For example, setters are considered properties instead of
- * methods.
+ * methods in the UI but not the AST.
*/
String get uiKind => kind;
+ /**
+ * Longer possibly multiple word description of the [kind].
+ */
+ String get kindDescription => uiKind;
+
/** Invoke [callback] on this [Element] and all descendants. */
void traverse(void callback(Element)) {
callback(this);
@@ -237,49 +190,22 @@ class Element {
}
/**
- * Uri containing the definition of the element.
+ * Uri containing the source code for the definition of the element.
*/
- String get uri {
- Element current = this;
- while (current != null) {
- if (current._uri != null) return current._uri;
- current = current.parent;
- }
- return null;
- }
+ String get uri => _uri != null ? _uri : (parent != null ? parent.uri : null);
/**
- * Line in the original source file that starts the definition of the element.
+ * Line in the original source file that begins the definition of the element.
*/
- String get line {
- Element current = this;
- while (current != null) {
- if (current._line != null) return current._line;
- current = current.parent;
- }
- return null;
- }
-
- Element.stub(this.id, this.parent) :
- name = '???', // TODO(jacobr): remove/add
- _uri = null,
- _line = null,
- comment = null,
- rawKind = null,
- children = <Element>[],
- isPrivate = null,
- loading = true;
+ String get line => _line != null ?
+ _line : (parent != null ? parent.line : null);
/**
* Globally unique identifier for this element.
*/
String get refId {
if (_refId == null) {
- if (parent == null) {
- _refId = id;
- } else {
- _refId = '${parent.refId}/$id';
- }
+ _refId = (parent == null) ? id : '${parent.refId}/$id';
}
return _refId;
}
@@ -287,20 +213,13 @@ class Element {
/**
* Whether this [Element] references the specified [referenceId].
*/
- bool hasReference(String referenceId) {
- for (var child in children) {
- if (child.hasReference(referenceId)) {
- return true;
- }
- }
- return false;
- }
+ bool hasReference(String referenceId) =>
+ children.some((child) => child.hasReference(referenceId));
/** Returns all [Element]s that reference this [Element]. */
List<Element> get references {
if (_references == null) {
_references = <Element>[];
- // TODO(jacobr): change to filterWorld and tweak meaning.
_traverseWorld((element) {
if (element.hasReference(refId)) {
_references.add(element);
@@ -310,16 +229,23 @@ class Element {
return _references;
}
- // TODO(jacobr): write without recursion.
- /**
- * Path from this [Element] to the root of the tree starting at the root.
- */
+ /** Path from the root of the tree to this [Element]. */
List<Element> get path {
if (parent == null) {
return <Element>[this];
} else {
return parent.path..add(this);
}
+ // TODO(jacobr): replace this code with:
+ // return parent == null ? <Element>[this]) : parent.path..add(this);
+ // once http://code.google.com/p/dart/issues/detail?id=7665 is fixed.
+ }
+
+ List<Element> get typeParameters {
+ if (_typeParameters == null) {
+ _typeParameters = _filterByKind('typeparam');
+ }
+ return _typeParameters;
}
/**
@@ -337,9 +263,22 @@ class Element {
* Short description appropriate for displaying in a tree control or other
* situtation where a short description is required.
*/
- String get shortDescription => name;
+ String get shortDescription {
+ if (typeParameters.isEmpty) {
+ return name;
+ } else {
+ var params = Strings.join(
+ typeParameters.map((param) => param.shortDescription),
+ ', ');
+ return '$name<$params>';
+ }
+ }
- /** Possibly normalized representation of the node kind. */
+ /**
+ * Ui specific representation of the node kind.
+ * For example, currently operators are considered their own kind even though
+ * they aren't their own kind in the AST.
+ */
String get kind => rawKind;
/**
@@ -361,7 +300,7 @@ class Element {
for (var kind in desiredKinds) {
var elements = blockMap[kind];
if (elements != null) {
- blocks.add(new ElementBlock(kind, elements..sort(elementUiOrder)));
+ blocks.add(new ElementBlock(kind, elements..sort()));
}
}
return blocks;
@@ -372,34 +311,24 @@ class Element {
Map<String, Element> _mapForKind(String kind) {
Map ret = {};
- if (children != null) {
- for (var child in children) {
- if (child.kind == kind) {
- ret[child.id] = child;
- }
- }
- }
- return ret;
- }
+ if (children == null) return ret;
- Map<String, Element> _mapForKinds(Map<String, Element> kinds) {
- Map ret = {};
- if (children != null) {
- for (var child in children) {
- if (kinds.containsKey(child.kind)) {
- ret[child.id] = child;
- }
+ for (var child in children) {
+ if (child.kind == kind) {
+ ret[child.id] = child;
}
}
return ret;
}
- Map<String, Element> get members {
- if (_members == null) {
- // TODO(jacobr): include properties???!?
- _members = _mapForKinds({'method': true, 'property' : true});
+ /**
+ * Specifies the order elements should appear in the UI.
+ */
+ int compareTo(Element other) {
+ if (isPrivate != other.isPrivate) {
+ return other.isPrivate ? 1 : -1;
}
- return _members;
+ return name.compareTo(other.name);
}
}
@@ -414,7 +343,6 @@ class LibraryElement extends Element {
List<ElementBlock> _childBlocks;
LibraryElement(json, Element parent) : super(json, parent);
- LibraryElement.stub(String id, Element parent) : super.stub(id, parent);
/** Returns all classes defined by the library. */
Map<String, ClassElement> get classes {
@@ -430,7 +358,7 @@ class LibraryElement extends Element {
*/
List<ClassElement> get sortedClasses {
if (_sortedClasses == null) {
- _sortedClasses = []..addAll(classes.values)..sort(elementUiOrder);
+ _sortedClasses = []..addAll(classes.values)..sort();
}
return _sortedClasses;
}
@@ -440,7 +368,9 @@ class LibraryElement extends Element {
* the Library.
*/
List<ElementBlock> get childBlocks {
- if (_childBlocks == null) _childBlocks = _createElementBlocks(LIBRARY_KINDS);
+ if (_childBlocks == null) {
+ _childBlocks = _createElementBlocks(LIBRARY_ITEMS);
+ }
return _childBlocks;
}
}
@@ -449,25 +379,27 @@ class LibraryElement extends Element {
* [Element] describing a Dart class.
*/
class ClassElement extends Element {
+
/** Members of the class grouped into logical blocks. */
List<ElementBlock> _childBlocks;
+
/** Interfaces the class implements. */
final List<Reference> interfaces;
+
/** Superclass of this class. */
final Reference superclass;
+ /** Whether the class is abstract. */
+ final bool isAbstract;
+
List<ClassElement> _superclasses;
List<ClassElement> _subclasses;
ClassElement(Map json, Element parent)
: super(json, parent),
- interfaces = jsonDeserializeReferenceArray(json['interfaces']),
- superclass = jsonDeserializeReference(json['superclass']);
-
- ClassElement.stub(String id, Element parent)
- : super.stub(id, parent),
- interfaces = [],
- superclass = null;
+ interfaces = _jsonDeserializeReferenceArray(json['interfaces']),
+ superclass = jsonDeserializeReference(json['superclass']),
+ isAbstract = json['isAbstract'] == true;
/** Returns all superclasses of this class. */
List<ClassElement> get superclasses {
@@ -475,8 +407,7 @@ class ClassElement extends Element {
_superclasses = <ClassElement>[];
addSuperclasses(clazz) {
if (clazz.superclass != null) {
- ClassElement superclassElement =
- lookupReferenceId(clazz.superclass.refId);
+ var superclassElement = lookupReferenceId(clazz.superclass.refId);
addSuperclasses(superclassElement);
_superclasses.add(superclassElement);
}
@@ -486,6 +417,9 @@ class ClassElement extends Element {
return _superclasses;
}
+ String get kindDescription =>
+ isAbstract ? 'abstract $uiKind' : uiKind;
+
/**
* Returns classes that directly extend or implement this class.
*/
@@ -519,14 +453,17 @@ class ClassElement extends Element {
* order for describing a class definition.
*/
List<ElementBlock> get childBlocks {
- if (_childBlocks == null) _childBlocks = _createElementBlocks(CLASS_KINDS);
+ if (_childBlocks == null) _childBlocks = _createElementBlocks(CLASS_ITEMS);
return _childBlocks;
}
}
+/**
+ * Element describing a typedef.
+ */
class TypedefElement extends Element {
final Reference returnType;
- List<ParameterElement> _parameters;
+ List<Element> _parameters;
TypedefElement(Map json, Element parent) : super(json, parent),
returnType = jsonDeserializeReference(json['returnType']);
@@ -534,7 +471,7 @@ class TypedefElement extends Element {
/**
* Returns a list of the parameters of the typedef.
*/
- List<ParameterElement> get parameters {
+ List<Element> get parameters {
if (_parameters == null) {
_parameters = _filterByKind('param');
}
@@ -546,13 +483,13 @@ class TypedefElement extends Element {
* [Element] describing a method which may be a regular method, a setter, or an
* operator.
*/
-abstract class MethodElementBase extends Element {
+abstract class MethodLikeElement extends Element {
final bool isOperator;
final bool isStatic;
final bool isSetter;
- MethodElementBase(Map json, Element parent)
+ MethodLikeElement(Map json, Element parent)
: super(json, parent),
isOperator = json['isOperator'] == true,
isStatic = json['isStatic'] == true,
@@ -571,8 +508,8 @@ abstract class MethodElementBase extends Element {
* required.
*/
String get shortDescription {
- if (isSetter == true) {
- var sb = new StringBuffer('${name.substring(0, name.length-1)}');
+ if (isSetter) {
+ var sb = new StringBuffer('${name.substring(0, name.length - 1)}');
if (!parameters.isEmpty && parameters.first != null
&& parameters.first.type != null) {
sb..add(' ')..add(parameters.first.type.name);
@@ -584,19 +521,19 @@ abstract class MethodElementBase extends Element {
}
Reference get returnType;
- List<ParameterElement> _parameters;
+ List<Element> _parameters;
/**
* Returns a list of the parameters of the Method.
*/
- List<ParameterElement> get parameters {
+ List<Element> get parameters {
if (_parameters == null) {
_parameters = _filterByKind('param');
}
return _parameters;
}
- // For UI purposes we want to treat operators as their own kind.
+ /// For UI purposes we want to treat operators as their own kind.
String get kind => isOperator ? 'operator' : rawKind;
}
@@ -631,13 +568,24 @@ class TypeParameterElement extends Element {
super(json, parent),
upperBound = jsonDeserializeReference(json['upperBound']);
+ String get shortDescription {
+ if (upperBound == null) {
+ return name;
+ } else {
+ return '$name extends ${upperBound.shortDescription}';
+ }
+ }
+
bool hasReference(String referenceId) {
if (super.hasReference(referenceId)) return true;
return upperBound != null && upperBound.refId == referenceId;
}
}
-class MethodElement extends MethodElementBase {
+/**
+ * Element describing a method.
+ */
+class MethodElement extends MethodLikeElement {
final Reference returnType;
@@ -645,7 +593,10 @@ class MethodElement extends MethodElementBase {
returnType = jsonDeserializeReference(json['returnType']);
}
-class PropertyElement extends MethodElementBase {
+/**
+ * Element describing a property getter.
+ */
+class PropertyElement extends MethodLikeElement {
final Reference returnType;
String get shortDescription => name;
@@ -654,7 +605,10 @@ class PropertyElement extends MethodElementBase {
returnType = jsonDeserializeReference(json['ref']);
}
-class VariableElement extends MethodElementBase {
+/**
+ * Element describing a variable.
+ */
+class VariableElement extends MethodLikeElement {
final Reference returnType;
/** Whether this variable is final. */
final bool isFinal;
@@ -666,8 +620,85 @@ class VariableElement extends MethodElementBase {
isFinal = json['isFinal'];
}
-class ConstructorElement extends MethodElementBase {
+/**
+ * Element describing a constructor.
+ */
+class ConstructorElement extends MethodLikeElement {
ConstructorElement(json, Element parent) : super(json, parent);
Reference get returnType => null;
}
+
+/**
+ * Block of elements to render summary documentation for all elements that share
+ * the same kind.
+ *
+ * For example, all properties, all functions, or all constructors.
+ */
+class ElementBlock {
+ String kind;
+ List<Element> elements;
+
+ ElementBlock(this.kind, this.elements);
+
+ String get kindTitle => KIND_TITLES[kind];
+}
+
+Reference jsonDeserializeReference(Map json) {
+ return json != null ? new Reference(json) : null;
+}
+
+/**
+ * Deserializes JSON into an [Element] object.
+ */
+Element jsonDeserialize(Map json, Element parent) {
+ if (json == null) return null;
+
+ var kind = json['kind'];
+ if (kind == null) {
+ throw "Unable to deserialize $json";
+ }
+
+ switch (kind) {
+ case 'class':
+ return new ClassElement(json, parent);
+ case 'typedef':
+ return new TypedefElement(json, parent);
+ case 'typeparam':
+ return new TypeParameterElement(json, parent);
+ case 'library':
+ return new LibraryElement(json, parent);
+ case 'method':
+ return new MethodElement(json, parent);
+ case 'property':
+ return new PropertyElement(json, parent);
+ case 'constructor':
+ return new ConstructorElement(json, parent);
+ case 'variable':
+ return new VariableElement(json, parent);
+ case 'param':
+ return new ParameterElement(json, parent);
+ default:
+ return new Element(json, parent);
+ }
+}
+
+List<Element> _jsonDeserializeArray(List json, Element parent) {
+ var ret = <Element>[];
+ if (json == null) return ret;
+
+ for (Map elementJson in json) {
+ ret.add(jsonDeserialize(elementJson, parent));
+ }
+ return ret;
+}
+
+List<Reference> _jsonDeserializeReferenceArray(List json) {
+ var ret = <Reference>[];
+ if (json == null) return ret;
+
+ for (Map referenceJson in json) {
+ ret.add(new Reference(referenceJson));
+ }
+ return ret;
+}
« 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