Skip to content

Commit 3e2dd15

Browse files
authored
Escape HTML in parameter default values (#2288)
1 parent 141322d commit 3e2dd15

File tree

3 files changed

+37
-12
lines changed

3 files changed

+37
-12
lines changed

lib/src/render/parameter_renderer.dart

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:convert';
6+
57
import 'package:analyzer/dart/element/type.dart';
68
import 'package:dartdoc/src/element_type.dart';
79
import 'package:dartdoc/src/model/parameter.dart';
10+
import 'package:meta/meta.dart' as meta;
811

912
/// Render HTML in an extended vertical format using <ol> tag.
1013
class ParameterRendererHtmlList extends ParameterRendererHtml {
@@ -27,8 +30,12 @@ class ParameterRendererHtml extends ParameterRenderer {
2730
@override
2831
String covariant(String covariant) => '<span>$covariant</span>';
2932
@override
30-
String defaultValue(String defaultValue) =>
31-
'<span class="default-value">$defaultValue</span>';
33+
String defaultValue(String defaultValue) {
34+
var escaped =
35+
const HtmlEscape(HtmlEscapeMode.unknown).convert(defaultValue);
36+
return '<span class="default-value">$escaped</span>';
37+
}
38+
3239
@override
3340
String parameter(String parameter, String htmlId) =>
3441
'<span class="parameter" id="${htmlId}">$parameter</span>';
@@ -93,34 +100,38 @@ abstract class ParameterRenderer {
93100
var positional = '', optional = '', named = '';
94101
if (positionalParams.isNotEmpty) {
95102
positional = _linkedParameterSublist(positionalParams,
96-
optionalPositionalParams.isNotEmpty || namedParams.isNotEmpty,
97-
showMetadata: showMetadata, showNames: showNames);
103+
trailingComma:
104+
optionalPositionalParams.isNotEmpty || namedParams.isNotEmpty,
105+
showMetadata: showMetadata,
106+
showNames: showNames);
98107
}
99108
if (optionalPositionalParams.isNotEmpty) {
100-
optional = _linkedParameterSublist(
101-
optionalPositionalParams, namedParams.isNotEmpty,
109+
optional = _linkedParameterSublist(optionalPositionalParams,
110+
trailingComma: namedParams.isNotEmpty,
102111
openBracket: '[',
103112
closeBracket: ']',
104113
showMetadata: showMetadata,
105114
showNames: showNames);
106115
}
107116
if (namedParams.isNotEmpty) {
108-
named = _linkedParameterSublist(namedParams, false,
117+
named = _linkedParameterSublist(namedParams,
118+
trailingComma: false,
109119
openBracket: '{',
110120
closeBracket: '}',
111121
showMetadata: showMetadata,
112122
showNames: showNames);
113123
}
114-
return (orderedList(positional + optional + named));
124+
return orderedList(positional + optional + named);
115125
}
116126

117-
String _linkedParameterSublist(List<Parameter> parameters, bool trailingComma,
118-
{String openBracket = '',
127+
String _linkedParameterSublist(List<Parameter> parameters,
128+
{@meta.required bool trailingComma,
129+
String openBracket = '',
119130
String closeBracket = '',
120131
showMetadata = true,
121132
showNames = true}) {
122133
var builder = StringBuffer();
123-
parameters.forEach((p) {
134+
for (var p in parameters) {
124135
var prefix = '';
125136
var suffix = '';
126137
if (identical(p, parameters.first)) {
@@ -136,7 +147,7 @@ abstract class ParameterRenderer {
136147
_renderParam(p, showMetadata: showMetadata, showNames: showNames);
137148
builder.write(
138149
listItem(parameter(prefix + renderedParam + suffix, p.htmlId)));
139-
});
150+
}
140151
return builder.toString();
141152
}
142153

test/model_test.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,17 @@ void main() {
22732273
expect(topLevelFunction.documentation, contains("['hello from dart']"));
22742274
});
22752275

2276+
test('escapes HTML in default values', () {
2277+
var topLevelFunction2 = fakeLibrary.functions
2278+
.firstWhere((f) => f.name == 'topLevelFunction2');
2279+
2280+
expect(
2281+
topLevelFunction2.linkedParamsLines,
2282+
contains('<span class="parameter-name">p3</span> = '
2283+
'<span class="default-value">const &lt;String, int&gt;{}</span>'
2284+
']</span>'));
2285+
});
2286+
22762287
test('has source code', () {
22772288
expect(topLevelFunction.sourceCode, startsWith('@deprecated'));
22782289
expect(topLevelFunction.sourceCode, endsWith('''

testing/test_package/lib/fake.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,9 @@ String topLevelFunction(int param1, bool param2, Cool coolBeans,
737737
return null;
738738
}
739739

740+
void topLevelFunction2(int p1, bool p2,
741+
[Map<String, int> p3 = const <String, int>{}]) {}
742+
740743
/// A single optional positional param, no type annotation, no default value.
741744
@greatAnnotation
742745
void onlyPositionalWithNoDefaultNoType([@greatestAnnotation anything]) {}

0 commit comments

Comments
 (0)