1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace I2R.Endpoints.Generator;
[Generator]
public class EndpointGenerator : ISourceGenerator
{
private const string SourceGenereatedComment = "// Generated by I2R.Endpoints, probably smart to leave it be";
public void Initialize(GeneratorInitializationContext context) {
context.RegisterForSyntaxNotifications(() => new EndpointFinder());
}
public void Execute(GeneratorExecutionContext context) {
var endpointClasses = ((EndpointFinder) context.SyntaxReceiver)?.Endpoints;
if (endpointClasses == null) {
context.ReportDiagnostic(CreateDebugDiagnostic("no endpoints were found"));
return;
}
foreach (var info in endpointClasses.Select(GetEndpointInfoFromClass)) {
context.AddSource(info.GeneratedFileName, info.IsSynchronous ? GetSyncSource(info) : GetAsyncSource(info));
}
}
private static Diagnostic CreateDebugDiagnostic(string message) {
var descriptor = new DiagnosticDescriptor("debug", "Debug", message, "debug", DiagnosticSeverity.Warning, true);
return Diagnostic.Create(descriptor, null, "");
}
private class EndpointInfo
{
public string BaseEndpointClassName { get; set; }
public bool IsSynchronous { get; set; }
public string GeneratedFileName { get; set; }
}
public static bool IsSyncEndpoint(string name) {
return name.StartsWith("SyncEndpoint");
}
public static bool IsAyncEndpoint(string name) {
return name.StartsWith("AsyncEndpoint");
}
private static EndpointInfo GetEndpointInfoFromClass(ClassDeclarationSyntax classDeclarationSyntax) {
var baseType = classDeclarationSyntax.BaseList?.Types.FirstOrDefault();
if (baseType == default) {
return default;
}
var fullTypeName = baseType.Type.ToString();
var className = Regex.Match(fullTypeName, "(!?<).+?(?=>)").Value.Replace("<", "");
return new EndpointInfo() {
BaseEndpointClassName = className,
IsSynchronous = IsSyncEndpoint(baseType.ToString()),
GeneratedFileName = className + ".endpoints.g.cs"
};
}
private static string GetSyncSource(EndpointInfo info) {
return $@"
{SourceGenereatedComment}
namespace {typeof(EndpointGenerator).Namespace};
public static partial class SyncEndpoint<T{info.BaseEndpointClassName}>
{{
public static class Req<TRequest>
{{
public abstract class Res<TResponse> : {info.BaseEndpointClassName}
{{
public abstract TResponse Handle(
TRequest request
);
}}
public abstract class NoRes : {info.BaseEndpointClassName}
{{
public abstract void Handle(
TRequest request
);
}}
}}
public static class NoReq
{{
public abstract class Res<TResponse> : {info.BaseEndpointClassName}
{{
public abstract TResponse Handle();
}}
public abstract class NoRes : {info.BaseEndpointClassName}
{{
public abstract void Handle();
}}
}}
}}
";
}
private static string GetAsyncSource(EndpointInfo info) {
return $@"
{SourceGenereatedComment}
namespace {typeof(EndpointGenerator).Namespace};
public static partial class AsyncEndpoint<T>
{{
public static class Req<TRequest>
{{
public abstract class Res<TResponse> : {info.BaseEndpointClassName}
{{
public abstract Task<TResponse> HandleAsync(
TRequest request,
CancellationToken cancellationToken = default
);
}}
public abstract class NoRes : {info.BaseEndpointClassName}
{{
public abstract Task HandleAsync(
TRequest request,
CancellationToken cancellationToken = default
);
}}
}}
public static class NoReq
{{
public abstract class Res<TResponse> : {info.BaseEndpointClassName}
{{
public abstract Task<TResponse> HandleAsync(
CancellationToken cancellationToken = default
);
}}
public abstract class NoRes : {info.BaseEndpointClassName}
{{
public abstract Task HandleAsync(
CancellationToken cancellationToken = default
);
}}
}}
}}
";
}
}
|