Skip to content

Commit

Permalink
Merge pull request #23 from kysect/feat/roslyn-rule-id
Browse files Browse the repository at this point in the history
Add strong typing for RoslynRuleId
  • Loading branch information
FrediKats committed Aug 17, 2023
2 parents 5ecfa65 + 87dae86 commit 3c711c9
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 13 deletions.
2 changes: 2 additions & 0 deletions Sources/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
</Project>
14 changes: 14 additions & 0 deletions Sources/Kysect.Configuin.Common/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Kysect.Configuin.Common;

public static class StringExtensions
{
public static string WithoutPrefix(this string value, string prefix)
{
if (!value.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
throw new ArgumentException($"String {value} does not start with {prefix}");

return value.Substring(prefix.Length, value.Length - prefix.Length);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Kysect.Configuin.Core.EditorConfigParsing.Rules;
using Kysect.Configuin.Core.IniParsing;
using Kysect.Configuin.Core.RoslynRuleModels;

namespace Kysect.Configuin.Core.EditorConfigParsing;

Expand Down Expand Up @@ -61,7 +62,7 @@ private static IEditorConfigRule ParseRoslynSeverityRule(IniFileLine line)
if (!Enum.TryParse(line.Value, true, out RoslynRuleSeverity severity))
throw new ArgumentException($"Cannot parse severity from {line.Value}");

string ruleId = keyParts[1];
var ruleId = RoslynRuleId.Parse(keyParts[1]);
return new RoslynSeverityEditorConfigRule(ruleId, severity);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Kysect.Configuin.Core.EditorConfigParsing.Rules;
using Kysect.Configuin.Core.RoslynRuleModels;

namespace Kysect.Configuin.Core.EditorConfigParsing.Rules;

public interface IEditorConfigRule
{
Expand All @@ -16,8 +18,9 @@ public record GeneralEditorConfigRule(
public record RoslynOptionEditorConfigRule(
string Key,
string Value,
// TODO: ensure that this is supported (severity per option)
RoslynRuleSeverity? Severity) : IEditorConfigRule;

public record RoslynSeverityEditorConfigRule(
string RuleId,
RoslynRuleId RuleId,
RoslynRuleSeverity Severity) : IEditorConfigRule;
4 changes: 4 additions & 0 deletions Sources/Kysect.Configuin.Core/Kysect.Configuin.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@
<PackageReference Include="Markdig" Version="0.31.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Kysect.Configuin.Common\Kysect.Configuin.Common.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public RoslynStyleRule ParseStyleRule(string info)
IReadOnlyCollection<RoslynStyleRuleOption> roslynStyleRuleOptions = ParseOptions(markdownHeadedBlocks);

return new RoslynStyleRule(
ruleId.Value,
RoslynRuleId.Parse(ruleId.Value),
title.Value,
category.Value,
overviewText,
Expand Down Expand Up @@ -99,7 +99,7 @@ public RoslynQualityRule ParseQualityRule(string info)
MsLearnPropertyValueDescriptionTableRow isDefault = table.GetSingleValue("Enabled by default in .NET 7");

return new RoslynQualityRule(
ruleId.Value,
RoslynRuleId.Parse(ruleId.Value),
// TODO: parse rule name
ruleName: string.Empty,
category.Value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

public class RoslynQualityRule
{
public string RuleId { get; }
public RoslynRuleId RuleId { get; }
public string RuleName { get; }
public string Category { get; }
public string Description { get; }

public RoslynQualityRule(string ruleId, string ruleName, string category, string description)
public RoslynQualityRule(RoslynRuleId ruleId, string ruleName, string category, string description)
{
RuleId = ruleId;
RuleName = ruleName;
Expand Down
54 changes: 54 additions & 0 deletions Sources/Kysect.Configuin.Core/RoslynRuleModels/RoslynRuleId.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Kysect.Configuin.Common;

namespace Kysect.Configuin.Core.RoslynRuleModels;

public readonly struct RoslynRuleId
{
public RoslynRuleType Type { get; }
public int Id { get; }

public static RoslynRuleId Parse(string value)
{
// CA1234
string qualityRulePrefix = "CA";
if (value.StartsWith(qualityRulePrefix, StringComparison.InvariantCultureIgnoreCase))
{
string id = value.WithoutPrefix(qualityRulePrefix);
return new RoslynRuleId(RoslynRuleType.QualityRule, int.Parse(id));
}

// IDE1234
string styleRulePrefix = "IDE";
if (value.StartsWith(styleRulePrefix, StringComparison.InvariantCultureIgnoreCase))
{
string id = value.WithoutPrefix(styleRulePrefix);
return new RoslynRuleId(RoslynRuleType.StyleRule, int.Parse(id));
}

throw new ArgumentException($"String {value} is not valid Roslyn rule id");
}

public RoslynRuleId(RoslynRuleType type, int id)
{
Type = type;
Id = id;
}

public override bool Equals(object? obj)
{
if (obj is RoslynRuleId o)
return Equals(o);

return false;
}

public bool Equals(RoslynRuleId other)
{
return Type == other.Type && Id == other.Id;
}

public override int GetHashCode()
{
return HashCode.Combine((int)Type, Id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kysect.Configuin.Core.RoslynRuleModels;

public enum RoslynRuleType
{
StyleRule,
QualityRule
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

public class RoslynStyleRule
{
public string RuleId { get; }
public RoslynRuleId RuleId { get; }
public string Title { get; }
public string Category { get; }
public string Overview { get; }
public string Example { get; }
public IReadOnlyCollection<RoslynStyleRuleOption> Options { get; }

public RoslynStyleRule(string ruleId, string title, string category, string overview, string example, IReadOnlyCollection<RoslynStyleRuleOption> options)
public RoslynStyleRule(RoslynRuleId ruleId, string title, string category, string overview, string example, IReadOnlyCollection<RoslynStyleRuleOption> options)
{
RuleId = ruleId;
Title = title;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions;
using Kysect.Configuin.Core.EditorConfigParsing;
using Kysect.Configuin.Core.EditorConfigParsing.Rules;
using Kysect.Configuin.Core.RoslynRuleModels;
using NUnit.Framework;

namespace Kysect.Configuin.Tests.EditorConfigFileParsing;
Expand All @@ -26,7 +27,8 @@ public void Parse_TabWidth_ReturnGeneralEditorRule()
public void Parse_DotnetDiagnosticSeverity_ReturnRoslyntSeverityRule()
{
string content = "dotnet_diagnostic.IDE0001.severity = warning";
var expected = new RoslynSeverityEditorConfigRule("IDE0001", RoslynRuleSeverity.Warning);
var roslynRuleId = RoslynRuleId.Parse("IDE0001");
var expected = new RoslynSeverityEditorConfigRule(roslynRuleId, RoslynRuleSeverity.Warning);

EditorConfigRuleSet editorConfigRuleSet = _parser.Parse(content);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ public void Setup()
public void ParseStyleRule_IDE0040_ReturnExpectedResult()
{
string fileText = File.ReadAllText(Path.Combine("MsLearnDocumentation", "Resources", "Ide0040.md"));
RoslynRuleId expected = RoslynRuleId.Parse("IDE0040");

RoslynStyleRule roslynStyleRule = _parser.ParseStyleRule(fileText);

roslynStyleRule.RuleId
.Should().Be("IDE0040");
.Should().Be(expected);

roslynStyleRule.Title
.Should().Be("Add accessibility modifiers");
Expand Down Expand Up @@ -57,12 +58,13 @@ public void ParseStyleRule_IDE0040_ReturnExpectedResult()
public void ParseQualityRule_CS1064_ReturnExpectedResult()
{
string fileText = File.ReadAllText(Path.Combine("MsLearnDocumentation", "Resources", "Ca1064.md"));
RoslynRuleId expected = RoslynRuleId.Parse("CA1064");

RoslynQualityRule qualityRule = _parser.ParseQualityRule(fileText);

qualityRule.RuleId
.Should().Be("CA1064");
.Should().Be(expected);

qualityRule.Category
.Should().Be("Design");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using FluentAssertions;
using Kysect.Configuin.Core.RoslynRuleModels;
using NUnit.Framework;

namespace Kysect.Configuin.Tests.MsLearnDocumentation;

public class RoslynRuleIdTests
{
[Test]
[TestCase("CA1000", RoslynRuleType.QualityRule, 1000)]
[TestCase("ca1001", RoslynRuleType.QualityRule, 1001)]
[TestCase("IDE1002", RoslynRuleType.StyleRule, 1002)]
public void Parse(string input, RoslynRuleType type, int id)
{
var expected = new RoslynRuleId(type, id);

var roslynRuleId = RoslynRuleId.Parse(input);

roslynRuleId.Should().Be(expected);
}

[Test]
public void Parse_WithIncorrectPrefix_ThrowException()
{
Assert.Throws<ArgumentException>(() =>
{
var roslynRuleId = RoslynRuleId.Parse("QWE1234");
});
}
}

0 comments on commit 3c711c9

Please sign in to comment.