Create renderers for more model classes and update some tests (#2078)
* Create renderer for EnumField
* Create renderers for Typedef & TypeParamaters
* Create renderer for ModelElement
* Fix some tests and dartfmt
diff --git a/lib/src/model/enum.dart b/lib/src/model/enum.dart
index 0ff67e4..91c2e68 100644
--- a/lib/src/model/enum.dart
+++ b/lib/src/model/enum.dart
@@ -5,6 +5,7 @@
// TODO(jcollins-g): Consider Enum as subclass of Container?
import 'package:analyzer/dart/element/element.dart';
import 'package:dartdoc/src/model/model.dart';
+import 'package:dartdoc/src/render/enum_field_renderer.dart';
class Enum extends Class {
Enum(ClassElement element, Library library, PackageGraph packageGraph)
@@ -32,24 +33,18 @@
/// Enum's fields are virtual, so we do a little work to create
/// usable values for the docs.
class EnumField extends Field {
- int _index;
+ int index;
EnumField(FieldElement element, Library library, PackageGraph packageGraph,
Accessor getter, Accessor setter)
: super(element, library, packageGraph, getter, setter);
- EnumField.forConstant(this._index, FieldElement element, Library library,
+ EnumField.forConstant(this.index, FieldElement element, Library library,
PackageGraph packageGraph, Accessor getter)
: super(element, library, packageGraph, getter, null);
@override
- String get constantValueBase {
- if (name == 'values') {
- return 'const List<<wbr><span class="type-parameter">${field.enclosingElement.name}</span>>';
- } else {
- return 'const ${field.enclosingElement.name}($_index)';
- }
- }
+ String get constantValueBase => EnumFieldRendererHtml().renderValue(this);
@override
List<ModelElement> get documentationFrom {
@@ -87,7 +82,7 @@
if (name == 'index') return false;
// If this is something inherited from Object, e.g. hashCode, let the
// normal rules apply.
- if (_index == null) {
+ if (index == null) {
return super.isCanonical;
}
// TODO(jcollins-g): We don't actually document this as a separate entity;
diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart
index e09ba79..e2e0f4f 100644
--- a/lib/src/model/model_element.dart
+++ b/lib/src/model/model_element.dart
@@ -27,6 +27,7 @@
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/model_utils.dart' as utils;
import 'package:dartdoc/src/render/parameter_renderer.dart';
+import 'package:dartdoc/src/render/model_element_renderer.dart';
import 'package:dartdoc/src/source_linker.dart';
import 'package:dartdoc/src/tuple.dart';
import 'package:dartdoc/src/utils.dart';
@@ -1144,8 +1145,7 @@
return htmlEscape.convert(name);
}
- var classContent = isDeprecated ? ' class="deprecated"' : '';
- return '<a${classContent} href="${href}">$name</a>';
+ return ModelElementRendererHtml().renderLinkedName(this);
}
/// Replace {@example ...} in API comments with the content of named file.
@@ -1370,37 +1370,14 @@
warn(PackageWarning.invalidParameter,
message: 'A @youtube directive has an invalid URL: '
'"${positionalArgs[2]}". Supported YouTube URLs have the '
- 'follwing format: https://www.youtube.com/watch?v=oHg5SJYRHA0.');
+ 'following format: https://www.youtube.com/watch?v=oHg5SJYRHA0.');
return '';
}
final String youTubeId = url.group(url.groupCount);
final String aspectRatio = (height / width * 100).toStringAsFixed(2);
- // Blank lines before and after, and no indenting at the beginning and end
- // is needed so that Markdown doesn't confuse this with code, so be
- // careful of whitespace here.
- return '''
-
-<p style="position: relative;
- padding-top: $aspectRatio%;">
- <iframe src="https://www.youtube.com/embed/$youTubeId?rel=0"
- frameborder="0"
- allow="accelerometer;
- autoplay;
- encrypted-media;
- gyroscope;
- picture-in-picture"
- allowfullscreen
- style="position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;">
- </iframe>
-</p>
-
-'''; // String must end at beginning of line, or following inline text will be
- // indented.
+ return ModelElementRendererHtml()
+ .renderYoutubeUrl(youTubeId, aspectRatio);
});
}
@@ -1531,45 +1508,8 @@
'parameter)');
}
- // Blank lines before and after, and no indenting at the beginning and end
- // is needed so that Markdown doesn't confuse this with code, so be
- // careful of whitespace here.
- return '''
-
-<div style="position: relative;">
- <div id="${overlayId}"
- onclick="var $uniqueId = document.getElementById('$uniqueId');
- if ($uniqueId.paused) {
- $uniqueId.play();
- this.style.display = 'none';
- } else {
- $uniqueId.pause();
- this.style.display = 'block';
- }"
- style="position:absolute;
- width:${width}px;
- height:${height}px;
- z-index:100000;
- background-position: center;
- background-repeat: no-repeat;
- background-image: url(static-assets/play_button.svg);">
- </div>
- <video id="$uniqueId"
- style="width:${width}px; height:${height}px;"
- onclick="var $overlayId = document.getElementById('$overlayId');
- if (this.paused) {
- this.play();
- $overlayId.style.display = 'none';
- } else {
- this.pause();
- $overlayId.style.display = 'block';
- }" loop>
- <source src="$movieUrl" type="video/mp4"/>
- </video>
-</div>
-
-'''; // String must end at beginning of line, or following inline text will be
- // indented.
+ return ModelElementRendererHtml()
+ .renderAnimation(uniqueId, width, height, movieUrl, overlayId);
});
}
diff --git a/lib/src/model/type_parameter.dart b/lib/src/model/type_parameter.dart
index fc5d0ae..158095d 100644
--- a/lib/src/model/type_parameter.dart
+++ b/lib/src/model/type_parameter.dart
@@ -5,6 +5,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model/model.dart';
+import 'package:dartdoc/src/render/type_parameters_renderer.dart';
class TypeParameter extends ModelElement {
TypeParameter(
@@ -76,21 +77,11 @@
bool get hasGenericParameters => typeParameters.isNotEmpty;
String get genericParameters {
- if (typeParameters.isEmpty) return '';
-
- var joined = typeParameters
- .map((t) => t.name)
- .join('</span>, <span class="type-parameter">');
- return '<<wbr><span class="type-parameter">${joined}</span>>';
+ return TypeParametersRendererHtml().renderGenericParameters(this);
}
String get linkedGenericParameters {
- if (typeParameters.isEmpty) return '';
-
- var joined = typeParameters
- .map((t) => t.linkedName)
- .join('</span>, <span class="type-parameter">');
- return '<span class="signature"><<wbr><span class="type-parameter">${joined}</span>></span>';
+ return TypeParametersRendererHtml().renderLinkedGenericParameters(this);
}
@override
diff --git a/lib/src/model/typedef.dart b/lib/src/model/typedef.dart
index 15a168e..3a13447 100644
--- a/lib/src/model/typedef.dart
+++ b/lib/src/model/typedef.dart
@@ -5,6 +5,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model/model.dart';
+import 'package:dartdoc/src/render/typedef_renderer.dart';
class Typedef extends ModelElement
with SourceCodeMixin, TypeParameters, Categorization
@@ -20,18 +21,14 @@
String get nameWithGenerics => '$name${super.genericParameters}';
@override
- String get genericParameters {
+ String get genericParameters =>
+ TypedefRendererHtml().renderGenericParameters(this);
+
+ List<TypeParameterElement> get genericTypeParameters {
if (element is GenericTypeAliasElement) {
- List<TypeParameterElement> genericTypeParameters =
- (element as GenericTypeAliasElement).function.typeParameters;
- if (genericTypeParameters.isNotEmpty) {
- var joined = genericTypeParameters
- .map((t) => t.name)
- .join('</span>, <span class="type-parameter">');
- return '<<wbr><span class="type-parameter">${joined}</span>>';
- }
- } // else, all types are resolved.
- return '';
+ return (element as GenericTypeAliasElement).function.typeParameters;
+ }
+ return Iterable.empty();
}
@override
diff --git a/lib/src/render/enum_field_renderer.dart b/lib/src/render/enum_field_renderer.dart
new file mode 100644
index 0000000..c9096b0
--- /dev/null
+++ b/lib/src/render/enum_field_renderer.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+import 'package:dartdoc/src/model/enum.dart';
+
+abstract class EnumFieldRenderer {
+ String renderValue(EnumField field);
+}
+
+class EnumFieldRendererHtml extends EnumFieldRenderer {
+ @override
+ String renderValue(EnumField field) {
+ if (field.name == 'values') {
+ return 'const List<<wbr><span class="type-parameter">${field.enclosingElement.name}</span>>';
+ } else {
+ return 'const ${field.enclosingElement.name}(${field.index})';
+ }
+ }
+}
diff --git a/lib/src/render/model_element_renderer.dart b/lib/src/render/model_element_renderer.dart
new file mode 100644
index 0000000..700e3f2
--- /dev/null
+++ b/lib/src/render/model_element_renderer.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2019, 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.
+
+import 'package:dartdoc/src/model/model_element.dart';
+
+abstract class ModelElementRenderer {
+ String renderLinkedName(ModelElement modelElement);
+
+ String renderYoutubeUrl(String youTubeId, String aspectRatio);
+
+ String renderAnimation(
+ String uniqueId, int width, int height, Uri movieUrl, String overlayId);
+}
+
+class ModelElementRendererHtml extends ModelElementRenderer {
+ @override
+ String renderLinkedName(ModelElement modelElement) {
+ var cssClass = modelElement.isDeprecated ? ' class="deprecated"' : '';
+ return '<a${cssClass} href="${modelElement.href}">${modelElement.name}</a>';
+ }
+
+ @override
+ String renderYoutubeUrl(String youTubeId, String aspectRatio) {
+ // Blank lines before and after, and no indenting at the beginning and end
+ // is needed so that Markdown doesn't confuse this with code, so be
+ // careful of whitespace here.
+ return '''
+
+<p style="position: relative;
+ padding-top: $aspectRatio%;">
+ <iframe src="https://www.youtube.com/embed/$youTubeId?rel=0"
+ frameborder="0"
+ allow="accelerometer;
+ autoplay;
+ encrypted-media;
+ gyroscope;
+ picture-in-picture"
+ allowfullscreen
+ style="position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;">
+ </iframe>
+</p>
+
+'''; // Must end at start of line, or following inline text will be indented.
+ }
+
+ @override
+ String renderAnimation(
+ String uniqueId, int width, int height, Uri movieUrl, String overlayId) {
+ return '''
+
+<div style="position: relative;">
+ <div id="${overlayId}"
+ onclick="var $uniqueId = document.getElementById('$uniqueId');
+ if ($uniqueId.paused) {
+ $uniqueId.play();
+ this.style.display = 'none';
+ } else {
+ $uniqueId.pause();
+ this.style.display = 'block';
+ }"
+ style="position:absolute;
+ width:${width}px;
+ height:${height}px;
+ z-index:100000;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-image: url(static-assets/play_button.svg);">
+ </div>
+ <video id="$uniqueId"
+ style="width:${width}px; height:${height}px;"
+ onclick="var $overlayId = document.getElementById('$overlayId');
+ if (this.paused) {
+ this.play();
+ $overlayId.style.display = 'none';
+ } else {
+ this.pause();
+ $overlayId.style.display = 'block';
+ }" loop>
+ <source src="$movieUrl" type="video/mp4"/>
+ </video>
+</div>
+
+'''; // Must end at start of line, or following inline text will be indented.
+ }
+}
diff --git a/lib/src/render/type_parameters_renderer.dart b/lib/src/render/type_parameters_renderer.dart
new file mode 100644
index 0000000..879ca0f
--- /dev/null
+++ b/lib/src/render/type_parameters_renderer.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, 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.
+
+import 'package:dartdoc/src/model/type_parameter.dart';
+
+abstract class TypeParametersRenderer {
+ String renderGenericParameters(TypeParameters typeParameters);
+ String renderLinkedGenericParameters(TypeParameters typeParameters);
+}
+
+class TypeParametersRendererHtml extends TypeParametersRenderer {
+ @override
+ String renderGenericParameters(TypeParameters typeParameters) {
+ if (typeParameters.typeParameters.isEmpty) {
+ return '';
+ }
+ var joined = typeParameters.typeParameters
+ .map((t) => t.name)
+ .join('</span>, <span class="type-parameter">');
+ return '<<wbr><span class="type-parameter">${joined}</span>>';
+ }
+
+ @override
+ String renderLinkedGenericParameters(TypeParameters typeParameters) {
+ if (typeParameters.typeParameters.isEmpty) {
+ return '';
+ }
+ var joined = typeParameters.typeParameters
+ .map((t) => t.linkedName)
+ .join('</span>, <span class="type-parameter">');
+ return '<span class="signature"><<wbr><span class="type-parameter">${joined}</span>></span>';
+ }
+}
diff --git a/lib/src/render/typedef_renderer.dart b/lib/src/render/typedef_renderer.dart
new file mode 100644
index 0000000..385225b
--- /dev/null
+++ b/lib/src/render/typedef_renderer.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, 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.
+
+import 'package:dartdoc/src/model/typedef.dart';
+
+abstract class TypedefRenderer {
+ String renderGenericParameters(Typedef typedef);
+}
+
+class TypedefRendererHtml extends TypedefRenderer {
+ @override
+ String renderGenericParameters(Typedef typedef) {
+ if (typedef.genericTypeParameters.isEmpty) {
+ return '';
+ }
+ var joined = typedef.genericTypeParameters
+ .map((t) => t.name)
+ .join('</span>, <span class="type-parameter">');
+ return '<<wbr><span class="type-parameter">${joined}</span>>';
+ }
+}
diff --git a/test/model_special_cases_test.dart b/test/model_special_cases_test.dart
index 782e33f..8abf5af 100644
--- a/test/model_special_cases_test.dart
+++ b/test/model_special_cases_test.dart
@@ -459,7 +459,7 @@
PackageWarning.invalidParameter,
'A @youtube directive has an invalid URL: '
'"http://host/path/to/video.mp4". Supported YouTube URLs have '
- 'the follwing format: '
+ 'the following format: '
'https://www.youtube.com/watch?v=oHg5SJYRHA0.'),
isTrue);
});
@@ -470,7 +470,7 @@
PackageWarning.invalidParameter,
'A @youtube directive has an invalid URL: '
'"https://www.youtube.com/watch?v=yI-8QHpGIP4&list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG&index=5". '
- 'Supported YouTube URLs have the follwing format: '
+ 'Supported YouTube URLs have the following format: '
'https://www.youtube.com/watch?v=oHg5SJYRHA0.'),
isTrue);
});
diff --git a/test/model_test.dart b/test/model_test.dart
index ccc3970..58572a7 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -10,6 +10,8 @@
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/render/category_renderer.dart';
import 'package:dartdoc/src/render/parameter_renderer.dart';
+import 'package:dartdoc/src/render/enum_field_renderer.dart';
+import 'package:dartdoc/src/render/typedef_renderer.dart';
import 'package:dartdoc/src/warnings.dart';
import 'package:test/test.dart';
@@ -1984,20 +1986,19 @@
});
test("has a (synthetic) values constant", () {
- var values = animal.constants.firstWhere((f) => f.name == 'values');
- expect(values, isNotNull);
- expect(
- values.constantValue,
- equals(
- 'const List<<wbr><span class="type-parameter">Animal</span>>'));
- expect(values.documentation, startsWith('A constant List'));
+ var valuesField = animal.constants.firstWhere((f) => f.name == 'values');
+ expect(valuesField, isNotNull);
+ expect(valuesField.constantValue,
+ equals(EnumFieldRendererHtml().renderValue(valuesField)));
+ expect(valuesField.documentation, startsWith('A constant List'));
});
test('has a constant that does not link anywhere', () {
var dog = animal.constants.firstWhere((f) => f.name == 'DOG');
expect(dog.linkedName, equals('DOG'));
expect(dog.isConst, isTrue);
- expect(dog.constantValue, equals('const Animal(1)'));
+ expect(
+ dog.constantValue, equals(EnumFieldRendererHtml().renderValue(dog)));
});
test('constants have correct indicies', () {
@@ -3410,9 +3411,12 @@
'NewGenericTypedef<<wbr><span class="type-parameter">T</span>>'));
});
- test("generic parameters", () {
- expect(t.genericParameters, equals(''));
- expect(generic.genericParameters,
+ // TODO(jdkoren): Not easy to call TypedefRenderer directly because Typedef
+ // inspects its element member. Find a better way when we start to isolate
+ // renderer tests.
+ test("TypedefRendererHtml renders genericParameters", () {
+ expect(TypedefRendererHtml().renderGenericParameters(t), equals(''));
+ expect(TypedefRendererHtml().renderGenericParameters(generic),
equals('<<wbr><span class="type-parameter">S</span>>'));
});
});