Relocate ParameterRenderer alongside CategoryRenderer (#2077)

* Move parameter renderer into the new render library directory

* copyright date

* optimize import
diff --git a/lib/src/element_type.dart b/lib/src/element_type.dart
index 5f026fa..a3a8b85 100644
--- a/lib/src/element_type.dart
+++ b/lib/src/element_type.dart
@@ -11,7 +11,7 @@
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:dartdoc/src/model/model.dart';
-import 'package:dartdoc/src/model_utils.dart';
+import 'package:dartdoc/src/render/parameter_renderer.dart';
 
 /// Base class representing a type in Dartdoc.  It wraps a [DartType], and
 /// may link to a [ModelElement].
@@ -147,7 +147,7 @@
       buf.write('${returnType.linkedName} ');
       buf.write('${nameWithGenerics}');
       buf.write('<span class="signature">');
-      buf.write('(${linkedParams(parameters)})');
+      buf.write('(${ParameterRendererHtml().renderLinkedParams(parameters)})');
       buf.write('</span>');
       _linkedName = buf.toString();
     }
@@ -418,7 +418,7 @@
   @override
   String get linkedName {
     if (name != null && name.isNotEmpty) return super.linkedName;
-    return '${nameWithGenerics}(${linkedParams(element.parameters, showNames: false).trim()}) → ${returnType.linkedName}';
+    return '${nameWithGenerics}(${ParameterRendererHtml(showNames: false).renderLinkedParams(element.parameters).trim()}) → ${returnType.linkedName}';
   }
 }
 
@@ -435,7 +435,7 @@
   String get linkedName {
     if (_linkedName == null) {
       _linkedName =
-          '${returnType.linkedName} ${super.linkedName}<span class="signature">(${linkedParams(element.parameters)})</span>';
+          '${returnType.linkedName} ${super.linkedName}<span class="signature">(${ParameterRendererHtml().renderLinkedParams(element.parameters)})</span>';
     }
     return _linkedName;
   }
diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart
index 29e54b5..e09ba79 100644
--- a/lib/src/model/model_element.dart
+++ b/lib/src/model/model_element.dart
@@ -26,6 +26,7 @@
 import 'package:dartdoc/src/markdown_processor.dart' show Documentation;
 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/source_linker.dart';
 import 'package:dartdoc/src/tuple.dart';
 import 'package:dartdoc/src/utils.dart';
@@ -928,18 +929,18 @@
     return _linkedName;
   }
 
-  String get linkedParams => utils.linkedParams(parameters);
+  String get linkedParams =>
+      ParameterRendererHtml().renderLinkedParams(parameters);
 
   String get linkedParamsLines =>
-      utils.linkedParams(parameters, asList: true).trim();
+      ParameterRendererHtmlList().renderLinkedParams(parameters).trim();
 
   String get linkedParamsNoMetadata =>
-      utils.linkedParams(parameters, showMetadata: false);
+      ParameterRendererHtml(showMetadata: false).renderLinkedParams(parameters);
 
-  String get linkedParamsNoMetadataOrNames {
-    return utils.linkedParams(parameters,
-        showMetadata: false, showNames: false);
-  }
+  String get linkedParamsNoMetadataOrNames =>
+      ParameterRendererHtml(showMetadata: false, showNames: false)
+          .renderLinkedParams(parameters);
 
   ElementType get modelType {
     if (_modelType == null) {
diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart
index 22d9afe..8c88c72 100644
--- a/lib/src/model_utils.dart
+++ b/lib/src/model_utils.dart
@@ -9,193 +9,11 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:dartdoc/src/model/model.dart';
-import 'package:dartdoc/src/element_type.dart';
 
 final Map<String, String> _fileContents = <String, String>{};
 
-/// Render HTML in an extended vertical format using <ol> tag.
-class ParameterRendererHtmlList extends ParameterRendererHtml {
-  ParameterRendererHtmlList({bool showMetadata = true, bool showNames = true})
-      : super(showMetadata: showMetadata, showNames: showNames);
-  @override
-  String listItem(String listItem) => '<li>$listItem</li>\n';
-  @override
-  // TODO(jcollins-g): consider comma separated lists and more advanced css.
-  String orderedList(String listItems) =>
-      '<ol class="parameter-list">$listItems</ol>\n';
-}
-
-/// Render HTML suitable for a single, wrapped line.
-class ParameterRendererHtml extends ParameterRenderer {
-  @override
-  final bool showMetadata;
-  @override
-  final bool showNames;
-  ParameterRendererHtml({this.showMetadata = true, this.showNames = true});
-
-  @override
-  String listItem(String listItem) => '${listItem}<wbr>';
-  @override
-  String orderedList(String listItems) => listItems;
-  @override
-  String annotation(String annotation) => '<span>$annotation</span>';
-  @override
-  String covariant(String covariant) => '<span>$covariant</span>';
-  @override
-  String defaultValue(String defaultValue) =>
-      '<span class="default-value">$defaultValue</span>';
-  @override
-  String parameter(String parameter, String htmlId) =>
-      '<span class="parameter" id="${htmlId}">$parameter</span>';
-  @override
-  String parameterName(String parameterName) =>
-      '<span class="parameter-name">$parameterName</span>';
-  @override
-  String typeName(String typeName) =>
-      '<span class="type-annotation">$typeName</span>';
-  @override
-  String required(String required) => '<span>$required</span>';
-}
-
-abstract class ParameterRenderer {
-  bool get showMetadata;
-  bool get showNames;
-
-  String listItem(String item);
-  String orderedList(String listItems);
-  String annotation(String annotation);
-  String covariant(String covariant);
-  String defaultValue(String defaultValue);
-  String parameter(String parameter, String id);
-  String parameterName(String parameterName);
-  String typeName(String typeName);
-  String required(String required);
-
-  String _linkedParameterSublist(List<Parameter> parameters, bool trailingComma,
-      {String thisOpenBracket = '', String thisCloseBracket = ''}) {
-    StringBuffer builder = StringBuffer();
-    parameters.forEach((p) {
-      String prefix = '';
-      String suffix = '';
-      if (identical(p, parameters.first)) {
-        prefix = thisOpenBracket;
-      }
-      if (identical(p, parameters.last)) {
-        suffix += thisCloseBracket;
-        if (trailingComma) suffix += ', ';
-      } else {
-        suffix += ', ';
-      }
-      builder.write(
-          listItem(parameter(prefix + renderParam(p) + suffix, p.htmlId)));
-    });
-    return builder.toString();
-  }
-
-  String linkedParams(List<Parameter> parameters) {
-    List<Parameter> positionalParams =
-        parameters.where((Parameter p) => p.isRequiredPositional).toList();
-    List<Parameter> optionalPositionalParams =
-        parameters.where((Parameter p) => p.isOptionalPositional).toList();
-    List<Parameter> namedParams =
-        parameters.where((Parameter p) => p.isNamed).toList();
-
-    String positional = '', optional = '', named = '';
-    if (positionalParams.isNotEmpty) {
-      positional = _linkedParameterSublist(positionalParams,
-          optionalPositionalParams.isNotEmpty || namedParams.isNotEmpty);
-    }
-    if (optionalPositionalParams.isNotEmpty) {
-      optional = _linkedParameterSublist(
-          optionalPositionalParams, namedParams.isNotEmpty,
-          thisOpenBracket: '[', thisCloseBracket: ']');
-    }
-    if (namedParams.isNotEmpty) {
-      named = _linkedParameterSublist(namedParams, false,
-          thisOpenBracket: '{', thisCloseBracket: '}');
-    }
-    return (orderedList(positional + optional + named));
-  }
-
-  String renderParam(Parameter param) {
-    StringBuffer buf = StringBuffer();
-    ElementType paramModelType = param.modelType;
-
-    if (showMetadata && param.hasAnnotations) {
-      buf.write(param.annotations.map(annotation).join(' ') + ' ');
-    }
-    if (param.isRequiredNamed) {
-      buf.write(required('required') + ' ');
-    }
-    if (param.isCovariant) {
-      buf.write(covariant('covariant') + ' ');
-    }
-    if (paramModelType is CallableElementTypeMixin ||
-        paramModelType.type is FunctionType) {
-      String returnTypeName;
-      if (paramModelType.isTypedef) {
-        returnTypeName = paramModelType.linkedName;
-      } else {
-        returnTypeName = paramModelType.createLinkedReturnTypeName();
-      }
-      buf.write(typeName(returnTypeName));
-      if (showNames) {
-        buf.write(' ${parameterName(param.name)}');
-      } else if (paramModelType.isTypedef ||
-          paramModelType is CallableAnonymousElementType ||
-          paramModelType.type is FunctionType) {
-        buf.write(' ${parameterName(paramModelType.name)}');
-      }
-      if (!paramModelType.isTypedef && paramModelType is DefinedElementType) {
-        buf.write('(');
-        buf.write(linkedParams(paramModelType.element.parameters));
-        buf.write(')');
-      }
-      if (!paramModelType.isTypedef && paramModelType.type is FunctionType) {
-        buf.write('(');
-        buf.write(
-            linkedParams((paramModelType as UndefinedElementType).parameters));
-        buf.write(')');
-      }
-    } else if (param.modelType != null) {
-      String linkedTypeName = paramModelType.linkedName;
-      if (linkedTypeName.isNotEmpty) {
-        buf.write(typeName(linkedTypeName));
-        if (showNames && param.name.isNotEmpty) {
-          buf.write(' ');
-        }
-      }
-      if (showNames && param.name.isNotEmpty) {
-        buf.write(parameterName(param.name));
-      }
-    }
-
-    if (param.hasDefaultValue) {
-      if (param.isNamed) {
-        buf.write(': ');
-      } else {
-        buf.write(' = ');
-      }
-      buf.write(defaultValue(param.defaultValue));
-    }
-    return buf.toString();
-  }
-}
-
-String linkedParams(List<Parameter> parameters,
-    {showMetadata = true, showNames = true, asList = false}) {
-  if (asList) {
-    return ParameterRendererHtmlList(
-            showMetadata: showMetadata, showNames: showNames)
-        .linkedParams(parameters);
-  }
-  return ParameterRendererHtml(showMetadata: showMetadata, showNames: showNames)
-      .linkedParams(parameters);
-}
-
 /// Returns the [AstNode] for a given [Element].
 ///
 /// Uses a precomputed map of [element.source.fullName] to [CompilationUnit]
diff --git a/lib/src/render/parameter_renderer.dart b/lib/src/render/parameter_renderer.dart
new file mode 100644
index 0000000..f4998c9
--- /dev/null
+++ b/lib/src/render/parameter_renderer.dart
@@ -0,0 +1,176 @@
+// 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:analyzer/dart/element/type.dart';
+import 'package:dartdoc/src/element_type.dart';
+import 'package:dartdoc/src/model/parameter.dart';
+
+/// Render HTML in an extended vertical format using <ol> tag.
+class ParameterRendererHtmlList extends ParameterRendererHtml {
+  ParameterRendererHtmlList({bool showMetadata = true, bool showNames = true})
+      : super(showMetadata: showMetadata, showNames: showNames);
+  @override
+  String listItem(String listItem) => '<li>$listItem</li>\n';
+  @override
+  // TODO(jcollins-g): consider comma separated lists and more advanced css.
+  String orderedList(String listItems) =>
+      '<ol class="parameter-list">$listItems</ol>\n';
+}
+
+/// Render HTML suitable for a single, wrapped line.
+class ParameterRendererHtml extends ParameterRenderer {
+  @override
+  final bool showMetadata;
+  @override
+  final bool showNames;
+  ParameterRendererHtml({this.showMetadata = true, this.showNames = true});
+
+  @override
+  String listItem(String listItem) => '${listItem}<wbr>';
+  @override
+  String orderedList(String listItems) => listItems;
+  @override
+  String annotation(String annotation) => '<span>$annotation</span>';
+  @override
+  String covariant(String covariant) => '<span>$covariant</span>';
+  @override
+  String defaultValue(String defaultValue) =>
+      '<span class="default-value">$defaultValue</span>';
+  @override
+  String parameter(String parameter, String htmlId) =>
+      '<span class="parameter" id="${htmlId}">$parameter</span>';
+  @override
+  String parameterName(String parameterName) =>
+      '<span class="parameter-name">$parameterName</span>';
+  @override
+  String typeName(String typeName) =>
+      '<span class="type-annotation">$typeName</span>';
+  @override
+  String required(String required) => '<span>$required</span>';
+}
+
+abstract class ParameterRenderer {
+  bool get showMetadata;
+  bool get showNames;
+
+  String listItem(String item);
+  String orderedList(String listItems);
+  String annotation(String annotation);
+  String covariant(String covariant);
+  String defaultValue(String defaultValue);
+  String parameter(String parameter, String id);
+  String parameterName(String parameterName);
+  String typeName(String typeName);
+  String required(String required);
+
+  String _linkedParameterSublist(List<Parameter> parameters, bool trailingComma,
+      {String thisOpenBracket = '', String thisCloseBracket = ''}) {
+    StringBuffer builder = StringBuffer();
+    parameters.forEach((p) {
+      String prefix = '';
+      String suffix = '';
+      if (identical(p, parameters.first)) {
+        prefix = thisOpenBracket;
+      }
+      if (identical(p, parameters.last)) {
+        suffix += thisCloseBracket;
+        if (trailingComma) suffix += ', ';
+      } else {
+        suffix += ', ';
+      }
+      builder.write(
+          listItem(parameter(prefix + renderParam(p) + suffix, p.htmlId)));
+    });
+    return builder.toString();
+  }
+
+  String renderLinkedParams(List<Parameter> parameters) {
+    List<Parameter> positionalParams =
+        parameters.where((Parameter p) => p.isRequiredPositional).toList();
+    List<Parameter> optionalPositionalParams =
+        parameters.where((Parameter p) => p.isOptionalPositional).toList();
+    List<Parameter> namedParams =
+        parameters.where((Parameter p) => p.isNamed).toList();
+
+    String positional = '', optional = '', named = '';
+    if (positionalParams.isNotEmpty) {
+      positional = _linkedParameterSublist(positionalParams,
+          optionalPositionalParams.isNotEmpty || namedParams.isNotEmpty);
+    }
+    if (optionalPositionalParams.isNotEmpty) {
+      optional = _linkedParameterSublist(
+          optionalPositionalParams, namedParams.isNotEmpty,
+          thisOpenBracket: '[', thisCloseBracket: ']');
+    }
+    if (namedParams.isNotEmpty) {
+      named = _linkedParameterSublist(namedParams, false,
+          thisOpenBracket: '{', thisCloseBracket: '}');
+    }
+    return (orderedList(positional + optional + named));
+  }
+
+  String renderParam(Parameter param) {
+    StringBuffer buf = StringBuffer();
+    ElementType paramModelType = param.modelType;
+
+    if (showMetadata && param.hasAnnotations) {
+      buf.write(param.annotations.map(annotation).join(' ') + ' ');
+    }
+    if (param.isRequiredNamed) {
+      buf.write(required('required') + ' ');
+    }
+    if (param.isCovariant) {
+      buf.write(covariant('covariant') + ' ');
+    }
+    if (paramModelType is CallableElementTypeMixin ||
+        paramModelType.type is FunctionType) {
+      String returnTypeName;
+      if (paramModelType.isTypedef) {
+        returnTypeName = paramModelType.linkedName;
+      } else {
+        returnTypeName = paramModelType.createLinkedReturnTypeName();
+      }
+      buf.write(typeName(returnTypeName));
+      if (showNames) {
+        buf.write(' ${parameterName(param.name)}');
+      } else if (paramModelType.isTypedef ||
+          paramModelType is CallableAnonymousElementType ||
+          paramModelType.type is FunctionType) {
+        buf.write(' ${parameterName(paramModelType.name)}');
+      }
+      if (!paramModelType.isTypedef && paramModelType is DefinedElementType) {
+        buf.write('(');
+        buf.write(renderLinkedParams(paramModelType.element.parameters));
+        buf.write(')');
+      }
+      if (!paramModelType.isTypedef && paramModelType.type is FunctionType) {
+        buf.write('(');
+        buf.write(renderLinkedParams(
+            (paramModelType as UndefinedElementType).parameters));
+        buf.write(')');
+      }
+    } else if (param.modelType != null) {
+      String linkedTypeName = paramModelType.linkedName;
+      if (linkedTypeName.isNotEmpty) {
+        buf.write(typeName(linkedTypeName));
+        if (showNames && param.name.isNotEmpty) {
+          buf.write(' ');
+        }
+      }
+      if (showNames && param.name.isNotEmpty) {
+        buf.write(parameterName(param.name));
+      }
+    }
+
+    if (param.hasDefaultValue) {
+      if (param.isNamed) {
+        buf.write(': ');
+      } else {
+        buf.write(' = ');
+      }
+      buf.write(defaultValue(param.defaultValue));
+    }
+    return buf.toString();
+  }
+}
diff --git a/test/model_test.dart b/test/model_test.dart
index 55fc10e..ccc3970 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -8,8 +8,8 @@
 
 import 'package:dartdoc/dartdoc.dart';
 import 'package:dartdoc/src/model/model.dart';
-import 'package:dartdoc/src/model_utils.dart';
 import 'package:dartdoc/src/render/category_renderer.dart';
+import 'package:dartdoc/src/render/parameter_renderer.dart';
 import 'package:dartdoc/src/warnings.dart';
 import 'package:test/test.dart';
 
@@ -2084,7 +2084,8 @@
     });
 
     test('handles dynamic parameters correctly', () {
-      expect(linkedParams(f1.parameters), contains('lastParam'));
+      expect(ParameterRendererHtml().renderLinkedParams(f1.parameters),
+          contains('lastParam'));
     });
 
     test('async function', () {
@@ -2123,7 +2124,8 @@
 
     test('function with a parameter having type FutureOr<Null>', () {
       expect(
-          linkedParams(paramOfFutureOrNull.parameters),
+          ParameterRendererHtml()
+              .renderLinkedParams(paramOfFutureOrNull.parameters),
           equals(
               '<span class="parameter" id="paramOfFutureOrNull-param-future"><span class="type-annotation">FutureOr<span class="signature">&lt;<wbr><span class="type-parameter">Null</span>&gt;</span></span> <span class="parameter-name">future</span></span><wbr>'));
     });
@@ -2151,7 +2153,8 @@
     test('typedef params have proper signature', () {
       ModelFunction function =
           fakeLibrary.functions.firstWhere((f) => f.name == 'addCallback');
-      String params = linkedParams(function.parameters);
+      String params =
+          ParameterRendererHtml().renderLinkedParams(function.parameters);
       expect(
           params,
           '<span class="parameter" id="addCallback-param-callback">'
@@ -2160,7 +2163,7 @@
 
       function =
           fakeLibrary.functions.firstWhere((f) => f.name == 'addCallback2');
-      params = linkedParams(function.parameters);
+      params = ParameterRendererHtml().renderLinkedParams(function.parameters);
       expect(
           params,
           '<span class="parameter" id="addCallback2-param-callback">'
@@ -2174,7 +2177,8 @@
     });
 
     test('can resolve functions as parameters', () {
-      String params = linkedParams(doAComplicatedThing.parameters);
+      String params = ParameterRendererHtml()
+          .renderLinkedParams(doAComplicatedThing.parameters);
       expect(params,
           '<span class="parameter" id="doAComplicatedThing-param-x"><span class="type-annotation">int</span> <span class="parameter-name">x</span>, </span><wbr><span class="parameter" id="doAComplicatedThing-param-doSomething">{<span class="type-annotation">void</span> <span class="parameter-name">doSomething</span>(<span class="parameter" id="param-aThingParameter"><span class="type-annotation">int</span> <span class="parameter-name">aThingParameter</span>, </span><wbr><span class="parameter" id="param-anotherThing"><span class="type-annotation">String</span> <span class="parameter-name">anotherThing</span></span><wbr>), </span><wbr><span class="parameter" id="doAComplicatedThing-param-doSomethingElse"><span class="type-annotation">void</span> <span class="parameter-name">doSomethingElse</span>(<span class="parameter" id="param-aThingParameter"><span class="type-annotation">int</span> <span class="parameter-name">aThingParameter</span>, </span><wbr><span class="parameter" id="param-somethingElse"><span class="type-annotation">double</span> <span class="parameter-name">somethingElse</span></span><wbr>)}</span><wbr>');
     });
@@ -2292,7 +2296,9 @@
           .singleWhere((m) => m.name == 'operator +');
       expect(aInheritedAdditionOperator.linkedReturnType,
           '<a href="ex/ParameterizedClass-class.html">ParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span>');
-      expect(linkedParams(aInheritedAdditionOperator.parameters),
+      expect(
+          ParameterRendererHtml()
+              .renderLinkedParams(aInheritedAdditionOperator.parameters),
           '<span class="parameter" id="+-param-other"><span class="type-annotation"><a href="ex/ParameterizedClass-class.html">ParameterizedClass</a><span class="signature">&lt;<wbr><span class="type-parameter">List<span class="signature">&lt;<wbr><span class="type-parameter">int</span>&gt;</span></span>&gt;</span></span> <span class="parameter-name">other</span></span><wbr>');
     });
 
@@ -3258,8 +3264,8 @@
 
     test('a function requiring a Future<void> parameter', () {
       expect(
-          linkedParams(aVoidParameter.parameters,
-              showMetadata: true, showNames: true),
+          ParameterRendererHtml(showMetadata: true, showNames: true)
+              .renderLinkedParams(aVoidParameter.parameters),
           equals(
               '<span class="parameter" id="aVoidParameter-param-p1"><span class="type-annotation">Future<span class="signature">&lt;<wbr><span class="type-parameter">void</span>&gt;</span></span> <span class="parameter-name">p1</span></span><wbr>'));
     });
@@ -3341,7 +3347,7 @@
         () {
       Constructor theConstructor = TypedefUsingClass.constructors.first;
       expect(
-          linkedParams(theConstructor.parameters),
+          ParameterRendererHtml().renderLinkedParams(theConstructor.parameters),
           equals(
               '<span class="parameter" id="-param-x"><span class="type-annotation"><a href="ex/ParameterizedTypedef.html">ParameterizedTypedef</a><span class="signature">&lt;<wbr><span class="type-parameter">double</span>&gt;</span></span> <span class="parameter-name">x</span></span><wbr>'));
     });
@@ -3488,21 +3494,24 @@
     });
 
     test('param with generics', () {
-      var params = linkedParams(methodWithGenericParam.parameters);
+      var params = ParameterRendererHtml()
+          .renderLinkedParams(methodWithGenericParam.parameters);
       expect(params.contains('List') && params.contains('Apple'), isTrue);
     });
 
     test('commas on same param line', () {
       ModelFunction method =
           fakeLibrary.functions.firstWhere((f) => f.name == 'paintImage1');
-      String params = linkedParams(method.parameters);
+      String params =
+          ParameterRendererHtml().renderLinkedParams(method.parameters);
       expect(params, contains(', </span>'));
     });
 
     test('param with annotations', () {
       ModelFunction method =
           fakeLibrary.functions.firstWhere((f) => f.name == 'paintImage1');
-      String params = linkedParams(method.parameters);
+      String params =
+          ParameterRendererHtml().renderLinkedParams(method.parameters);
       expect(params, contains('@required'));
     });
 
@@ -3513,7 +3522,8 @@
     });
 
     test('typedef param is linked and does not include types', () {
-      var params = linkedParams(methodWithTypedefParam.parameters);
+      var params = ParameterRendererHtml()
+          .renderLinkedParams(methodWithTypedefParam.parameters);
       expect(
           params,
           equals(