Skip to content

Commit 37f892e

Browse files
committed
improve RegionParser to support multiple classes in a file
1 parent 0e28833 commit 37f892e

File tree

5 files changed

+86
-43
lines changed

5 files changed

+86
-43
lines changed

src/EntityFrameworkCore.Generator.Core/Metadata/Parsing/CodeRegion.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ public class CodeRegion
44
{
55
public int StartIndex { get; set; }
66
public int EndIndex { get; set; }
7-
public string Name { get; set; } = null!;
7+
public string RegionName { get; set; } = null!;
8+
public string? ClassName { get; set; }
89
public string? Content { get; set; }
910
}
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
using System.Collections.Generic;
1+
using System.Collections.Generic;
22
using EntityFrameworkCore.Generator.Metadata.Parsing;
33
using Microsoft.CodeAnalysis.CSharp;
44
using Microsoft.CodeAnalysis.CSharp.Syntax;
55

66
namespace EntityFrameworkCore.Generator.Parsing;
77

8-
public class RegionParser
8+
public static class RegionParser
99
{
10-
public Dictionary<string, CodeRegion> ParseRegions(string code)
10+
public static List<CodeRegion> ParseRegions(string code)
1111
{
1212
var syntaxTree = CSharpSyntaxTree.ParseText(code);
1313
var root = (CompilationUnitSyntax)syntaxTree.GetRoot();
@@ -18,10 +18,8 @@ public Dictionary<string, CodeRegion> ParseRegions(string code)
1818
var regions = visitor.Regions;
1919

2020
// extract content using start and end indexes
21-
foreach (var pair in regions)
21+
foreach (var region in regions)
2222
{
23-
var region = pair.Value;
24-
2523
var start = region.StartIndex;
2624
var end = region.EndIndex;
2725
var length = end - start;
@@ -31,4 +29,4 @@ public Dictionary<string, CodeRegion> ParseRegions(string code)
3129

3230
return regions;
3331
}
34-
}
32+
}

src/EntityFrameworkCore.Generator.Core/Parsing/RegionReplace.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@ namespace EntityFrameworkCore.Generator.Parsing;
44

55
public class RegionReplace
66
{
7-
public RegionReplace(RegionParser? regionParser = null)
8-
{
9-
RegionParser = regionParser ?? new RegionParser();
10-
}
11-
12-
protected RegionParser RegionParser { get; }
13-
147
public void MergeFile(string fullPath, string outputContent)
158
{
169
if (string.IsNullOrEmpty(fullPath) || string.IsNullOrEmpty(outputContent) || !Path.Exists(fullPath))
@@ -34,10 +27,15 @@ public string MergeContent(string originalContent, string outputContent)
3427
var originalBuilder = new StringBuilder(originalContent);
3528

3629
int offset = 0;
37-
foreach (var pair in outputRegions)
30+
foreach (var outputRegion in outputRegions)
3831
{
39-
var outputRegion = pair.Value;
40-
if (!originalRegions.TryGetValue(pair.Key, out var originalRegion))
32+
var originalRegion = originalRegions
33+
.Find(r =>
34+
string.Equals(r.RegionName, outputRegion.RegionName, StringComparison.OrdinalIgnoreCase)
35+
&& r.ClassName == outputRegion.ClassName
36+
);
37+
38+
if (originalRegion == null)
4139
{
4240
// log error
4341
continue;

src/EntityFrameworkCore.Generator.Core/Parsing/RegionVisitor.cs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,53 @@ namespace EntityFrameworkCore.Generator.Parsing;
88

99
public class RegionVisitor : CSharpSyntaxWalker
1010
{
11-
private readonly Stack<CodeRegion> _stack = new();
11+
private readonly Stack<string> _classStack = new();
12+
private readonly Stack<CodeRegion> _regionStack = new();
1213

1314
public RegionVisitor() : base(SyntaxWalkerDepth.StructuredTrivia)
1415
{
15-
Regions = new Dictionary<string, CodeRegion>(StringComparer.OrdinalIgnoreCase);
16+
Regions = [];
1617
}
1718

18-
public Dictionary<string, CodeRegion> Regions { get; }
19+
public List<CodeRegion> Regions { get; }
20+
21+
public override void VisitClassDeclaration(ClassDeclarationSyntax node)
22+
{
23+
var className = node.Identifier.Text;
24+
_classStack.Push(className);
25+
26+
base.VisitClassDeclaration(node);
27+
28+
_classStack.Pop();
29+
}
1930

2031
public override void VisitRegionDirectiveTrivia(RegionDirectiveTriviaSyntax node)
2132
{
2233
if (node == null)
2334
return;
2435

36+
_classStack.TryPeek(out var className);
37+
2538
var region = new CodeRegion
2639
{
2740
StartIndex = node.FullSpan.Start,
28-
Name = ParseRegionName(node)
41+
RegionName = ParseRegionName(node),
42+
ClassName = className ?? string.Empty
2943
};
30-
_stack.Push(region);
44+
_regionStack.Push(region);
3145

3246
base.VisitRegionDirectiveTrivia(node);
3347
}
3448

3549
public override void VisitEndRegionDirectiveTrivia(EndRegionDirectiveTriviaSyntax node)
3650
{
37-
if (node == null || _stack.Count == 0)
51+
if (node == null || _regionStack.Count == 0)
3852
return;
3953

40-
var region = _stack.Pop();
54+
var region = _regionStack.Pop();
4155
region.EndIndex = node.FullSpan.End;
4256

43-
Regions[region.Name] = region;
57+
Regions.Add(region);
4458

4559
base.VisitEndRegionDirectiveTrivia(node);
4660
}

test/EntityFrameworkCore.Generator.Core.Tests/Parsing/RegionParserTests.cs

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ public class RegionParserTests
1212
[Fact]
1313
public void ParseRegions()
1414
{
15-
var parser = new RegionParser();
16-
1715
var source = new StringBuilder();
1816
source.AppendLine(@"using System;");
1917
source.AppendLine(@"using System.Collections.Generic;");
@@ -29,13 +27,13 @@ public void ParseRegions()
2927
source.AppendLine(@"}");
3028

3129

32-
var result = parser.ParseRegions(source.ToString());
30+
var result = RegionParser.ParseRegions(source.ToString());
3331
Assert.NotNull(result);
3432
Assert.Single(result);
3533

36-
var first = result.Values.First();
34+
var first = result.First();
3735
Assert.NotNull(first);
38-
Assert.Equal("Generated Properties", first.Name);
36+
Assert.Equal("Generated Properties", first.RegionName);
3937

4038
var content = new StringBuilder();
4139
content.AppendLine(@"#region Generated Properties");
@@ -49,8 +47,6 @@ public void ParseRegions()
4947
[Fact]
5048
public void ParseMultipleRegions()
5149
{
52-
var parser = new RegionParser();
53-
5450
var source = new StringBuilder();
5551
source.AppendLine(@"using System;");
5652
source.AppendLine(@"using System.Collections.Generic;");
@@ -82,20 +78,18 @@ public void ParseMultipleRegions()
8278
source.AppendLine(@"}");
8379

8480

85-
var result = parser.ParseRegions(source.ToString());
81+
var result = RegionParser.ParseRegions(source.ToString());
8682
Assert.NotNull(result);
8783
Assert.Equal(3, result.Count);
8884

89-
var first = result.Values.First();
85+
var first = result.First();
9086
Assert.NotNull(first);
91-
Assert.Equal("Generated Initializes", first.Name);
87+
Assert.Equal("Generated Initializes", first.RegionName);
9288
}
9389

9490
[Fact]
9591
public void ParseNestedRegions()
9692
{
97-
var parser = new RegionParser();
98-
9993
var source = new StringBuilder();
10094
source.AppendLine(@"using System;");
10195
source.AppendLine(@"using System.Collections.Generic;");
@@ -116,13 +110,13 @@ public void ParseNestedRegions()
116110
source.AppendLine(@"}");
117111

118112

119-
var result = parser.ParseRegions(source.ToString());
113+
var result = RegionParser.ParseRegions(source.ToString());
120114
Assert.NotNull(result);
121115
Assert.Equal(2, result.Count);
122116

123-
var nested = result["Nested Properties"];
117+
var nested = result.Find(p => p.RegionName == "Nested Properties");
124118
Assert.NotNull(nested);
125-
Assert.Equal("Nested Properties", nested.Name);
119+
Assert.Equal("Nested Properties", nested.RegionName);
126120

127121
var nestedContent = new StringBuilder();
128122
nestedContent.AppendLine(@"#region Nested Properties");
@@ -131,9 +125,9 @@ public void ParseNestedRegions()
131125

132126
Assert.Equal(nestedContent.ToString(), nested.Content);
133127

134-
var generated = result["Generated Properties"];
128+
var generated = result.Find(p => p.RegionName == "Generated Properties");
135129
Assert.NotNull(generated);
136-
Assert.Equal("Generated Properties", generated.Name);
130+
Assert.Equal("Generated Properties", generated.RegionName);
137131

138132
var generatedContent = new StringBuilder();
139133
generatedContent.AppendLine(@"#region Generated Properties");
@@ -149,5 +143,43 @@ public void ParseNestedRegions()
149143

150144
}
151145

146+
[Fact]
147+
public void ParseRegionsMultipleClasses()
148+
{
149+
var source = new StringBuilder();
150+
source.AppendLine(@"using System;");
151+
source.AppendLine(@"using System.Collections.Generic;");
152+
source.AppendLine(@"");
153+
source.AppendLine(@"namespace EntityFrameworkCore.Generator.Core.Tests;");
154+
source.AppendLine(@"public partial class User");
155+
source.AppendLine(@"{");
156+
source.AppendLine(@" #region Generated Properties");
157+
source.AppendLine(@" public Guid UserId { get; set; }");
158+
source.AppendLine(@" #endregion");
159+
source.AppendLine(@"}");
160+
source.AppendLine(@"public partial class Tester");
161+
source.AppendLine(@"{");
162+
source.AppendLine(@" #region Generated Properties");
163+
source.AppendLine(@" public Guid TesterId { get; set; }");
164+
source.AppendLine(@" #endregion");
165+
source.AppendLine(@"}");
166+
167+
168+
var result = RegionParser.ParseRegions(source.ToString());
169+
Assert.NotNull(result);
170+
Assert.Equal(2, result.Count);
171+
172+
var first = result[0];
173+
Assert.NotNull(first);
174+
Assert.Equal("Generated Properties", first.RegionName);
175+
176+
var content = new StringBuilder();
177+
content.AppendLine(@"#region Generated Properties");
178+
content.AppendLine(@" public Guid Id { get; set; }");
179+
content.AppendLine(@" #endregion");
180+
181+
Assert.Equal(content.ToString(), first.Content);
182+
183+
}
152184

153185
}

0 commit comments

Comments
 (0)