-
Notifications
You must be signed in to change notification settings - Fork 29
/
CodeNormalizer.cs
124 lines (109 loc) · 7.05 KB
/
CodeNormalizer.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
117
118
119
120
121
122
123
124
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace PublicApiGenerator
{
internal static class CodeNormalizer
{
const string AutoGeneratedHeader = @"^//-+\s*$.*^//-+\s*$";
const string EmptyGetSet = @"\s+{\s+get\s+{\s+}\s+set\s+{\s+}\s+}";
const string EmptyGet = @"\s+{\s+get\s+{\s+}\s+}";
const string EmptySet = @"\s+{\s+set\s+{\s+}\s+}";
const string GetSet = @"\s+{\s+get;\s+set;\s+}";
const string Get = @"\s+{\s+get;\s+}";
const string Set = @"\s+{\s+set;\s+}";
// https://github.com/PublicApiGenerator/PublicApiGenerator/issues/80
internal const string StaticMarker = "static_C91E2709_C00B-4CAB_8BBC_B2B11DC75E50 ";
internal const string ReadonlyMarker = "readonly_79D3ED2A_0B60_4C3B_8432_941FE471A38B ";
internal const string AttributeMarker = "_attribute_292C96C3_C42E_4C07_BEED_73F5DAA0A6DF_";
internal const string EventModifierMarkerTemplate = "_{0}_292C96C3C42E4C07BEED73F5DAA0A6DF_";
internal const string EventRemovePublicMarker = "removepublic";
internal const string MethodModifierMarkerTemplate = "_{0}_3C0D97CD952D40AA8B6E1ECB98FFC79F_";
internal const string PropertyModifierMarkerTemplate = "_{0}_5DB9F56043FF464997155541DA321AD4_";
public static string NormalizeMethodName(string methodName)
{
return Regex.Replace(methodName, @"(_(.*)_3C0D97CD952D40AA8B6E1ECB98FFC79F_)?", string.Empty);
}
public static string NormalizeGeneratedCode(StringWriter writer)
{
var gennedClass = writer.ToString();
gennedClass = Regex.Replace(gennedClass, AutoGeneratedHeader, string.Empty,
RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.Singleline);
gennedClass = Regex.Replace(gennedClass, EmptyGetSet, " { get; set; }",
RegexOptions.IgnorePatternWhitespace);
gennedClass = Regex.Replace(gennedClass, GetSet, " { get; set; }", RegexOptions.IgnorePatternWhitespace);
gennedClass = Regex.Replace(gennedClass, EmptyGet, " { get; }", RegexOptions.IgnorePatternWhitespace);
gennedClass = Regex.Replace(gennedClass, EmptySet, " { set; }", RegexOptions.IgnorePatternWhitespace);
gennedClass = Regex.Replace(gennedClass, Get, " { get; }", RegexOptions.IgnorePatternWhitespace);
gennedClass = Regex.Replace(gennedClass, Set, " { set; }", RegexOptions.IgnorePatternWhitespace);
gennedClass = Regex.Replace(gennedClass, @"\s+{\s+}", " { }", RegexOptions.IgnorePatternWhitespace);
gennedClass = Regex.Replace(gennedClass, @"\)\s+;", ");", RegexOptions.IgnorePatternWhitespace);
var attributeMarkerEscaped = Regex.Escape(AttributeMarker);
gennedClass = Regex.Replace(gennedClass, $@"
(Attribute)? # Delete this if present. Would create a clash for Attribute1, Attribute1Attribute but that is a very rare edge case
( # Then require:
{attributeMarkerEscaped}(\(\))?(?=\]) # - Empty parens (to delete) if present, immediately followed by closing square brace (not deleted),
|
{attributeMarkerEscaped}(?=\(.+\)\]) # - or non-empty parens immediately followed by closing square brace (not deleted).
|
{attributeMarkerEscaped}(?=new.+\}}\)\])) # - or non-empty parens immediately followed by new, closing curlies, closing brace and square brace to cover new object [] {{ }} cases (not deleted).
",
string.Empty,
RegexOptions.Singleline |
RegexOptions.IgnorePatternWhitespace); // SingleLine is required for multi line params arrays
gennedClass = Regex.Replace(gennedClass, @"(public|protected) (.*) _(.*)_292C96C3C42E4C07BEED73F5DAA0A6DF_(.*)", EventModifierMatcher);
gennedClass = Regex.Replace(gennedClass, @"(public|protected)( abstract | static | new static | virtual | override | new | unsafe | )(.*) _(.*)_5DB9F56043FF464997155541DA321AD4_(.*)", PropertyModifierMatcher);
gennedClass = Regex.Replace(gennedClass, @"(public|protected)( abstract | static | new static | virtual | override | new | unsafe | )(.*) _(.*)_3C0D97CD952D40AA8B6E1ECB98FFC79F_(.*)", MethodModifierMatcher);
gennedClass = gennedClass.Replace("class " + StaticMarker, "static class ");
gennedClass = gennedClass.Replace("struct " + ReadonlyMarker, "readonly struct ");
gennedClass = gennedClass.Replace(ReadonlyMarker, string.Empty); // remove magic marker from readonly struct ctor
gennedClass = Regex.Replace(gennedClass, @"\r\n|\n\r|\r|\n", Environment.NewLine);
gennedClass = RemoveUnnecessaryWhiteSpace(gennedClass);
return gennedClass;
}
static string EventModifierMatcher(Match match)
{
var visibility = match.Groups[1].Value;
var modifier = match.Groups[3].Value;
var replacementBuilder = new StringBuilder();
if (modifier.EndsWith(EventRemovePublicMarker))
{
replacementBuilder.Append(modifier == EventRemovePublicMarker
? "event "
: $"{modifier.Replace(EventRemovePublicMarker, string.Empty)} event ");
}
else
{
replacementBuilder.Append($"{visibility} {modifier} event ");
}
return match.ToString().Replace(string.Format(EventModifierMarkerTemplate, modifier), string.Empty)
.Replace($"{visibility} event ", replacementBuilder.ToString());
}
static string PropertyModifierMatcher(Match match)
{
var oldModifier = match.Groups[2].Value;
var modifier = match.Groups[4].Value;
var s = match.ToString().Replace(string.Format(PropertyModifierMarkerTemplate, modifier), string.Empty);
return string.IsNullOrWhiteSpace(oldModifier) ? s.Insert(s.IndexOf(oldModifier, StringComparison.Ordinal), modifier) : s.Replace(oldModifier, modifier);
}
static string MethodModifierMatcher(Match match)
{
var oldModifier = match.Groups[2].Value;
var modifier = match.Groups[4].Value;
var s = match.ToString().Replace(string.Format(MethodModifierMarkerTemplate, modifier), string.Empty);
return string.IsNullOrWhiteSpace(oldModifier) ? s.Insert(s.IndexOf(oldModifier, StringComparison.Ordinal), modifier) : s.Replace(oldModifier, modifier);
}
static string RemoveUnnecessaryWhiteSpace(string publicApi)
{
return string.Join(Environment.NewLine, publicApi.Split(new[]
{
Environment.NewLine
}, StringSplitOptions.RemoveEmptyEntries)
.Where(l => !string.IsNullOrWhiteSpace(l))
.Select(l => l.TrimEnd())
);
}
}
}