diff --git a/lib/src/model/package_builder.dart b/lib/src/model/package_builder.dart
index 572faedaad..e3da440664 100644
--- a/lib/src/model/package_builder.dart
+++ b/lib/src/model/package_builder.dart
@@ -42,8 +42,8 @@ class PackageBuilder {
if (config.topLevelPackageMeta.needsPubGet) {
config.topLevelPackageMeta.runPubGet();
}
- // TODO(jdkoren): change factory for other formats based on config options
- RendererFactory rendererFactory = HtmlRenderFactory();
+
+ RendererFactory rendererFactory = RendererFactory.forFormat(config.format);
PackageGraph newGraph = PackageGraph.UninitializedPackageGraph(
config, driver, sdk, hasEmbedderSdkFiles, rendererFactory);
diff --git a/lib/src/render/category_renderer.dart b/lib/src/render/category_renderer.dart
index 7b0b803c9e..d8e5f0598d 100644
--- a/lib/src/render/category_renderer.dart
+++ b/lib/src/render/category_renderer.dart
@@ -31,7 +31,7 @@ class CategoryRendererHtml extends CategoryRenderer {
StringBuffer buf = StringBuffer();
buf.write('');
- buf.write(category.linkedName);
+ buf.write(renderLinkedName(category));
buf.write('');
return buf.toString();
}
@@ -46,3 +46,17 @@ class CategoryRendererHtml extends CategoryRenderer {
}
}
}
+
+class CategoryRendererMd extends CategoryRenderer {
+ @override
+ String renderCategoryLabel(Category category) => renderLinkedName(category);
+
+ @override
+ String renderLinkedName(Category category) {
+ String name = category.name;
+ if (category.isDocumented) {
+ return '[$name](${category.href})';
+ }
+ return name;
+ }
+}
diff --git a/lib/src/render/element_type_renderer.dart b/lib/src/render/element_type_renderer.dart
index cc4be7a4fb..af03ac7be9 100644
--- a/lib/src/render/element_type_renderer.dart
+++ b/lib/src/render/element_type_renderer.dart
@@ -11,6 +11,8 @@ abstract class ElementTypeRenderer {
String renderNameWithGenerics(T elementType) => '';
}
+// Html implementations
+
class FunctionTypeElementTypeRendererHtml
extends ElementTypeRenderer {
@override
@@ -93,3 +95,83 @@ class CallableElementTypeRendererHtml
return buf.toString();
}
}
+
+// Markdown implementations
+
+class FunctionTypeElementTypeRendererMd
+ extends ElementTypeRenderer {
+ @override
+ String renderLinkedName(FunctionTypeElementType elementType) {
+ StringBuffer buf = StringBuffer();
+ buf.write('${elementType.returnType.linkedName} ');
+ buf.write('${elementType.nameWithGenerics}');
+ buf.write('(');
+ buf.write(ParameterRendererMd().renderLinkedParams(elementType.parameters));
+ buf.write(')');
+ return buf.toString();
+ }
+
+ @override
+ String renderNameWithGenerics(FunctionTypeElementType elementType) {
+ StringBuffer buf = StringBuffer();
+ buf.write(elementType.name);
+ if (elementType.typeFormals.isNotEmpty) {
+ if (!elementType.typeFormals.every((t) => t.name == 'dynamic')) {
+ buf.write('<');
+ buf.writeAll(elementType.typeFormals.map((t) => t.name), ', ');
+ buf.write('>');
+ }
+ }
+ return buf.toString();
+ }
+}
+
+class ParameterizedElementTypeRendererMd
+ extends ElementTypeRenderer {
+ @override
+ String renderLinkedName(ParameterizedElementType elementType) {
+ StringBuffer buf = StringBuffer();
+ buf.write(elementType.element.linkedName);
+ if (elementType.typeArguments.isNotEmpty &&
+ !elementType.typeArguments.every((t) => t.name == 'dynamic')) {
+ buf.write('<');
+ buf.writeAll(elementType.typeArguments.map((t) => t.linkedName), ', ');
+ buf.write('>');
+ }
+ return buf.toString();
+ }
+
+ @override
+ String renderNameWithGenerics(ParameterizedElementType elementType) {
+ StringBuffer buf = StringBuffer();
+ buf.write(elementType.element.name);
+ if (elementType.typeArguments.isNotEmpty &&
+ !elementType.typeArguments.every((t) => t.name == 'dynamic')) {
+ buf.write('<');
+ buf.writeAll(
+ elementType.typeArguments.map((t) => t.nameWithGenerics), ', ');
+ buf.write('>');
+ }
+ return buf.toString();
+ }
+}
+
+class CallableElementTypeRendererMd
+ extends ElementTypeRenderer {
+ @override
+ String renderLinkedName(CallableElementType elementType) {
+ if (elementType.name != null && elementType.name.isNotEmpty) {
+ return elementType.superLinkedName;
+ }
+
+ StringBuffer buf = StringBuffer();
+ buf.write(elementType.nameWithGenerics);
+ buf.write('(');
+ buf.write(ParameterRendererMd()
+ .renderLinkedParams(elementType.element.parameters, showNames: false)
+ .trim());
+ buf.write(') → ');
+ buf.write(elementType.returnType.linkedName);
+ return buf.toString();
+ }
+}
diff --git a/lib/src/render/enum_field_renderer.dart b/lib/src/render/enum_field_renderer.dart
index c9096b0b26..4a635909e7 100644
--- a/lib/src/render/enum_field_renderer.dart
+++ b/lib/src/render/enum_field_renderer.dart
@@ -18,3 +18,14 @@ class EnumFieldRendererHtml extends EnumFieldRenderer {
}
}
}
+
+class EnumFieldRendererMd extends EnumFieldRenderer {
+ @override
+ String renderValue(EnumField field) {
+ if (field.name == 'values') {
+ return 'const List<${field.enclosingElement.name}>';
+ } 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
index 9d274d4fe4..d7755d4851 100644
--- a/lib/src/render/model_element_renderer.dart
+++ b/lib/src/render/model_element_renderer.dart
@@ -95,3 +95,17 @@ class ModelElementRendererHtml extends ModelElementRenderer {
'''; // Must end at start of line, or following inline text will be indented.
}
}
+
+class ModelElementRendererMd extends ModelElementRendererHtml {
+ @override
+ String renderLinkedName(ModelElement modelElement) {
+ if (modelElement.isDeprecated) {
+ return '[~~${modelElement.name}~~](${modelElement.href})';
+ }
+ return '[${modelElement.name}](${modelElement.href})';
+ }
+
+ @override
+ String renderExtendedDocLink(ModelElement modelElement) =>
+ '[...](${modelElement.href})';
+}
diff --git a/lib/src/render/parameter_renderer.dart b/lib/src/render/parameter_renderer.dart
index 3e7a895c3a..fab430d259 100644
--- a/lib/src/render/parameter_renderer.dart
+++ b/lib/src/render/parameter_renderer.dart
@@ -42,6 +42,35 @@ class ParameterRendererHtml extends ParameterRenderer {
String required(String required) => '$required';
}
+class ParameterRendererMd extends ParameterRenderer {
+ @override
+ String annotation(String annotation) => annotation;
+
+ @override
+ String covariant(String covariant) => covariant;
+
+ @override
+ String defaultValue(String defaultValue) => defaultValue;
+
+ @override
+ String listItem(String item) => item;
+
+ @override
+ String orderedList(String listItems) => listItems;
+
+ @override
+ String parameter(String parameter, String id) => parameter;
+
+ @override
+ String parameterName(String parameterName) => parameterName;
+
+ @override
+ String required(String required) => required;
+
+ @override
+ String typeName(String typeName) => typeName;
+}
+
abstract class ParameterRenderer {
String listItem(String item);
String orderedList(String listItems);
diff --git a/lib/src/render/renderer_factory.dart b/lib/src/render/renderer_factory.dart
index f8787228a8..eaead50507 100644
--- a/lib/src/render/renderer_factory.dart
+++ b/lib/src/render/renderer_factory.dart
@@ -14,6 +14,17 @@ import 'package:dartdoc/src/render/type_parameters_renderer.dart';
import 'package:dartdoc/src/render/typedef_renderer.dart';
abstract class RendererFactory {
+ static RendererFactory forFormat(String format) {
+ switch (format) {
+ case 'html':
+ return HtmlRenderFactory();
+ case 'md':
+ return MdRenderFactory();
+ default:
+ throw ArgumentError('Unsupported format: $format');
+ }
+ }
+
TemplateRenderer get templateRenderer;
CategoryRenderer get categoryRenderer;
@@ -86,3 +97,50 @@ class HtmlRenderFactory extends RendererFactory {
@override
TypedefRenderer get typedefRenderer => TypedefRendererHtml();
}
+
+class MdRenderFactory extends RendererFactory {
+ @override
+ TemplateRenderer get templateRenderer => MdTemplateRenderer();
+
+ @override
+ CategoryRenderer get categoryRenderer => CategoryRendererMd();
+
+ // We render documentation as HTML for now.
+ // TODO(jdkoren): explore using documentation directly in the output file.
+ @override
+ DocumentationRenderer get documentationRenderer =>
+ DocumentationRendererHtml();
+
+ @override
+ ElementTypeRenderer get callableElementTypeRenderer =>
+ CallableElementTypeRendererMd();
+
+ @override
+ ElementTypeRenderer
+ get functionTypeElementTypeRenderer =>
+ FunctionTypeElementTypeRendererMd();
+
+ @override
+ ElementTypeRenderer
+ get parameterizedElementTypeRenderer =>
+ ParameterizedElementTypeRendererMd();
+
+ @override
+ EnumFieldRenderer get enumFieldRenderer => EnumFieldRendererMd();
+
+ @override
+ ModelElementRenderer get modelElementRenderer => ModelElementRendererMd();
+
+ @override
+ ParameterRenderer get parameterRenderer => ParameterRendererMd();
+
+ @override
+ ParameterRenderer get parameterRendererDetailed => parameterRenderer;
+
+ @override
+ TypeParametersRenderer get typeParametersRenderer =>
+ TypeParametersRendererMd();
+
+ @override
+ TypedefRenderer get typedefRenderer => TypedefRendererMd();
+}
diff --git a/lib/src/render/template_renderer.dart b/lib/src/render/template_renderer.dart
index 3e0ed15391..e18ab4ac41 100644
--- a/lib/src/render/template_renderer.dart
+++ b/lib/src/render/template_renderer.dart
@@ -16,3 +16,14 @@ class HtmlTemplateRenderer implements TemplateRenderer {
}
}
}
+
+class MdTemplateRenderer implements TemplateRenderer {
+ @override
+ String composeLayoutTitle(String name, String kind, bool isDeprecated) {
+ if (isDeprecated) {
+ return '~~${name}~~ ${kind}';
+ } else {
+ return '${name} ${kind}';
+ }
+ }
+}
diff --git a/lib/src/render/type_parameters_renderer.dart b/lib/src/render/type_parameters_renderer.dart
index 879ca0ffaa..09ac2eeda0 100644
--- a/lib/src/render/type_parameters_renderer.dart
+++ b/lib/src/render/type_parameters_renderer.dart
@@ -6,6 +6,7 @@ import 'package:dartdoc/src/model/type_parameter.dart';
abstract class TypeParametersRenderer {
String renderGenericParameters(TypeParameters typeParameters);
+
String renderLinkedGenericParameters(TypeParameters typeParameters);
}
@@ -32,3 +33,22 @@ class TypeParametersRendererHtml extends TypeParametersRenderer {
return '<${joined}>';
}
}
+
+class TypeParametersRendererMd extends TypeParametersRenderer {
+ @override
+ String renderGenericParameters(TypeParameters typeParameters) =>
+ _compose(typeParameters.typeParameters, (t) => t.name);
+
+ @override
+ String renderLinkedGenericParameters(TypeParameters typeParameters) =>
+ _compose(typeParameters.typeParameters, (t) => t.linkedName);
+
+ String _compose(List typeParameters,
+ String Function(TypeParameter) mapfn) {
+ if (typeParameters.isEmpty) {
+ return '';
+ }
+ var joined = typeParameters.map(mapfn).join(', ');
+ return '<${joined}>';
+ }
+}
diff --git a/lib/src/render/typedef_renderer.dart b/lib/src/render/typedef_renderer.dart
index 385225b87b..b79e3b3091 100644
--- a/lib/src/render/typedef_renderer.dart
+++ b/lib/src/render/typedef_renderer.dart
@@ -20,3 +20,14 @@ class TypedefRendererHtml extends TypedefRenderer {
return '<${joined}>';
}
}
+
+class TypedefRendererMd extends TypedefRenderer {
+ @override
+ String renderGenericParameters(Typedef typedef) {
+ if (typedef.genericTypeParameters.isEmpty) {
+ return '';
+ }
+ var joined = typedef.genericTypeParameters.map((t) => t.name).join(', ');
+ return '<{$joined}>';
+ }
+}
diff --git a/lib/templates/md/_callable.md b/lib/templates/md/_callable.md
index 49d5fdb5f3..9cc868478b 100644
--- a/lib/templates/md/_callable.md
+++ b/lib/templates/md/_callable.md
@@ -1,3 +1,3 @@
-{{#isDeprecated}}~~{{/isDeprecated}}{{{linkedName}}}{{{linkedGenericParameters}}}({{{ linkedParamsNoMetadata }}}) {{{ linkedReturnType }}} {{>categorization}}{{#isDeprecated}}~~{{/isDeprecated}}
+{{{linkedName}}}{{{linkedGenericParameters}}}({{{ linkedParamsNoMetadata }}}) {{{ linkedReturnType }}} {{>categorization}}
: {{{ oneLineDoc }}} {{{ extendedDocLink }}}
{{>features}}
diff --git a/lib/templates/md/_class.md b/lib/templates/md/_class.md
index 90721f1898..7659fa0e6e 100644
--- a/lib/templates/md/_class.md
+++ b/lib/templates/md/_class.md
@@ -1,2 +1,2 @@
-{{#isDeprecated}}~~{{/isDeprecated}}{{{linkedName}}}{{{linkedGenericParameters}}} {{>categorization}}{{#isDeprecated}}~~{{/isDeprecated}}
+{{{linkedName}}}{{{linkedGenericParameters}}} {{>categorization}}
: {{{ oneLineDoc }}} {{{ extendedDocLink }}}
diff --git a/lib/templates/md/_constant.md b/lib/templates/md/_constant.md
index 54d040ba0d..6367e59957 100644
--- a/lib/templates/md/_constant.md
+++ b/lib/templates/md/_constant.md
@@ -1,3 +1,3 @@
-{{#isDeprecated}}~~{{/isDeprecated}}{{{ linkedName }}} const {{{ linkedReturnType }}} {{>categorization}}{{#isDeprecated}}~~{{/isDeprecated}}
+{{{ linkedName }}} const {{{ linkedReturnType }}} {{>categorization}}
: {{{ oneLineDoc }}} {{{ extendedDocLink }}}
{{>features}}
diff --git a/lib/templates/md/_extension.md b/lib/templates/md/_extension.md
index 097235ead6..84737c4d56 100644
--- a/lib/templates/md/_extension.md
+++ b/lib/templates/md/_extension.md
@@ -1,2 +1,2 @@
-{{#isDeprecated}}~~{{/isDeprecated}}{{{linkedName}}} {{>categorization}}{{#isDeprecated}}~~{{/isDeprecated}}
+{{{linkedName}}} {{>categorization}}
: {{{ oneLineDoc }}} {{{ extendedDocLink }}}
diff --git a/lib/templates/md/_mixin.md b/lib/templates/md/_mixin.md
index 90721f1898..7659fa0e6e 100644
--- a/lib/templates/md/_mixin.md
+++ b/lib/templates/md/_mixin.md
@@ -1,2 +1,2 @@
-{{#isDeprecated}}~~{{/isDeprecated}}{{{linkedName}}}{{{linkedGenericParameters}}} {{>categorization}}{{#isDeprecated}}~~{{/isDeprecated}}
+{{{linkedName}}}{{{linkedGenericParameters}}} {{>categorization}}
: {{{ oneLineDoc }}} {{{ extendedDocLink }}}
diff --git a/lib/templates/md/constructor.md b/lib/templates/md/constructor.md
index bd50ad17a1..ce897718a4 100644
--- a/lib/templates/md/constructor.md
+++ b/lib/templates/md/constructor.md
@@ -14,7 +14,7 @@
{{/hasAnnotations}}
{{#isConst}}const{{/isConst}}
-{{#isDeprecated}}~~{{/isDeprecated}}{{{nameWithGenerics}}}({{#hasParameters}}{{{linkedParamsLines}}}{{/hasParameters}}){{#isDeprecated}}~~{{/isDeprecated}}
+{{{nameWithGenerics}}}({{#hasParameters}}{{{linkedParamsLines}}}{{/hasParameters}})
{{>documentation}}
diff --git a/test/model_test.dart b/test/model_test.dart
index 5f4efdef7b..9fc8dbda34 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -373,6 +373,7 @@ void main() {
equals(utils.kTestPackagePublicLibraries - 5));
});
+ // TODO consider moving these to a separate suite
test('CategoryRendererHtml renders category label', () {
Category category = packageGraph.publicPackages.first.categories.first;
CategoryRendererHtml renderer = CategoryRendererHtml();
@@ -388,6 +389,20 @@ void main() {
expect(renderer.renderLinkedName(category),
'Superb');
});
+
+ test('CategoryRendererMd renders category label', () {
+ Category category = packageGraph.publicPackages.first.categories.first;
+ CategoryRendererMd renderer = CategoryRendererMd();
+ expect(renderer.renderCategoryLabel(category),
+ '[Superb](${HTMLBASE_PLACEHOLDER}topics/Superb-topic.html)');
+ });
+
+ test('CategoryRendererMd renders linkedName', () {
+ Category category = packageGraph.publicPackages.first.categories.first;
+ CategoryRendererMd renderer = CategoryRendererMd();
+ expect(renderer.renderLinkedName(category),
+ '[Superb](${HTMLBASE_PLACEHOLDER}topics/Superb-topic.html)');
+ });
});
group('LibraryContainer', () {
diff --git a/test/html/html_template_renderer_test.dart b/test/render/template_renderer_test.dart
similarity index 63%
rename from test/html/html_template_renderer_test.dart
rename to test/render/template_renderer_test.dart
index e0611b9b4d..577a3b4a4a 100644
--- a/test/html/html_template_renderer_test.dart
+++ b/test/render/template_renderer_test.dart
@@ -23,4 +23,22 @@ void main() {
expect(test, equals('Banana Fruit'));
});
});
+
+ group('MdTemplateRenderer', () {
+ MdTemplateRenderer renderer;
+
+ setUpAll(() {
+ renderer = MdTemplateRenderer();
+ });
+
+ test('composeLayoutTitle', () {
+ String test = renderer.composeLayoutTitle('Banana', 'Fruit', false);
+ expect(test, equals('Banana Fruit'));
+ });
+
+ test('composeLayoutTitle deprecated', () {
+ String test = renderer.composeLayoutTitle('Banana', 'Fruit', true);
+ expect(test, equals('~~Banana~~ Fruit'));
+ });
+ });
}