Skip to content

Commit

Permalink
leverage generated regex
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonCropp committed Nov 6, 2024
1 parent 65f9bed commit 05c2252
Show file tree
Hide file tree
Showing 20 changed files with 181 additions and 128 deletions.
10 changes: 4 additions & 6 deletions src/Docfx.Build.OverwriteDocuments/OverwriteUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@

namespace Docfx.Build.OverwriteDocuments;

public static class OverwriteUtility
public static partial class OverwriteUtility
{
private static readonly string[] UidWrappers = ["`", "``", "```", "````", "`````", "``````"];

private static readonly Regex OPathRegex =
new(
@"^(?<propertyName>[:A-Za-z_](?>[\w\.\-:]*))(?:\[\s*(?<key>[:A-Za-z_](?>[\w\.\-:]*))\s*=\s*(?:""(?<value>(?:(?>[^""\\]*)|\\.)*)"")\s*\])?(?:\/|$)",
RegexOptions.Compiled);
[GeneratedRegex(@"^(?<propertyName>[:A-Za-z_](?>[\w\.\-:]*))(?:\[\s*(?<key>[:A-Za-z_](?>[\w\.\-:]*))\s*=\s*(?:""(?<value>(?:(?>[^""\\]*)|\\.)*)"")\s*\])?(?:\/|$)")]
private static partial Regex OPathRegex();

public static List<OPathSegment> ParseOPath(string OPathString)
{
Expand All @@ -33,7 +31,7 @@ public static List<OPathSegment> ParseOPath(string OPathString)
var leftString = OPathString;
while (leftString.Length > 0)
{
var match = OPathRegex.Match(leftString);
var match = OPathRegex().Match(leftString);
if (match.Length == 0)
{
throw new ArgumentException($"{OPathString} is not a valid OPath");
Expand Down
9 changes: 5 additions & 4 deletions src/Docfx.Build.RestApi/SwaggerModelConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace Docfx.Build.RestApi;

public static class SwaggerModelConverter
public static partial class SwaggerModelConverter
{
public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger)
{
Expand Down Expand Up @@ -106,7 +106,9 @@ public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger)

#region Private methods

private static readonly Regex HtmlEncodeRegex = new(@"\W", RegexOptions.Compiled);
[GeneratedRegex(@"\W")]
private static partial Regex HtmlEncodeRegex();

private const string TagText = "tag";
private static readonly string[] OperationNames = ["get", "put", "post", "delete", "options", "head", "patch"];

Expand All @@ -118,7 +120,7 @@ public static RestApiRootItemViewModel FromSwaggerModel(SwaggerModel swagger)
private static string GetHtmlId(string id)
{
if (string.IsNullOrEmpty(id)) return null;
return HtmlEncodeRegex.Replace(id, "_");
return HtmlEncodeRegex().Replace(id, "_");
}

private static string GetUid(SwaggerModel swagger)
Expand Down Expand Up @@ -194,6 +196,5 @@ private static string GetMetadataStringValue(ParameterObject parameter, string m
}
return null;
}

#endregion
}
8 changes: 5 additions & 3 deletions src/Docfx.Build/PostProcessors/ExtractSearchIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
namespace Docfx.Build.Engine;

[Export(nameof(ExtractSearchIndex), typeof(IPostProcessor))]
class ExtractSearchIndex : IPostProcessor
partial class ExtractSearchIndex : IPostProcessor
{
private static readonly Regex s_regexWhiteSpace = new(@"\s+", RegexOptions.Compiled);
[GeneratedRegex(@"\s+")]
private static partial Regex s_regexWhiteSpace();

private static readonly HashSet<string> s_htmlInlineTags = new(StringComparer.OrdinalIgnoreCase)
{
"a", "area", "del", "ins", "link", "map", "meta", "abbr", "audio", "b", "bdo", "button", "canvas", "cite", "code", "command", "data",
Expand Down Expand Up @@ -136,7 +138,7 @@ private static string NormalizeContent(string str)
return string.Empty;
}
str = WebUtility.HtmlDecode(str);
return s_regexWhiteSpace.Replace(str, " ").Trim();
return s_regexWhiteSpace().Replace(str, " ").Trim();
}

private static void ExtractTextFromNode(HtmlNode node, StringBuilder contentBuilder)
Expand Down
78 changes: 41 additions & 37 deletions src/Docfx.Build/TableOfContents/MarkdownTocReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Docfx.Build.TableOfContents;

public static class MarkdownTocReader
public static partial class MarkdownTocReader
{
private const string ContinuableCharacters = ".,;:!?~";
private const string StopCharacters = @"\s\""\'<>";
Expand Down Expand Up @@ -166,20 +166,22 @@ protected ParseState ApplyCore(ParseState state, int level, string text, string
/// 2. # [tocTitle](@uid)
/// 3. # [tocTitle](xref:uid)
/// </summary>
internal sealed class TopicTocParseRule : ParseRule
internal sealed partial class TopicTocParseRule : ParseRule
{
private static readonly Regex UidRegex = new(@"^\s*(?:xref:|@)(\s*?\S+?[\s\S]*?)\s*$", RegexOptions.Compiled);
public static readonly Regex TocRegex =
new(@"^(?<headerLevel>#+)(( |\t)*)\[(?<tocTitle>.+)\]\((?<tocLink>(?!http[s]?://).*?)(\)| ""(?<displayText>.*)""\))(?:( |\t)+#*)?( |\t)*(\n|$)", RegexOptions.Compiled);
[GeneratedRegex(@"^\s*(?:xref:|@)(\s*?\S+?[\s\S]*?)\s*$")]
private static partial Regex UidRegex();

public override Match Match(string text) => TocRegex.Match(text);
[GeneratedRegex(@"^(?<headerLevel>#+)(( |\t)*)\[(?<tocTitle>.+)\]\((?<tocLink>(?!http[s]?://).*?)(\)| ""(?<displayText>.*)""\))(?:( |\t)+#*)?( |\t)*(\n|$)")]
private static partial Regex TocRegex();

public override Match Match(string text) => TocRegex().Match(text);

public override ParseState Apply(ParseState state, Match match)
{
var tocLink = match.Groups["tocLink"].Value;
var tocTitle = match.Groups["tocTitle"].Value;
var headerLevel = match.Groups["headerLevel"].Value.Length;
var uidMatch = UidRegex.Match(tocLink);
var uidMatch = UidRegex().Match(tocLink);
string tocDisplayTitle = null;

var displayGrp = match.Groups["displayText"];
Expand All @@ -202,19 +204,20 @@ public override ParseState Apply(ParseState state, Match match)
/// 1. <xref:uid>
/// 2. <xref:"uid_containing_spaces_or_greator_than_symbol">
/// </summary>
internal sealed class TopicXrefAutoLinkTocParseRule : ParseRule
internal sealed partial class TopicXrefAutoLinkTocParseRule : ParseRule
{
public static readonly Regex XrefAutoLinkTocRegex =
new($@"^(#+)(?: |\t)*{XrefAutoLinkRegexString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled);
public static readonly Regex XrefAutoLinkWithQuoteTocRegex =
new($@"^(#+)(?: |\t)*{XrefAutoLinkRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled);
[GeneratedRegex($@"^(#+)(?: |\t)*{XrefAutoLinkRegexString}( |\t)*#*( |\t)*(\n|$)")]
private static partial Regex XrefAutoLinkTocRegex();

[GeneratedRegex($@"^(#+)(?: |\t)*{XrefAutoLinkRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)")]
private static partial Regex XrefAutoLinkWithQuoteTocRegex();

public override Match Match(string text)
{
var match = XrefAutoLinkWithQuoteTocRegex.Match(text);
var match = XrefAutoLinkWithQuoteTocRegex().Match(text);
if (match.Length == 0)
{
match = XrefAutoLinkTocRegex.Match(text);
match = XrefAutoLinkTocRegex().Match(text);
}

return match;
Expand All @@ -226,19 +229,20 @@ public override ParseState Apply(ParseState state, Match match)
}
}

internal sealed class TopicXrefShortcutTocParseRule : ParseRule
internal sealed partial class TopicXrefShortcutTocParseRule : ParseRule
{
public static readonly Regex XrefShortcutTocRegex =
new($@"^(#+)(?: |\t)*{XrefShortcutRegexString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled);
public static readonly Regex XrefShortcutTocWithQuoteTocRegex =
new($@"^(#+)(?: |\t)*{XrefShortcutRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)", RegexOptions.Compiled);
[GeneratedRegex($@"^(#+)(?: |\t)*{XrefShortcutRegexString}( |\t)*#*( |\t)*(\n|$)")]
private static partial Regex XrefShortcutTocRegex();

[GeneratedRegex($@"^(#+)(?: |\t)*{XrefShortcutRegexWithQuoteString}( |\t)*#*( |\t)*(\n|$)")]
private static partial Regex XrefShortcutTocWithQuoteTocRegex();

public override Match Match(string text)
{
var match = XrefShortcutTocWithQuoteTocRegex.Match(text);
var match = XrefShortcutTocWithQuoteTocRegex().Match(text);
if (match.Length == 0)
{
match = XrefShortcutTocRegex.Match(text);
match = XrefShortcutTocRegex().Match(text);
}

return match;
Expand All @@ -250,48 +254,48 @@ public override ParseState Apply(ParseState state, Match match)
}
}

internal sealed class ExternalLinkTocParseRule : ParseRule
internal sealed partial class ExternalLinkTocParseRule : ParseRule
{
public static readonly Regex TocRegex =
new(@"^(?<headerLevel>#+)(( |\t)*)\[(?<tocTitle>.+?)\]\((?<tocLink>(http[s]?://).*?)\)(?:( |\t)+#*)?( |\t)*(\n|$)", RegexOptions.Compiled);
[GeneratedRegex(@"^(?<headerLevel>#+)(( |\t)*)\[(?<tocTitle>.+?)\]\((?<tocLink>(http[s]?://).*?)\)(?:( |\t)+#*)?( |\t)*(\n|$)")]
private static partial Regex TocRegex();

public override Match Match(string text) => TocRegex.Match(text);
public override Match Match(string text) => TocRegex().Match(text);

public override ParseState Apply(ParseState state, Match match)
{
return ApplyCore(state, match.Groups["headerLevel"].Value.Length, match.Groups["tocTitle"].Value, match.Groups["tocLink"].Value);
}
}

internal sealed class ContainerParseRule : ParseRule
internal sealed partial class ContainerParseRule : ParseRule
{
public static readonly Regex ContainerRegex =
new(@"^(?<headerLevel>#+)(( |\t)*)(?<tocTitle>.+?)(?:( |\t)+#*)?( |\t)*(\n|$)", RegexOptions.Compiled);
[GeneratedRegex(@"^(?<headerLevel>#+)(( |\t)*)(?<tocTitle>.+?)(?:( |\t)+#*)?( |\t)*(\n|$)")]
private static partial Regex ContainerRegex();

public override Match Match(string text) => ContainerRegex.Match(text);
public override Match Match(string text) => ContainerRegex().Match(text);

public override ParseState Apply(ParseState state, Match match)
{
return ApplyCore(state, match.Groups["headerLevel"].Value.Length, match.Groups["tocTitle"].Value, null);
}
}

internal sealed class CommentParseRule : ParseRule
internal sealed partial class CommentParseRule : ParseRule
{
public static readonly Regex CommentRegex =
new(@"^\s*<!--[\s\S]*?-->\s*(\n|$)", RegexOptions.Compiled);
[GeneratedRegex(@"^\s*<!--[\s\S]*?-->\s*(\n|$)")]
private static partial Regex CommentRegex();

public override Match Match(string text) => CommentRegex.Match(text);
public override Match Match(string text) => CommentRegex().Match(text);

public override ParseState Apply(ParseState state, Match match) => state;
}

internal sealed class WhitespaceParseRule : ParseRule
internal sealed partial class WhitespaceParseRule : ParseRule
{
public static readonly Regex WhitespaceRegex =
new(@"^\s*(\n|$)", RegexOptions.Compiled);
[GeneratedRegex(@"^\s*(\n|$)")]
private static partial Regex WhitespaceRegex();

public override Match Match(string text) => WhitespaceRegex.Match(text);
public override Match Match(string text) => WhitespaceRegex().Match(text);

public override ParseState Apply(ParseState state, Match match) => state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@

namespace Docfx.Build.Engine;

internal class MustacheTemplateRenderer : ITemplateRenderer
internal partial class MustacheTemplateRenderer : ITemplateRenderer
{
public const string Extension = ".tmpl";

private static readonly Regex IncludeRegex = new(@"{{\s*!\s*include\s*\(:?(:?['""]?)\s*(?<file>(.+?))\1\s*\)\s*}}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MasterPageRegex = new(@"{{\s*!\s*master\s*\(:?(:?['""]?)\s*(?<file>(.+?))\1\s*\)\s*}}\s*\n?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MasterPageBodyRegex = new(@"{{\s*!\s*body\s*}}\s*\n?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
[GeneratedRegex(@"{{\s*!\s*include\s*\(:?(:?['""]?)\s*(?<file>(.+?))\1\s*\)\s*}}", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-AU")]
private static partial Regex IncludeRegex();

[GeneratedRegex(@"{{\s*!\s*master\s*\(:?(:?['""]?)\s*(?<file>(.+?))\1\s*\)\s*}}\s*\n?", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-AU")]
private static partial Regex MasterPageRegex();

[GeneratedRegex(@"{{\s*!\s*body\s*}}\s*\n?", RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-AU")]
private static partial Regex MasterPageBodyRegex();

private readonly ResourceFileReader _reader;
private readonly IStubbleRenderer _renderer;
Expand All @@ -37,7 +42,7 @@ public MustacheTemplateRenderer(ResourceFileReader reader, ResourceInfo info, st
})
.Build();

var processedTemplate = ParseTemplateHelper.ExpandMasterPage(reader, info, MasterPageRegex, MasterPageBodyRegex);
var processedTemplate = ParseTemplateHelper.ExpandMasterPage(reader, info, MasterPageRegex(), MasterPageBodyRegex());

_template = processedTemplate;

Expand All @@ -63,7 +68,7 @@ public string Render(object model)
/// <param name="template"></param>
private IEnumerable<string> ExtractDependencyResourceNames(string template)
{
foreach (Match match in IncludeRegex.Matches(template))
foreach (Match match in IncludeRegex().Matches(template))
{
var filePath = match.Groups["file"].Value;
foreach (var name in ParseTemplateHelper.GetResourceName(filePath, Path, _reader))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

namespace Docfx.Build.Engine;

internal static class ParseTemplateHelper
internal static partial class ParseTemplateHelper
{
private static readonly Regex IsRegexPatternRegex = new(@"^\s*/(.*)/\s*$", RegexOptions.Compiled);
[GeneratedRegex(@"^\s*/(.*)/\s*$")]
private static partial Regex IsRegexPatternRegex();

public static string ExpandMasterPage(ResourceFileReader reader, ResourceInfo info, Regex masterRegex, Regex bodyRegex)
{
Expand Down Expand Up @@ -72,7 +73,7 @@ public static IEnumerable<string> GetResourceName(string file, string templateNa
file = file.Substring(2);
}

var regexPatternMatch = IsRegexPatternRegex.Match(file);
var regexPatternMatch = IsRegexPatternRegex().Match(file);
if (regexPatternMatch.Groups.Count > 1)
{
file = regexPatternMatch.Groups[1].Value;
Expand Down
8 changes: 5 additions & 3 deletions src/Docfx.Common/Path/PathUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@

namespace Docfx.Common;

public static class PathUtility
public static partial class PathUtility
{
private static readonly Regex UriWithProtocol = new(@"^\w{2,}\:", RegexOptions.Compiled);

[GeneratedRegex(@"^\w{2,}\:")]
private static partial Regex UriWithProtocol();

private static readonly char[] AdditionalInvalidChars = ":*".ToArray();
public static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars().Concat(AdditionalInvalidChars).ToArray();
Expand Down Expand Up @@ -98,7 +100,7 @@ public static bool IsRelativePath(string path)
return false;
}

if (UriWithProtocol.IsMatch(path))
if (UriWithProtocol().IsMatch(path))
{
return false;
}
Expand Down
17 changes: 10 additions & 7 deletions src/Docfx.Dotnet/ManagedReference/Visitors/SpecIdHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@

namespace Docfx.Dotnet;

internal sealed class SpecIdHelper
internal sealed partial class SpecIdHelper
{
private static readonly Regex TypeParameterRegex = new(@"\B(?<!`)`\d+", RegexOptions.Compiled);
private static readonly Regex MethodParameterRegex = new(@"\B``\d+", RegexOptions.Compiled);
[GeneratedRegex(@"\B(?<!`)`\d+")]
private static partial Regex TypeParameterRegex();

[GeneratedRegex(@"\B``\d+")]
private static partial Regex MethodParameterRegex();

public static string GetSpecId(
ISymbol symbol,
Expand Down Expand Up @@ -41,7 +44,7 @@ private static string SpecMethodGenericParameter(IMethodSymbol symbol, string id
{
return id;
}
return MethodParameterRegex.Replace(
return MethodParameterRegex().Replace(
id,
match =>
{
Expand All @@ -57,7 +60,7 @@ private static string SpecTypeGenericParameter(IReadOnlyList<string> names, stri
{
return id;
}
return TypeParameterRegex.Replace(
return TypeParameterRegex().Replace(
id,
match =>
{
Expand All @@ -72,7 +75,7 @@ private static string SpecMethodGenericParameter(IReadOnlyList<string> names, st
{
return id;
}
return MethodParameterRegex.Replace(
return MethodParameterRegex().Replace(
id,
match =>
{
Expand All @@ -82,7 +85,7 @@ private static string SpecMethodGenericParameter(IReadOnlyList<string> names, st
}

/// <summary>
/// spec extension method's receiver type.
/// spec extension method's receiver type.
/// for below overload: M(this A), M(this A, A), AddReference applies to the first method and AddSpecReference applies to the second method might get same id without prepending receiver type.
/// </summary>
/// <param name="symbol">symbol</param>
Expand Down
Loading

0 comments on commit 05c2252

Please sign in to comment.