Skip to content

Commit

Permalink
Adjust namespaces
Browse files Browse the repository at this point in the history
  • Loading branch information
ramoneeza committed Jul 7, 2023
1 parent 7d9307c commit 0a4dfe5
Show file tree
Hide file tree
Showing 63 changed files with 609 additions and 1,129 deletions.
86 changes: 86 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,91 @@ Rop.Generators is a free and open source project, licensed under the MIT license

Each package is published in nuget

Rop.ControllerGenerator
------------------------
This generator is designed to automate the creation of controllers for any application.
This is specialy userful for WinForms applications, but can be used in any other type of application.

- A Controller must be a class that resides in a "Controllers" path in the project, or
alternatively, a class decorated with the attribute `[Controller]`

- A Controller must have derive from a generic class with the following signature:
`BaseController<T>` where T is the type of the form that the controller will handle.

- A controler must have a contructor with the following signature:
`public Controller(T form) : base(form)`
where T is the type of the form that the controller will handle.

In the other hand, the form must be partial and decorated with the attribute `[InsertControllers]` and must have the following line in the constructor:
```
public Form1() {
[...]
InitControllers();
[...]
}
```

The nuget package Rop.ControllerGenerator.Annotations is required in order to use the attributes.

Rop.CopyPartialGenerator
------------------------
This generator is designed to automate the creation of horizontaly derived classes for any application.
There are three types of new classes that can be generated:

- `[CopyPArtialTo]`A partial class that derives from another partial class (usualy to implements an interface).
This kind of partial class is userful when you need to implement an interface in a class whith exactly the same code.
- `[CopyPartialAsImmutableRecord]` A partial class that derives from another partial class but as Immutable Record.
This kind of partial class is userful when you need to implement a immutable version of a class.
- `[CopyPartialAsEditableClass]` A partial class that derives from another partial class but as an Editable Class.
This kind of partial class is userful when you need to implement a editable version of an immutable class.

The nuget package Rop.CopyPartialGenerator.Annotations is required in order to use the attributes.

Rop.DerivedFromGenerator
------------------------
This generator is designed to allow the creation of derived classes when generic base classes are not allowded.
This is specialy userful for WinForms applications, but can be used in any other type of application.

- The derived class must be a partial class whit an interface of type `IDerivedFrom`

The nuget package Rop.DerivedFromGenerator.Annotations is required in order to use the interface.

Rop.OneOfExtensionsGenerator
------------------------

This generator is designed to allow the creation of extension methods based on OneOf methods.
This is specialy userful when you need to create extension methods for each type of a OneOf type.
This avoid to repeating code for each type of the OneOf type.

- The extension class must be a partial static class decorated with the attribute `[OneOfExtensions]`
- The OneOf Extension methods can be private and prefixed with `_`
- The OneOf Extensio methods must be decorated with the attribute `[SplitOneOf]`

The nuget package Rop.OneOfExtensionsGenerator.Annotations is required in order to use the attributes.
The nuget package OneOf is required in order to use the OneOf type.

Rop.ProxyGenerator
------------------------

Rop.ProxyGenerator is a source generator package to automatic proxy of interfaces.
It can be used to provide Aspect Oriented Programming to c# via a "proxy".

-The partial class to be generated must be decorated with the attribute `[ProxyOf(interface,property into the class to be proxied, excluded names to be proxied)]`
-The partial class must have a property of a field with a instance of the interface to be proxied.
-There are a lot of auxiliary attributesd to control the proxy behavior.

The nuget package Rop.ProxyGenerator.Annotations is required in order to use the attributes.

Rop.StaticExtensionGenerator
------------------------

Rop.StaticExtensionGenerator is a source generator package to automatic static extension methods.
It can be used to provide static extension methods to classes. The current c# languaje does not allow to create static extension methods.

-The class to contain the static extension must be a generic class where the first generic type is the type class to be extended.
-The class where implement the static extension must be decorated with the attribute `[StaticExtension<MyStaticExtension<T,...>>()]`

The nuget package Rop.StaticExtensionGenerator.Annotations is required in order to use the attributes.

------
(C)2022 Ramón Ordiales Plaza
9 changes: 0 additions & 9 deletions Rop.ControllerGenerator.Annotations/Class1.cs

This file was deleted.

8 changes: 8 additions & 0 deletions Rop.ControllerGenerator.Annotations/ControllerAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;

namespace Rop.ControllerGenerator.Annotations;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ControllerAttribute : Attribute
{
}
10 changes: 10 additions & 0 deletions Rop.ControllerGenerator.Annotations/InsertControllersAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace Rop.ControllerGenerator.Annotations
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class InsertControllersAttribute : Attribute
{
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

Expand Down
49 changes: 25 additions & 24 deletions Rop.ControllerGenerator/ControllerToInclude.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Rop.GeneratorHelper;
using Rop.Generators.Shared;

namespace Rop.Winforms7.ControllerGenerator
{
public class ControllerToInclude
{
public string ControllerName { get; }
public string DesiredInstanceName { get; private set; } = "";
public ClassDeclarationSyntax Cds { get; }
public INamedTypeSymbol NamedTypeSymbol { get; private set; } = null;
public string ControllerFor { get; private set; }="";
public string ControllerNamesPace { get; private set; }
public ControllerToInclude(ClassDeclarationSyntax cds)
public string DesiredInstanceName { get; }
public INamedTypeSymbol NamedTypeSymbol { get; }
public string ControllerFor { get;}
public string ControllerNamesPace { get; }

private ControllerToInclude(INamedTypeSymbol namedTypeSymbol, string controllerName, string desiredInstanceName, string controllerFor, string controllerNamesPace)
{
ControllerName = cds.Identifier.Text;
Cds=cds;
ControllerNamesPace = cds.SyntaxTree.GetNamespace();
NamedTypeSymbol = namedTypeSymbol;
ControllerName = controllerName;
DesiredInstanceName = desiredInstanceName;
ControllerFor = controllerFor;
ControllerNamesPace = controllerNamesPace;
}

public bool IsControllerFor(string name, Compilation contextCompilation)
public static ControllerToInclude Factory(ClassDeclarationSyntax controller, Compilation contextCompilation)
{
if (NamedTypeSymbol == null)
{
var candidatos=contextCompilation.GetSymbolsWithName(s => s.EndsWith(ControllerName), SymbolFilter.Type);
NamedTypeSymbol = candidatos.FirstOrDefault() as INamedTypeSymbol;
var baseType = NamedTypeSymbol?.BaseType;
if (baseType?.IsGenericType??false)
{
ControllerFor = baseType.TypeArguments[0].Name;
}
DesiredInstanceName = ControllerName.StartsWith(ControllerFor) ? ControllerName.Substring(ControllerFor.Length) : ControllerName;
}
return ControllerFor == name;
var controllerName = controller.Identifier.Text;
var controllerNamesPace = controller.SyntaxTree.GetNamespace();
if (string.IsNullOrEmpty(controllerNamesPace)) return null;
var namedtypesymbol = contextCompilation.GetSymbolsWithName(s => s.EndsWith(controllerName), SymbolFilter.Type)
.OfType<INamedTypeSymbol>().FirstOrDefault();
if (namedtypesymbol == null) return null;
var baseType = namedtypesymbol.BaseType;
if (baseType == null) return null;
if (!baseType.IsGenericType) return null;
var controllerFor = baseType.TypeArguments[0].Name;
var desiredInstanceName = controllerName.StartsWith(controllerFor) ? controllerName.Substring(controllerFor.Length) : controllerName;
return new ControllerToInclude(namedtypesymbol, controllerName, desiredInstanceName, controllerFor, controllerNamesPace);
}
}
}
49 changes: 27 additions & 22 deletions Rop.ControllerGenerator/InsertControllerGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Rop.GeneratorHelper;
using Rop.Generators.Shared;

namespace Rop.Winforms7.ControllerGenerator
{
Expand All @@ -14,42 +14,29 @@ public class InsertControllerGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
//#if DEBUG
// if (!Debugger.IsAttached)
// {
// Debugger.Launch();
// }
//#endif
context.RegisterForSyntaxNotifications(() => new ClassesToAugmentReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
var collector = context.SyntaxReceiver as ClassesToAugmentReceiver;
if (collector == null || collector.ClassesToAugment.Count == 0) return;
if (collector == null || collector.ClassesToAugment.Count == 0 || collector.ControllersToInclude.Count==0) return;
var dic=collector.ProcessControllers(context.Compilation);
foreach (var classtoaugment in collector.ClassesToAugment)
{
generateCode(context, classtoaugment,collector);
generateCode(context, classtoaugment,dic);
}
collector.Clear();
}
private void generateCode(GeneratorExecutionContext context, PartialClassToAugment classtoaugment,ClassesToAugmentReceiver receiver)
private void generateCode(GeneratorExecutionContext context, PartialClassToAugment classtoaugment,Dictionary<string,List<ControllerToInclude>> diccontrollers)
{
var formname=classtoaugment.Identifier;
var file = classtoaugment.FileName +".Controllers_.g.cs";
var model = context.Compilation.GetSemanticModel(classtoaugment.Original.SyntaxTree);
var classmodel = (INamedTypeSymbol)model.GetDeclaredSymbol(classtoaugment.Original);
if (classmodel is null) return;
var finalcontrollers=classtoaugment.GetControllersToInclude(context.Compilation,receiver.ControllersToInclude);
if (!diccontrollers.TryGetValue(formname, out var finalcontrollers)) return;
var sb = new StringBuilder();
sb.AppendLine("// Autogenerated code for Controllers");
if (finalcontrollers.Count == 0)
{
// ERROR NO CONTROLLERS
sb.AppendLines("// ERROR NO CONTROLLERS",$"// Looking for:{classtoaugment.Identifier}");
var finalerror = sb.ToString();
context.AddSource(file, finalerror);
return;
}
var usings = finalcontrollers.Select(x => x.ControllerNamesPace).Distinct().ToList();
sb.AppendLines(classtoaugment.GetHeader(usings));
foreach (var symbol in finalcontrollers)
Expand All @@ -71,7 +58,7 @@ private void generateCode(GeneratorExecutionContext context, PartialClassToAugme
class ClassesToAugmentReceiver : ISyntaxReceiver
{
public ConcurrentBag<PartialClassToAugment> ClassesToAugment { get; private set; } = new ConcurrentBag<PartialClassToAugment>();
public ConcurrentBag<ControllerToInclude> ControllersToInclude { get; private set; } = new ConcurrentBag<ControllerToInclude>();
public ConcurrentBag<ClassDeclarationSyntax> ControllersToInclude { get; private set; } = new ConcurrentBag<ClassDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (!(syntaxNode is ClassDeclarationSyntax cds)) return;
Expand All @@ -83,13 +70,31 @@ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
}
if (cds.IsDecoratedWith("Controller") || (cds.SyntaxTree.GetNamespace().EndsWith("Controllers")))
{
if ((cds.BaseList?.Types.Count??0) != 0) ControllersToInclude.Add(new ControllerToInclude(cds));
if ((cds.BaseList?.Types.Count??0) != 0) ControllersToInclude.Add(cds);
}
}
public void Clear()
{
ClassesToAugment = new ConcurrentBag<PartialClassToAugment>();
ControllersToInclude = new ConcurrentBag<ControllerToInclude>();
ControllersToInclude = new ConcurrentBag<ClassDeclarationSyntax>();
}

public Dictionary<string,List<ControllerToInclude>> ProcessControllers(Compilation contextCompilation)
{
var dic=new Dictionary<string,List<ControllerToInclude>>();
foreach (var controller in ControllersToInclude)
{
var cti=ControllerToInclude.Factory(controller,contextCompilation);
if (cti is null) continue;
var name = cti.ControllerFor;
if (!dic.TryGetValue(name, out var lst))
{
lst=new List<ControllerToInclude>();
dic[name]=lst;
}
lst.Add(cti);
}
return dic;
}
}
}
Expand Down
60 changes: 9 additions & 51 deletions Rop.ControllerGenerator/PartialClassToAugment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,27 @@
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Rop.GeneratorHelper;
using Rop.Generators.Shared;
using Rop.GeneratorShared;

namespace Rop.Winforms7.ControllerGenerator
{
public class PartialClassToAugment
public class PartialClassToAugment:BasePartialClassToAugment
{
public bool IsStatic { get; }
public bool IsGeneric { get; }
public string GenericTypes { get; }
public string Identifier { get; }
public string FileName { get; }
public string Namespace { get; }
public string Modifier { get; }
public IReadOnlyList<(string name, string sentence)> Usings { get; }
public ClassDeclarationSyntax Original { get; }
public PartialClassToAugment(ClassDeclarationSyntax classToAugment)
public PartialClassToAugment(ClassDeclarationSyntax classToAugment) : base(classToAugment)
{
Original= classToAugment;
Identifier = classToAugment.Identifier.ToString();
var stfp = Path.GetFileNameWithoutExtension(classToAugment.SyntaxTree.FilePath);
FileName = (string.IsNullOrEmpty(stfp)) ? Identifier : stfp;
Usings = classToAugment.SyntaxTree.GetUsings().ToList();
Namespace = classToAugment.SyntaxTree.GetNamespace();
Modifier = classToAugment.Modifiers.FirstOrDefault().ToString();
IsStatic = classToAugment.IsStatic();
IsGeneric = classToAugment.IsGeneric();
GenericTypes = (IsGeneric) ? classToAugment.TypeParameterList?.ToString()??"" : "";
}
public IEnumerable<string> GetHeader(IEnumerable<string> additionalusings)
{
yield return "#nullable enable";
foreach (var u in Usings)
return GetHeader0().Concat(GetHeader1()).Concat(GetNamespace0()).Concat(GetClass0());
// Local functions
IEnumerable<string> GetHeader1()
{
yield return u.sentence;
}

foreach (var additionalusing in additionalusings)
{
yield return $"using {additionalusing};";
}
yield return $"namespace {Namespace}";
yield return "{";
yield return $"\t{Modifier} {(IsStatic?"static ":"")}partial class {Identifier}{GenericTypes}";
yield return "\t{";
}
public IEnumerable<string> GetFooter()
{
yield return "\t}";
yield return "}";
}

public List<ControllerToInclude> GetControllersToInclude(Compilation contextCompilation, IEnumerable<ControllerToInclude> controllers)
{
var name=this.Identifier;
var res=new List<ControllerToInclude>();
foreach (var c in controllers)
{
if (c.IsControllerFor(name, contextCompilation))
foreach (var additionalusing in additionalusings)
{
res.Add(c);
yield return $"using {additionalusing};";
}
}
return res;
}
}
}
2 changes: 1 addition & 1 deletion Rop.ControllerGenerator/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
},
"DebugComponent": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\test.winforms7\\test.winforms7.csproj"
"targetProject": "..\\tests\test.controllerGenerator\\test.controllergenerator.csproj"
}
}
}
Loading

0 comments on commit 0a4dfe5

Please sign in to comment.