Skip to content

Commit a2c69b7

Browse files
authored
Refactoring of the Source Code Generator (#1141)
* Refactoring of the Source Code Generator - Moved the Svg_Model.cs file as SvgModel.cs into the main source. - Restore the standard naming of the generated code files with "*.g.cs" suffix. - Set the output directory of the generated codes to "Generated". - Added the Generated directory to the main source codes. - Moved the Svg.Custom project to Tests directory. * Update runtests.yml - NuGet/setup-nuget@v1 to NuGet/setup-nuget@v2 - Needed to eliminate the warning: Node.js 16 actions are deprecated. * Update AvailableElementsGenerator.cs Removed the comment out portions.
1 parent 02518c4 commit a2c69b7

14 files changed

+264
-238
lines changed

.github/workflows/runtests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
with:
2323
fetch-depth: 0 # needed for GitVersioning to work
2424
- name: Setup NuGet
25-
uses: NuGet/setup-nuget@v1
25+
uses: NuGet/setup-nuget@v2
2626
- name: Cache NuGet packages
2727
uses: actions/cache@v4
2828
id: cache
@@ -61,7 +61,7 @@ jobs:
6161
with:
6262
fetch-depth: 0
6363
- name: Setup NuGet
64-
uses: NuGet/setup-nuget@v1
64+
uses: NuGet/setup-nuget@v2
6565
- name: Cache NuGet packages
6666
uses: actions/cache@v4
6767
id: cache

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,5 @@ Tests/W3CTestSuite/images
361361
Tests/W3CTestSuite/png
362362
Tests/W3CTestSuite/resources
363363
Tests/W3CTestSuite/svg
364+
365+
Source/Generated/**/*.cs

Generators/AvailableElementsGenerator.cs

+9-226
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Text;
66
using Microsoft.CodeAnalysis;
77
using Microsoft.CodeAnalysis.CSharp;
8-
using Microsoft.CodeAnalysis.CSharp.Syntax;
98
using Microsoft.CodeAnalysis.Text;
109

1110
namespace Svg.Generators
@@ -26,78 +25,6 @@ public class AvailableElementsGenerator : ISourceGenerator
2625
DiagnosticSeverity.Error,
2726
isEnabledByDefault: true);
2827

29-
#region Model
30-
31-
/// <summary>
32-
/// The object model used to generate SvgElements descriptors.
33-
/// </summary>
34-
private const string ModelText = @"// <auto-generated />
35-
#nullable disable
36-
using System;
37-
using System.Collections.Generic;
38-
using System.ComponentModel;
39-
using System.Globalization;
40-
41-
namespace Svg
42-
{
43-
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
44-
public sealed class ElementFactoryAttribute : Attribute
45-
{
46-
}
47-
48-
internal enum DescriptorType
49-
{
50-
Property,
51-
Event
52-
}
53-
54-
internal interface ISvgPropertyDescriptor
55-
{
56-
DescriptorType DescriptorType { get; }
57-
string AttributeName { get; }
58-
string AttributeNamespace { get; }
59-
TypeConverter Converter { get; }
60-
Type Type { get; }
61-
object GetValue(object component);
62-
void SetValue(object component, ITypeDescriptorContext context, CultureInfo culture, object value);
63-
}
64-
65-
internal class SvgPropertyDescriptor<T, TU> : ISvgPropertyDescriptor
66-
{
67-
public DescriptorType DescriptorType { get; }
68-
public string AttributeName { get; }
69-
public string AttributeNamespace { get; }
70-
public TypeConverter Converter { get; }
71-
public Type Type { get; } = typeof(TU);
72-
private Func<T, TU> Getter { get; }
73-
private Action<T, TU> Setter { get; }
74-
75-
public SvgPropertyDescriptor(DescriptorType descriptorType, string attributeName, string attributeNamespace, TypeConverter converter, Func<T, TU> getter, Action<T, TU> setter)
76-
{
77-
DescriptorType = descriptorType;
78-
AttributeName = attributeName;
79-
AttributeNamespace = attributeNamespace;
80-
Converter = converter;
81-
Getter = getter;
82-
Setter = setter;
83-
}
84-
85-
public object GetValue(object component)
86-
{
87-
return (object)Getter((T)component);
88-
}
89-
90-
public void SetValue(object component, ITypeDescriptorContext context, CultureInfo culture, object value)
91-
{
92-
if (Converter != null)
93-
{
94-
Setter((T)component, (TU)Converter.ConvertFrom(context, culture, value));
95-
}
96-
}
97-
}
98-
}";
99-
#endregion
100-
10128
/// <inheritdoc/>
10229
public void Initialize(GeneratorInitializationContext context)
10330
{
@@ -109,17 +36,13 @@ public void Initialize(GeneratorInitializationContext context)
10936
/// <inheritdoc/>
11037
public void Execute(GeneratorExecutionContext context)
11138
{
112-
// Add the ElementFactory model source to compilation.
113-
context.AddSource("Svg_Model", SourceText.From(ModelText, Encoding.UTF8));
114-
11539
// Check is we have our SyntaxReceiver object used to filter compiled code.
11640
if (!(context.SyntaxReceiver is SyntaxReceiver receiver))
11741
{
11842
return;
11943
}
12044

121-
var options = (context.Compilation as CSharpCompilation)?.SyntaxTrees[0].Options as CSharpParseOptions;
122-
var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(ModelText, Encoding.UTF8), options));
45+
var compilation = context.Compilation;
12346

12447
var elementFactoryAttribute = compilation.GetTypeByMetadataName("Svg.ElementFactoryAttribute");
12548
if (elementFactoryAttribute is null)
@@ -367,7 +290,7 @@ internal virtual bool SetValue(string attributeName, ITypeDescriptorContext cont
367290
}}
368291
}}
369292
");
370-
context.AddSource($"Svg_SvgElement_Properties.cs", SourceText.From(source.ToString(), Encoding.UTF8));
293+
context.AddSource($"Svg.SvgElement.Properties.g.cs", SourceText.From(source.ToString(), Encoding.UTF8));
371294
source.Clear();
372295

373296
// Generate SvgElement derived classes with descriptor Properties dictionary.
@@ -456,7 +379,7 @@ internal override bool SetValue(string attributeName, ITypeDescriptorContext con
456379
}}
457380
}}
458381
");
459-
context.AddSource($"{namespaceElement.Replace('.', '_')}_{element.Symbol.Name}_Properties.cs", SourceText.From(source.ToString(), Encoding.UTF8));
382+
context.AddSource($"{namespaceElement}.{element.Symbol.Name}.Properties.g.cs", SourceText.From(source.ToString(), Encoding.UTF8));
460383
source.Clear();
461384
}
462385

@@ -492,7 +415,7 @@ internal static class SvgElements
492415
}
493416
}
494417
");
495-
context.AddSource($"Svg_SvgElements.cs", SourceText.From(source.ToString(), Encoding.UTF8));
418+
context.AddSource($"Svg.SvgElements.g.cs", SourceText.From(source.ToString(), Encoding.UTF8));
496419
source.Clear();
497420

498421
// Generate ElementFactory class.
@@ -586,7 +509,7 @@ internal partial class {classElementFactory}
586509
}}
587510
}}");
588511

589-
context.AddSource($"{namespaceElementFactory.Replace('.', '_')}_{elementFactorySymbol.Name}_ElementFactory.cs", SourceText.From(source.ToString(), Encoding.UTF8));
512+
context.AddSource($"{namespaceElementFactory}.{elementFactorySymbol.Name}.ElementFactory.g.cs", SourceText.From(source.ToString(), Encoding.UTF8));
590513
source.Clear();
591514
}
592515

@@ -755,6 +678,10 @@ private static IEnumerable<INamedTypeSymbol> GetBaseTypes(INamedTypeSymbol named
755678
{
756679
"System.String" => "System.ComponentModel.StringConverter",
757680
"System.Single" => "System.ComponentModel.SingleConverter",
681+
"System.Int16" => "System.ComponentModel.Int16Converter",
682+
"System.Int32" => "System.ComponentModel.Int32Converter",
683+
"System.Int64" => "System.ComponentModel.Int64Converter",
684+
"System.Boolean" => "System.ComponentModel.BooleanConverter",
758685
"System.Uri" => "System.UriTypeConverter",
759686
_ => null
760687
};
@@ -863,149 +790,5 @@ private static IEnumerable<Property> GetElementProperties(Compilation compilatio
863790
}
864791
}
865792
}
866-
867-
/// <summary>
868-
/// Symbol member type.
869-
/// </summary>
870-
private enum MemberType
871-
{
872-
/// <summary>
873-
/// Property symbol.
874-
/// </summary>
875-
Property,
876-
/// <summary>
877-
/// Event symbol.
878-
/// </summary>
879-
Event
880-
}
881-
882-
/// <summary>
883-
/// The SvgElement object property/event.
884-
/// </summary>
885-
private class Property
886-
{
887-
/// <summary>
888-
/// Gets or sets property/event symbol.
889-
/// </summary>
890-
public ISymbol Symbol { get; }
891-
892-
/// <summary>
893-
/// Gets or sets property/event symbol member type.
894-
/// </summary>
895-
public MemberType MemberType { get; }
896-
897-
/// <summary>
898-
/// Gets or sets property/event attribute name.
899-
/// </summary>
900-
public string AttributeName { get; }
901-
902-
/// <summary>
903-
/// Gets or sets property/event attribute namespace.
904-
/// </summary>
905-
public string AttributeNamespace { get; }
906-
907-
/// <summary>
908-
/// Gets or sets property/event type converter type string.
909-
/// </summary>
910-
public string? Converter { get; }
911-
912-
/// <summary>
913-
/// Initializes a new instance of the <see cref="Property"/> class.
914-
/// </summary>
915-
/// <param name="symbol">The property/event symbol.</param>
916-
/// <param name="memberType">The property/event symbol member type.</param>
917-
/// <param name="attributeName">The property/event attribute name.</param>
918-
/// <param name="attributeNamespace">The property/event attribute namespace.</param>
919-
/// <param name="converter">The property/event type converter type string.</param>
920-
public Property(ISymbol symbol, MemberType memberType, string attributeName, string attributeNamespace, string? converter)
921-
{
922-
Symbol = symbol;
923-
MemberType = memberType;
924-
AttributeName = attributeName;
925-
AttributeNamespace = attributeNamespace;
926-
Converter = converter;
927-
}
928-
}
929-
930-
/// <summary>
931-
/// Custom <see cref="Property"/> equality comparer using <see cref="ISymbol"/> for cmparison.
932-
/// </summary>
933-
private class PropertyEqualityComparer : IEqualityComparer<Property>
934-
{
935-
/// <inheritdoc/>
936-
public bool Equals(Property p1, Property p2)
937-
{
938-
return SymbolEqualityComparer.Default.Equals(p1.Symbol, p2.Symbol);
939-
}
940-
941-
/// <inheritdoc/>
942-
public int GetHashCode(Property p)
943-
{
944-
#pragma warning disable RS1024
945-
return p.Symbol.GetHashCode();
946-
#pragma warning restore RS1024
947-
}
948-
}
949-
950-
/// <summary>
951-
/// The SvgElement object.
952-
/// </summary>
953-
private class Element
954-
{
955-
/// <summary>
956-
/// Gets or sets element type symbol.
957-
/// </summary>
958-
public INamedTypeSymbol Symbol { get; }
959-
960-
/// <summary>
961-
/// Gets or sets element name.
962-
/// </summary>
963-
public string? ElementName { get; }
964-
965-
/// <summary>
966-
/// Gets or sets classes that use element name.
967-
/// </summary>
968-
public List<string> ClassNames { get; }
969-
970-
/// <summary>
971-
/// Gets or sets element properties list.
972-
/// </summary>
973-
public List<Property> Properties { get; }
974-
975-
/// <summary>
976-
/// Initializes a new instance of the <see cref="Element"/> class.
977-
/// </summary>
978-
/// <param name="symbol">The element type symbol.</param>
979-
/// <param name="elementName">The element name.</param>
980-
/// <param name="classNames">The classes that use element name.</param>
981-
/// <param name="properties">The element properties list.</param>
982-
public Element(INamedTypeSymbol symbol, string? elementName, List<string> classNames, List<Property> properties)
983-
{
984-
Symbol = symbol;
985-
ElementName = elementName;
986-
ClassNames = classNames;
987-
Properties = properties;
988-
}
989-
}
990-
991-
/// <summary>
992-
/// The SyntaxReceiver is used to filter compiled code. This enable quick and easy way to filter compiled code.
993-
/// </summary>
994-
private class SyntaxReceiver : ISyntaxReceiver
995-
{
996-
/// <summary>
997-
/// Gets the list of all candidate class.
998-
/// </summary>
999-
public List<ClassDeclarationSyntax> CandidateClasses { get; } = new();
1000-
1001-
/// <inheritdoc/>
1002-
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
1003-
{
1004-
if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax)
1005-
{
1006-
CandidateClasses.Add(classDeclarationSyntax);
1007-
}
1008-
}
1009-
}
1010793
}
1011794
}

Generators/Element.cs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System.Collections.Generic;
2+
using Microsoft.CodeAnalysis;
3+
4+
namespace Svg.Generators
5+
{
6+
/// <summary>
7+
/// The SvgElement object.
8+
/// </summary>
9+
class Element
10+
{
11+
/// <summary>
12+
/// Gets or sets element type symbol.
13+
/// </summary>
14+
public INamedTypeSymbol Symbol { get; }
15+
16+
/// <summary>
17+
/// Gets or sets element name.
18+
/// </summary>
19+
public string? ElementName { get; }
20+
21+
/// <summary>
22+
/// Gets or sets classes that use element name.
23+
/// </summary>
24+
public List<string> ClassNames { get; }
25+
26+
/// <summary>
27+
/// Gets or sets element properties list.
28+
/// </summary>
29+
public List<Property> Properties { get; }
30+
31+
/// <summary>
32+
/// Initializes a new instance of the <see cref="Element"/> class.
33+
/// </summary>
34+
/// <param name="symbol">The element type symbol.</param>
35+
/// <param name="elementName">The element name.</param>
36+
/// <param name="classNames">The classes that use element name.</param>
37+
/// <param name="properties">The element properties list.</param>
38+
public Element(INamedTypeSymbol symbol, string? elementName, List<string> classNames, List<Property> properties)
39+
{
40+
Symbol = symbol;
41+
ElementName = elementName;
42+
ClassNames = classNames;
43+
Properties = properties;
44+
}
45+
}
46+
}

Generators/MemberType.cs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Svg.Generators
2+
{
3+
/// <summary>
4+
/// Symbol member type.
5+
/// </summary>
6+
enum MemberType
7+
{
8+
/// <summary>
9+
/// Property symbol.
10+
/// </summary>
11+
Property,
12+
/// <summary>
13+
/// Event symbol.
14+
/// </summary>
15+
Event
16+
}
17+
}

0 commit comments

Comments
 (0)