-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
XmlCommentsTextHelper.cs
116 lines (90 loc) · 3.85 KB
/
XmlCommentsTextHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
namespace Swashbuckle.AspNetCore.SwaggerGen
{
public static class XmlCommentsTextHelper
{
private static Regex RefTagPattern = new Regex(@"<(see|paramref) (name|cref|langword)=""([TPF]{1}:)?(?<display>.+?)"" ?/>");
private static Regex CodeTagPattern = new Regex(@"<c>(?<display>.+?)</c>");
private static Regex MultilineCodeTagPattern = new Regex(@"<code>(?<display>.+?)</code>", RegexOptions.Singleline);
private static Regex ParaTagPattern = new Regex(@"<para>(?<display>.+?)</para>", RegexOptions.Singleline);
public static string Humanize(string text)
{
if (text == null)
throw new ArgumentNullException("text");
//Call DecodeXml at last to avoid entities like < and > to break valid xml
return text
.NormalizeIndentation()
.HumanizeRefTags()
.HumanizeCodeTags()
.HumanizeMultilineCodeTags()
.HumanizeParaTags()
.DecodeXml();
}
private static string NormalizeIndentation(this string text)
{
string[] lines = text.Split('\n');
string padding = GetCommonLeadingWhitespace(lines);
int padLen = padding == null ? 0 : padding.Length;
// remove leading padding from each line
for (int i = 0, l = lines.Length; i < l; ++i)
{
string line = lines[i].TrimEnd('\r'); // remove trailing '\r'
if (padLen != 0 && line.Length >= padLen && line.Substring(0, padLen) == padding)
line = line.Substring(padLen);
lines[i] = line;
}
// remove leading empty lines, but not all leading padding
// remove all trailing whitespace, regardless
return string.Join("\r\n", lines.SkipWhile(x => string.IsNullOrWhiteSpace(x))).TrimEnd();
}
private static string GetCommonLeadingWhitespace(string[] lines)
{
if (null == lines)
throw new ArgumentException("lines");
if (lines.Length == 0)
return null;
string[] nonEmptyLines = lines
.Where(x => !string.IsNullOrWhiteSpace(x))
.ToArray();
if (nonEmptyLines.Length < 1)
return null;
int padLen = 0;
// use the first line as a seed, and see what is shared over all nonEmptyLines
string seed = nonEmptyLines[0];
for (int i = 0, l = seed.Length; i < l; ++i)
{
if (!char.IsWhiteSpace(seed, i))
break;
if (nonEmptyLines.Any(line => line[i] != seed[i]))
break;
++padLen;
}
if (padLen > 0)
return seed.Substring(0, padLen);
return null;
}
private static string HumanizeRefTags(this string text)
{
return RefTagPattern.Replace(text, (match) => match.Groups["display"].Value);
}
private static string HumanizeCodeTags(this string text)
{
return CodeTagPattern.Replace(text, (match) => "`" + match.Groups["display"].Value + "`");
}
private static string HumanizeMultilineCodeTags(this string text)
{
return MultilineCodeTagPattern.Replace(text, (match) => "```" + match.Groups["display"].Value + "```");
}
private static string HumanizeParaTags(this string text)
{
return ParaTagPattern.Replace(text, (match) => "<br>" + match.Groups["display"].Value);
}
private static string DecodeXml(this string text)
{
return WebUtility.HtmlDecode(text);
}
}
}