Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add grouping CA rules by category during formatting #120

Merged
merged 1 commit into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,29 @@ Some features:
- Options saved near the rule
- Not parsed rules don't change
- Comments are saved and moved with the rule

#### Grouping by category

Command 'format' support flag `--group-ca` that allows to group rules by category. For example:

```
# with --group-ca false
# Autogenerated values
[*.cs]
### CA ###
dotnet_diagnostic.CA1016.severity = none
dotnet_diagnostic.CA1027.severity = none
dotnet_diagnostic.CA1501.severity = none
dotnet_diagnostic.CA1835.severity = none

# with --group-ca true
# Autogenerated values
[*.cs]
### CA Design ###
dotnet_diagnostic.CA1016.severity = none
dotnet_diagnostic.CA1027.severity = none
### CA Maintainability ###
dotnet_diagnostic.CA1501.severity = none
### CA Performance ###
dotnet_diagnostic.CA1835.severity = none
```
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public sealed class Settings : CommandSettings
[Description("Path to cloned MS Learn repository.")]
[CommandOption("-d|--documentation")]
public string? MsLearnRepositoryPath { get; init; }

[Description("Group CA rules by category")]
[CommandOption("--group-ca")]
[DefaultValue(true)]
public bool GroupQualityRulesByCategory { get; init; }
}

public override int Execute(CommandContext context, Settings settings)
Expand All @@ -38,7 +43,7 @@ public override int Execute(CommandContext context, Settings settings)
MsLearnDocumentationRawInfo msLearnDocumentationRawInfo = repositoryPathReader.Provide(settings.MsLearnRepositoryPath);
RoslynRules roslynRules = msLearnDocumentationParser.Parse(msLearnDocumentationRawInfo);
EditorConfigDocument editorConfigDocument = editorConfigDocumentParser.Parse(editorConfigContentLines);
EditorConfigDocument formattedDocument = editorConfigFormatter.FormatAccordingToRuleDefinitions(editorConfigDocument, roslynRules);
EditorConfigDocument formattedDocument = editorConfigFormatter.FormatAccordingToRuleDefinitions(editorConfigDocument, roslynRules, settings.GroupQualityRulesByCategory);
File.WriteAllText(settings.EditorConfigPath, formattedDocument.ToFullString());

return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ public EditorConfigDocument Format(EditorConfigDocument value)
if (nodesForRemoving.IsEmpty())
return value;

EditorConfigCategoryNode autoGeneratedSection = CreateAutoGeneratedCategory(styleRuleNodesForMoving, qualityRuleNodesForMoving);
EditorConfigCategoryNode autoGeneratedSection = CreateAutoGeneratedCategory(styleRuleNodesForMoving, [new RoslynQualityRuleFormattedSection("CA", qualityRuleNodesForMoving)]);

return value
.RemoveNodes(nodesForRemoving)
.AddChild(autoGeneratedSection);
}

public EditorConfigDocument FormatAccordingToRuleDefinitions(EditorConfigDocument document, RoslynRules rules)
public EditorConfigDocument FormatAccordingToRuleDefinitions(EditorConfigDocument document, RoslynRules rules, bool groupQualityRulesByCategory = false)
{
rules.ThrowIfNull();

Expand Down Expand Up @@ -80,26 +80,54 @@ public EditorConfigDocument FormatAccordingToRuleDefinitions(EditorConfigDocumen
}
}

List<EditorConfigPropertyNode> selectedQualityRuleNodes = new List<EditorConfigPropertyNode>();
foreach (RoslynQualityRule qualityRule in rules.QualityRules)
List<RoslynQualityRuleFormattedSection> formattedSections = new List<RoslynQualityRuleFormattedSection>();
if (groupQualityRulesByCategory)
{
EditorConfigPropertyNode? editorConfigPropertyNode = TryFindSeverityNode(propertyNodes, qualityRule.RuleId);
if (editorConfigPropertyNode is null)
continue;
foreach (IGrouping<string, RoslynQualityRule> categoryRules in rules.QualityRules.GroupBy(r => r.Category).OrderBy(c => c.Key))
{
List<EditorConfigPropertyNode> selectedQualityRuleNodes = new List<EditorConfigPropertyNode>();
foreach (RoslynQualityRule qualityRule in categoryRules.OrderBy(r => r.RuleId))
{
EditorConfigPropertyNode? editorConfigPropertyNode = TryFindSeverityNode(propertyNodes, qualityRule.RuleId);
if (editorConfigPropertyNode is null)
continue;

selectedQualityRuleNodes.Add(editorConfigPropertyNode);
}

if (selectedQualityRuleNodes.Any())
formattedSections.Add(new RoslynQualityRuleFormattedSection($"CA {categoryRules.Key}", selectedQualityRuleNodes));
}
}
else
{
List<EditorConfigPropertyNode> selectedQualityRuleNodes = new List<EditorConfigPropertyNode>();
foreach (RoslynQualityRule qualityRule in rules.QualityRules)
{
EditorConfigPropertyNode? editorConfigPropertyNode = TryFindSeverityNode(propertyNodes, qualityRule.RuleId);
if (editorConfigPropertyNode is null)
continue;

selectedQualityRuleNodes.Add(editorConfigPropertyNode);
selectedQualityRuleNodes.Add(editorConfigPropertyNode);
}
if (selectedQualityRuleNodes.Any())
formattedSections.Add(new RoslynQualityRuleFormattedSection("CA", selectedQualityRuleNodes));
}

nodesForRemoving.AddRange(selectedStyleRuleNodes);
nodesForRemoving.AddRange(selectedQualityRuleNodes);
EditorConfigCategoryNode autoGeneratedSection = CreateAutoGeneratedCategory(selectedStyleRuleNodes, selectedQualityRuleNodes);
nodesForRemoving.AddRange(formattedSections.SelectMany(s => s.SelectedQualityRuleNodes));
EditorConfigCategoryNode autoGeneratedSection = CreateAutoGeneratedCategory(selectedStyleRuleNodes, formattedSections);

return document
.RemoveNodes(nodesForRemoving)
.AddChild(autoGeneratedSection);
}

private EditorConfigCategoryNode CreateAutoGeneratedCategory(IReadOnlyCollection<EditorConfigPropertyNode> styleRuleNodesForMoving, IReadOnlyCollection<EditorConfigPropertyNode> qualityRuleNodesForMoving)
public record RoslynQualityRuleFormattedSection(string Title, IReadOnlyCollection<EditorConfigPropertyNode> SelectedQualityRuleNodes);

private EditorConfigCategoryNode CreateAutoGeneratedCategory(
IReadOnlyCollection<EditorConfigPropertyNode> styleRuleNodesForMoving,
IReadOnlyCollection<RoslynQualityRuleFormattedSection> qualityRuleNodesForMoving)
{
var autoGeneratedSection = new EditorConfigCategoryNode("*.cs", [], ["# Autogenerated values"], null);

Expand All @@ -113,12 +141,14 @@ private EditorConfigCategoryNode CreateAutoGeneratedCategory(IReadOnlyCollection
autoGeneratedSection = autoGeneratedSection.AddChild(styleRuleSection);
}

if (qualityRuleNodesForMoving.Any())
foreach (RoslynQualityRuleFormattedSection roslynQualityRuleFormattedSection in qualityRuleNodesForMoving)
{
var qualitySection = new EditorConfigDocumentSectionNode("### CA ###");
foreach (EditorConfigPropertyNode qualityRule in qualityRuleNodesForMoving)
qualitySection = qualitySection.AddChild(qualityRule);
if (roslynQualityRuleFormattedSection.SelectedQualityRuleNodes.IsEmpty())
continue;

var qualitySection = new EditorConfigDocumentSectionNode($"### {roslynQualityRuleFormattedSection.Title} ###");
foreach (EditorConfigPropertyNode qualityRule in roslynQualityRuleFormattedSection.SelectedQualityRuleNodes)
qualitySection = qualitySection.AddChild(qualityRule);
autoGeneratedSection = autoGeneratedSection.AddChild(qualitySection);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,38 @@ public void Format_NamingRule_ReturnOrderedLinesWithHeader()
RoslynRules roslynRules = _msLearnDocumentationParser.Parse(msLearnDocumentationRawInfo);

EditorConfigDocument editorConfigDocument = _parser.Parse(input);
EditorConfigDocument formattedDocument = _formatter.FormatAccordingToRuleDefinitions(editorConfigDocument, roslynRules);
EditorConfigDocument formattedDocument = _formatter.FormatAccordingToRuleDefinitions(editorConfigDocument, roslynRules, false);

formattedDocument.ToFullString().Should().Be(expected);
}

[Fact]
public void Format_QualityRuleByCategory_ReturnGroupedByCategory()
{
var input = """
dotnet_diagnostic.CA1016.severity = none
dotnet_diagnostic.CA1027.severity = none
dotnet_diagnostic.CA1501.severity = none
dotnet_diagnostic.CA1835.severity = none
""";

var expected = """
# Autogenerated values
[*.cs]
### CA Design ###
dotnet_diagnostic.CA1016.severity = none
dotnet_diagnostic.CA1027.severity = none
### CA Maintainability ###
dotnet_diagnostic.CA1501.severity = none
### CA Performance ###
dotnet_diagnostic.CA1835.severity = none
""";

MsLearnDocumentationRawInfo msLearnDocumentationRawInfo = _repositoryPathReader.Provide(Constants.GetPathToMsDocsRoot());
RoslynRules roslynRules = _msLearnDocumentationParser.Parse(msLearnDocumentationRawInfo);

EditorConfigDocument editorConfigDocument = _parser.Parse(input);
EditorConfigDocument formattedDocument = _formatter.FormatAccordingToRuleDefinitions(editorConfigDocument, roslynRules, true);

formattedDocument.ToFullString().Should().Be(expected);
}
Expand All @@ -119,7 +150,7 @@ public void FormatAccordingToRuleDefinitions_Sample_ReturnExpectedFormatterDocum
RoslynRules roslynRules = _msLearnDocumentationParser.Parse(msLearnDocumentationRawInfo);

EditorConfigDocument editorConfigDocument = _parser.Parse(input);
EditorConfigDocument formattedDocument = _formatter.FormatAccordingToRuleDefinitions(editorConfigDocument, roslynRules);
EditorConfigDocument formattedDocument = _formatter.FormatAccordingToRuleDefinitions(editorConfigDocument, roslynRules, false);
// TODO: Do smth with this =_=

formattedDocument.ToFullString()
Expand Down