* Added ReplyKeyboardMarkupGenerator
* Added set of markup attributes dedicatedf to map a keyboard using partial methods
This commit is contained in:
@@ -5,4 +5,9 @@
|
|||||||
|
|
||||||
Rule ID | Category | Severity | Notes
|
Rule ID | Category | Severity | Notes
|
||||||
--------|----------|----------|-------
|
--------|----------|----------|-------
|
||||||
|
TG_1001 | Modelling | Error | GeneratedKeyboardMarkupGenerator
|
||||||
|
TG_1002 | Modelling | Error | GeneratedKeyboardMarkupGenerator
|
||||||
|
TG_1003 | Modelling | Error | GeneratedKeyboardMarkupGenerator
|
||||||
|
TG_1004 | Modelling | Error | GeneratedKeyboardMarkupGenerator
|
||||||
|
TG_1005 | Modelling | Error | GeneratedKeyboardMarkupGenerator
|
||||||
TR0001 | Aspect | Error | DiagnosticsHelper
|
TR0001 | Aspect | Error | DiagnosticsHelper
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Telegrator.RoslynExtensions;
|
||||||
|
|
||||||
namespace Telegrator.Analyzers
|
namespace Telegrator.Analyzers
|
||||||
{
|
{
|
||||||
@@ -33,7 +34,7 @@ namespace Telegrator.Analyzers
|
|||||||
private static HandlerDeclarationModel Transform(GeneratorSyntaxContext context, CancellationToken cancellationToken)
|
private static HandlerDeclarationModel Transform(GeneratorSyntaxContext context, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ClassDeclarationSyntax classSyntax = (ClassDeclarationSyntax)context.Node;
|
ClassDeclarationSyntax classSyntax = (ClassDeclarationSyntax)context.Node;
|
||||||
IEnumerable<AttributeSyntax> attributes = classSyntax.GetHandlerAttributes();
|
IEnumerable<AttributeSyntax> attributes = []; //classSyntax.GetHandlerAttributes();
|
||||||
BaseTypeSyntax? baseType = classSyntax.GetHandlerBaseClass();
|
BaseTypeSyntax? baseType = classSyntax.GetHandlerBaseClass();
|
||||||
|
|
||||||
if (baseType == null && !attributes.Any())
|
if (baseType == null && !attributes.Any())
|
||||||
@@ -58,7 +59,7 @@ namespace Telegrator.Analyzers
|
|||||||
context.CancellationToken.ThrowIfCancellationRequested();
|
context.CancellationToken.ThrowIfCancellationRequested();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
usingDirectives.UnionAdd(handler.ClassDeclaration.FindCompilationUnitSyntax().Usings.Select(use => use.ToString()));
|
usingDirectives.UnionAdd(handler.ClassDeclaration.FindAncestor<CompilationUnitSyntax>().Usings.Select(use => use.ToString()));
|
||||||
ParseHandlerDeclaration(context, sourceBuilder, handler, context.CancellationToken);
|
ParseHandlerDeclaration(context, sourceBuilder, handler, context.CancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
using Microsoft.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Telegrator.Analyzers
|
|
||||||
{
|
|
||||||
public static class DiagnosticsHelper
|
|
||||||
{
|
|
||||||
public const string Aspect = "Aspect";
|
|
||||||
|
|
||||||
public static readonly DiagnosticDescriptor Test = new DiagnosticDescriptor("TR0001", "Test descriptor", string.Empty, Aspect, DiagnosticSeverity.Error, true, "Test diagnostic description.");
|
|
||||||
|
|
||||||
public static Diagnostic Create(this DiagnosticDescriptor descriptor, Location? location, params object[] messageArgs)
|
|
||||||
=> Diagnostic.Create(descriptor, location, messageArgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Telegrator.Analyzers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Exception thrown when a target is not found during code generation.
|
|
||||||
/// </summary>
|
|
||||||
internal class TargteterNotFoundException() : Exception() { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Exception thrown when a base class type is not found during code generation.
|
|
||||||
/// </summary>
|
|
||||||
internal class BaseClassTypeNotFoundException() : Exception() { }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,341 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using Telegrator.RoslynExtensions;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
using System.Diagnostics;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Telegrator.Analyzers
|
||||||
|
{
|
||||||
|
[Generator(LanguageNames.CSharp)]
|
||||||
|
public class GeneratedKeyboardMarkupGenerator : IIncrementalGenerator
|
||||||
|
{
|
||||||
|
private const string InlineReturnType = "InlineKeyboardMarkup";
|
||||||
|
private const string ReplyReturnType = "ReplyKeyboardMarkup";
|
||||||
|
|
||||||
|
private const string CallbackDataAttribute = "CallbackButton";
|
||||||
|
private const string CallbackGameAttribute = "GameButton";
|
||||||
|
private const string CopyTextAttribute = "CopyTextButton";
|
||||||
|
private const string LoginRequestAttribute = "LoginRequestButton";
|
||||||
|
private const string PayRequestAttribute = "PayRequestButton";
|
||||||
|
private const string SwitchQueryAttribute = "SwitchQueryButton";
|
||||||
|
private const string QueryChosenAttribute = "QueryChosenButton";
|
||||||
|
private const string QueryCurrentAttribute = "QueryCurrentButton";
|
||||||
|
private const string UrlRedirectAttribute = "UrlRedirectButton";
|
||||||
|
private const string WebAppAttribute = "WebApp";
|
||||||
|
|
||||||
|
private static readonly string[] InlineAttributes = [CallbackDataAttribute, CallbackGameAttribute, CopyTextAttribute, LoginRequestAttribute, PayRequestAttribute, UrlRedirectAttribute, WebAppAttribute, SwitchQueryAttribute, QueryChosenAttribute, QueryCurrentAttribute];
|
||||||
|
private static readonly string[] ReplyAttributes = [];
|
||||||
|
private static readonly string[] DefaultUsings = ["Telegram.Bot.Types.ReplyMarkups"];
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, MemberAccessExpressionSyntax> InlineKeyboardLayout = new Dictionary<string, MemberAccessExpressionSyntax>()
|
||||||
|
{
|
||||||
|
{ CallbackDataAttribute, AccessExpression("InlineKeyboardButton", "WithCallbackData") },
|
||||||
|
{ CallbackGameAttribute, AccessExpression("InlineKeyboardButton", "WithCallbackGame") },
|
||||||
|
{ CopyTextAttribute, AccessExpression("InlineKeyboardButton", "WithCopyText") },
|
||||||
|
{ LoginRequestAttribute, AccessExpression("InlineKeyboardButton", "WithLoginUrl") },
|
||||||
|
{ PayRequestAttribute, AccessExpression("InlineKeyboardButton", "WithPay") },
|
||||||
|
{ SwitchQueryAttribute, AccessExpression("InlineKeyboardButton", "WithSwitchInlineQuery") },
|
||||||
|
{ QueryChosenAttribute, AccessExpression("InlineKeyboardButton", "WithSwitchInlineQueryChosenChat") },
|
||||||
|
{ QueryCurrentAttribute, AccessExpression("InlineKeyboardButton", "WithSwitchInlineQueryCurrentChat") },
|
||||||
|
{ UrlRedirectAttribute, AccessExpression("InlineKeyboardButton", "WithUrl") },
|
||||||
|
{ WebAppAttribute, AccessExpression("InlineKeyboardButton", "WithWebApp") },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, MemberAccessExpressionSyntax> ReplyKeyboardLayout = new Dictionary<string, MemberAccessExpressionSyntax>()
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, Dictionary<string, MemberAccessExpressionSyntax>> LayoutNames = new Dictionary<string, Dictionary<string, MemberAccessExpressionSyntax>>()
|
||||||
|
{
|
||||||
|
{ InlineReturnType, InlineKeyboardLayout },
|
||||||
|
{ ReplyReturnType, ReplyKeyboardLayout }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly DiagnosticDescriptor WrongReturnType = new DiagnosticDescriptor("TG_1001", "Wrong return type", string.Empty, "Modelling", DiagnosticSeverity.Error, true);
|
||||||
|
private static readonly DiagnosticDescriptor UnsupportedAttribute = new DiagnosticDescriptor("TG_1002", "Unsupported attribute", string.Empty, "Modelling", DiagnosticSeverity.Error, true);
|
||||||
|
private static readonly DiagnosticDescriptor NotPartialMethod = new DiagnosticDescriptor("TG_1003", "Not a partial method", string.Empty, "Modelling", DiagnosticSeverity.Error, true);
|
||||||
|
private static readonly DiagnosticDescriptor UseBodylessMethod = new DiagnosticDescriptor("TG_1004", "Use bodyless method", string.Empty, "Modelling", DiagnosticSeverity.Error, true);
|
||||||
|
private static readonly DiagnosticDescriptor UseParametrlessMethod = new DiagnosticDescriptor("TG_1005", "Use parametrless method", string.Empty, "Modelling", DiagnosticSeverity.Error, true);
|
||||||
|
|
||||||
|
private static SyntaxTrivia TabulationTrivia => SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\t");
|
||||||
|
private static SyntaxTrivia WhitespaceTrivia => SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " ");
|
||||||
|
private static SyntaxTrivia NewLineTrivia => SyntaxFactory.SyntaxTrivia(SyntaxKind.EndOfLineTrivia, "\n");
|
||||||
|
private static SyntaxToken Semicolon => SyntaxFactory.Token(SyntaxKind.SemicolonToken);
|
||||||
|
|
||||||
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
|
{
|
||||||
|
IncrementalValueProvider<ImmutableArray<MethodDeclarationSyntax>> pipeline = context.SyntaxProvider.CreateSyntaxProvider(Provide, Transform).Where(x => x != null).Collect();
|
||||||
|
context.RegisterSourceOutput(pipeline, Execute);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool Provide(SyntaxNode syntaxNode, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
if (syntaxNode is not MethodDeclarationSyntax method)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!HasGenAttributes(method))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodDeclarationSyntax Transform(GeneratorSyntaxContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
return (MethodDeclarationSyntax)context.Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Execute(SourceProductionContext context, ImmutableArray<MethodDeclarationSyntax> methods)
|
||||||
|
{
|
||||||
|
List<GeneratedMarkupMethodModel> models = [];
|
||||||
|
foreach (MethodDeclarationSyntax method in methods)
|
||||||
|
{
|
||||||
|
context.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string methodName = method.Identifier.Text;
|
||||||
|
string returnType = method.ReturnType.ToString();
|
||||||
|
bool anyErrors = false;
|
||||||
|
|
||||||
|
if (!LayoutNames.TryGetValue(returnType, out var layout))
|
||||||
|
{
|
||||||
|
WrongReturnType.Report(context, method.ReturnType.GetLocation());
|
||||||
|
anyErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!method.Modifiers.HasModifiers("partial"))
|
||||||
|
{
|
||||||
|
NotPartialMethod.Report(context, method.Identifier.GetLocation());
|
||||||
|
anyErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.ParameterList.Parameters.Any())
|
||||||
|
{
|
||||||
|
UseParametrlessMethod.Report(context, method.ParameterList.GetLocation());
|
||||||
|
anyErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.ExpressionBody != null)
|
||||||
|
{
|
||||||
|
UseBodylessMethod.Report(context, method.ExpressionBody.GetLocation());
|
||||||
|
anyErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.Body != null)
|
||||||
|
{
|
||||||
|
UseBodylessMethod.Report(context, method.Body.GetLocation());
|
||||||
|
anyErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anyErrors)
|
||||||
|
return;
|
||||||
|
|
||||||
|
context.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
SeparatedSyntaxList<CollectionElementSyntax> vertical = new SeparatedSyntaxList<CollectionElementSyntax>();
|
||||||
|
|
||||||
|
foreach (AttributeListSyntax attributeList in method.AttributeLists)
|
||||||
|
{
|
||||||
|
context.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
SeparatedSyntaxList<CollectionElementSyntax> horizontal = new SeparatedSyntaxList<CollectionElementSyntax>();
|
||||||
|
|
||||||
|
foreach (AttributeSyntax attribute in attributeList.Attributes)
|
||||||
|
{
|
||||||
|
context.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (!layout.TryGetValue(attribute.Name.ToString(), out var accessSyntax))
|
||||||
|
{
|
||||||
|
UnsupportedAttribute.Report(context, attribute.Name.GetLocation());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvocationExpressionSyntax expression = SyntaxFactory.InvocationExpression(accessSyntax, ConvertArguments(attribute.ArgumentList));
|
||||||
|
horizontal = horizontal.Add(SyntaxFactory.ExpressionElement(expression));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionElementSyntax element = SyntaxFactory.ExpressionElement(SyntaxFactory.CollectionExpression(horizontal));
|
||||||
|
vertical = vertical.Add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldDeclarationSyntax genField = GeneratedFieldDeclaration(methodName, method.ReturnType.WithoutTrivia(), SyntaxFactory.CollectionExpression(vertical));
|
||||||
|
MethodDeclarationSyntax genMethod = GeneratedMethodDeclaration(methodName, method.Modifiers, method.ReturnType, genField);
|
||||||
|
|
||||||
|
models.Add(new GeneratedMarkupMethodModel(method, genField, genMethod));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
context.AddSource(method.Identifier.ToString(), ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
CompilationUnitSyntax compilationUnit = SyntaxFactory.CompilationUnit();
|
||||||
|
SyntaxList<UsingDirectiveSyntax> usingDirectives = ParseUsings(DefaultUsings).ToSyntaxList();
|
||||||
|
|
||||||
|
foreach (GeneratedMarkupMethodModel model in models)
|
||||||
|
{
|
||||||
|
context.CancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (model.OriginalMethod.Parent is not ClassDeclarationSyntax containerClass)
|
||||||
|
throw new MissingMemberException();
|
||||||
|
|
||||||
|
FieldDeclarationSyntax genField = model.GeneratedField
|
||||||
|
.WithLeadingTrivia(NewLineTrivia, TabulationTrivia, TabulationTrivia);
|
||||||
|
|
||||||
|
MethodDeclarationSyntax genMethod = model.GeneratedMethod
|
||||||
|
.WithLeadingTrivia(NewLineTrivia, TabulationTrivia, TabulationTrivia);
|
||||||
|
|
||||||
|
//ClassDeclarationSyntax genClass = GeneratedClassDeclaration(containerClass.Identifier.WithLeadingTrivia(WhitespaceTrivia).WithTrailingTrivia(NewLineTrivia), containerClass.Modifiers, genField, genMethod);
|
||||||
|
NamespaceDeclarationSyntax genNamespace = GeneratedNamespaceDeclaration(model.OriginalMethod, [genField, genMethod]);
|
||||||
|
|
||||||
|
genNamespace = genNamespace
|
||||||
|
.WithCloseBraceToken(genNamespace.CloseBraceToken.WithLeadingTrivia(NewLineTrivia));
|
||||||
|
|
||||||
|
compilationUnit = compilationUnit.AddMembers(genNamespace);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
context.AddSource(model.OriginalMethod.Identifier.ToString(), ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compilationUnit = compilationUnit.WithUsings(usingDirectives);
|
||||||
|
context.AddSource("GeneratedKeyboards.g", compilationUnit.ToFullString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private static NamespaceDeclarationSyntax GeneratedNamespaceDeclaration(NameSyntax name, params IEnumerable<MemberDeclarationSyntax> members)
|
||||||
|
{
|
||||||
|
NamespaceDeclarationSyntax genNamespace = SyntaxFactory.NamespaceDeclaration(name)
|
||||||
|
.WithMembers(new SyntaxList<MemberDeclarationSyntax>(members))
|
||||||
|
.WithLeadingTrivia(NewLineTrivia);
|
||||||
|
|
||||||
|
return genNamespace
|
||||||
|
.WithCloseBraceToken(genNamespace.CloseBraceToken.WithLeadingTrivia(NewLineTrivia));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassDeclarationSyntax GeneratedClassDeclaration(SyntaxToken identifier, SyntaxTokenList modifiers, params IEnumerable<MemberDeclarationSyntax> members)
|
||||||
|
{
|
||||||
|
ClassDeclarationSyntax genClass = SyntaxFactory.ClassDeclaration(identifier)
|
||||||
|
.WithMembers(new SyntaxList<MemberDeclarationSyntax>(members))
|
||||||
|
.WithModifiers(modifiers)
|
||||||
|
.WithLeadingTrivia(NewLineTrivia, TabulationTrivia);
|
||||||
|
|
||||||
|
return genClass
|
||||||
|
.WithOpenBraceToken(genClass.OpenBraceToken.WithLeadingTrivia(TabulationTrivia))
|
||||||
|
.WithCloseBraceToken(genClass.CloseBraceToken.WithLeadingTrivia(NewLineTrivia, TabulationTrivia));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static MethodDeclarationSyntax GeneratedMethodDeclaration(string identifier, SyntaxTokenList modifiers, TypeSyntax returnType, FieldDeclarationSyntax field)
|
||||||
|
{
|
||||||
|
return SyntaxFactory.MethodDeclaration(returnType.WithTrailingTrivia(WhitespaceTrivia), identifier)
|
||||||
|
.WithModifiers(modifiers)
|
||||||
|
.WithExpressionBody(SyntaxFactory.ArrowExpressionClause(SyntaxFactory.IdentifierName(field.Declaration.Variables.ElementAt(0).Identifier)))
|
||||||
|
.WithSemicolonToken(Semicolon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FieldDeclarationSyntax GeneratedFieldDeclaration(string identifier, TypeSyntax returnType, CollectionExpressionSyntax collection)
|
||||||
|
{
|
||||||
|
ArgumentListSyntax arguments = SyntaxFactory.ArgumentList(SeparatedSyntaxList(SyntaxFactory.Argument(collection)));
|
||||||
|
ObjectCreationExpressionSyntax objectCreation = SyntaxFactory.ObjectCreationExpression(returnType.WithLeadingTrivia(WhitespaceTrivia), arguments, null);
|
||||||
|
|
||||||
|
VariableDeclaratorSyntax declarator = SyntaxFactory.VariableDeclarator(identifier + "_generatedMarkup")
|
||||||
|
.WithInitializer(SyntaxFactory.EqualsValueClause(objectCreation));
|
||||||
|
|
||||||
|
return SyntaxFactory.FieldDeclaration(SyntaxFactory.VariableDeclaration(returnType.WithTrailingTrivia(WhitespaceTrivia)).AddVariables(declarator))
|
||||||
|
.WithModifiers(Modifiers(SyntaxKind.PrivateKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ArgumentListSyntax ConvertArguments(AttributeArgumentListSyntax? attributeArgs)
|
||||||
|
{
|
||||||
|
if (attributeArgs == null)
|
||||||
|
return SyntaxFactory.ArgumentList();
|
||||||
|
|
||||||
|
return SyntaxFactory.ArgumentList(SeparatedSyntaxList(attributeArgs.Arguments.Select(CastArgument)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NamespaceDeclarationSyntax GeneratedNamespaceDeclaration(MethodDeclarationSyntax method, IEnumerable<MemberDeclarationSyntax> generatedMembers)
|
||||||
|
{
|
||||||
|
if (method.Parent is not ClassDeclarationSyntax containerClass)
|
||||||
|
throw new MemberAccessException();
|
||||||
|
|
||||||
|
int times = method.CountParentTree() - 1;
|
||||||
|
ClassDeclarationSyntax generatedContainerClass = SyntaxFactory.ClassDeclaration(containerClass.Identifier)
|
||||||
|
.WithMembers(new SyntaxList<MemberDeclarationSyntax>(generatedMembers.Select(member => member.DecorateMember(times + 1))))
|
||||||
|
.WithModifiers(containerClass.Modifiers.Decorate())
|
||||||
|
.Decorate(times);
|
||||||
|
|
||||||
|
MemberDeclarationSyntax generated = generatedContainerClass;
|
||||||
|
MemberDeclarationSyntax inspecting = containerClass;
|
||||||
|
|
||||||
|
while (inspecting.Parent != null)
|
||||||
|
{
|
||||||
|
times -= 1;
|
||||||
|
if (inspecting.Parent is not MemberDeclarationSyntax inspectingMember)
|
||||||
|
break;
|
||||||
|
|
||||||
|
inspecting = inspectingMember;
|
||||||
|
switch (inspectingMember)
|
||||||
|
{
|
||||||
|
case ClassDeclarationSyntax classDeclaration:
|
||||||
|
{
|
||||||
|
generated = SyntaxFactory.ClassDeclaration(classDeclaration.Identifier)
|
||||||
|
.WithMembers([generated])
|
||||||
|
.WithModifiers(classDeclaration.Modifiers.Decorate())
|
||||||
|
.Decorate(times);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case StructDeclarationSyntax structDeclaration:
|
||||||
|
{
|
||||||
|
generated = SyntaxFactory.StructDeclaration(structDeclaration.Identifier)
|
||||||
|
.WithMembers([generated])
|
||||||
|
.WithModifiers(structDeclaration.Modifiers.Decorate())
|
||||||
|
.Decorate(times);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NamespaceDeclarationSyntax namespaceDeclaration:
|
||||||
|
{
|
||||||
|
//foundNamespaceDeclaration = namespaceDeclaration;
|
||||||
|
return SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name)
|
||||||
|
.WithMembers([generated]).Decorate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AncestorNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ArgumentSyntax CastArgument(AttributeArgumentSyntax argument)
|
||||||
|
=> SyntaxFactory.Argument(argument.Expression).WithNameColon(argument.NameColon);
|
||||||
|
|
||||||
|
private static SyntaxTokenList Modifiers(params SyntaxKind[] kinds)
|
||||||
|
=> new SyntaxTokenList(kinds.Select(SyntaxFactory.Token).Select(mod => mod.WithTrailingTrivia(WhitespaceTrivia)));
|
||||||
|
|
||||||
|
private static IEnumerable<UsingDirectiveSyntax> ParseUsings(params string[] names) => names
|
||||||
|
.Select(name => SyntaxFactory.IdentifierName(name).WithLeadingTrivia(WhitespaceTrivia))
|
||||||
|
.Select(name => SyntaxFactory.UsingDirective(name).WithTrailingTrivia(NewLineTrivia));
|
||||||
|
|
||||||
|
private static bool HasGenAttributes(MethodDeclarationSyntax method) => method.AttributeLists.SelectMany(x => x.Attributes)
|
||||||
|
.Select(x => x.Name.ToString()).Intersect(InlineAttributes.Concat(ReplyAttributes)).Any();
|
||||||
|
|
||||||
|
private static SeparatedSyntaxList<T> SeparatedSyntaxList<T>(params IEnumerable<T> elements) where T : SyntaxNode
|
||||||
|
=> new SeparatedSyntaxList<T>().AddRange(elements);
|
||||||
|
|
||||||
|
private static MemberAccessExpressionSyntax AccessExpression(string className, string methodName)
|
||||||
|
=> SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(className), SyntaxFactory.IdentifierName(methodName));
|
||||||
|
|
||||||
|
private record class GeneratedMarkupMethodModel(MethodDeclarationSyntax OriginalMethod, FieldDeclarationSyntax GeneratedField, MethodDeclarationSyntax GeneratedMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,31 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
<Configurations>Debug;Release;AnalyzersDebug</Configurations>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0">
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
|
||||||
|
|
||||||
|
<PackageReference Include="PolySharp" Version="1.15.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\dev\Telegrator.RoslynExtensions\Telegrator.RoslynExtensions.csproj" PrivateAssets="all" />
|
||||||
|
<None Include="$(OutputPath)\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
using Microsoft.CodeAnalysis;
|
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Telegrator.Analyzers
|
|
||||||
{
|
|
||||||
internal static class TypeExtensions
|
|
||||||
{
|
|
||||||
public static StringBuilder AppendTabs(this StringBuilder builder, int count)
|
|
||||||
=> builder.Append(new string('\t', count));
|
|
||||||
|
|
||||||
public static string GetBaseTypeSyntaxName(this BaseTypeSyntax baseClassSyntax)
|
|
||||||
{
|
|
||||||
if (baseClassSyntax is PrimaryConstructorBaseTypeSyntax parimaryConstructor)
|
|
||||||
return parimaryConstructor.Type.ToString();
|
|
||||||
|
|
||||||
if (baseClassSyntax is SimpleBaseTypeSyntax simpleBaseType)
|
|
||||||
return simpleBaseType.Type.ToString();
|
|
||||||
|
|
||||||
throw new BaseClassTypeNotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsAssignableFrom(this ITypeSymbol? symbol, string className)
|
|
||||||
{
|
|
||||||
if (symbol is null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (symbol.BaseType == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (symbol.BaseType.Name == className)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return symbol.BaseType.IsAssignableFrom(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITypeSymbol? Cast(this ITypeSymbol symbol, string className)
|
|
||||||
{
|
|
||||||
if (symbol.BaseType == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (symbol.BaseType.Name == className)
|
|
||||||
return symbol.BaseType;
|
|
||||||
|
|
||||||
return symbol.BaseType.Cast(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<TResult> WhereCast<TResult>(this IEnumerable source)
|
|
||||||
{
|
|
||||||
foreach (object value in source)
|
|
||||||
{
|
|
||||||
if (value is TResult result)
|
|
||||||
yield return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CompilationUnitSyntax FindCompilationUnitSyntax(this SyntaxNode syntax)
|
|
||||||
{
|
|
||||||
while (syntax is not CompilationUnitSyntax)
|
|
||||||
syntax = syntax.Parent ?? throw new Exception();
|
|
||||||
|
|
||||||
return (CompilationUnitSyntax)syntax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<TSource> IntersectBy<TSource, TValue>(this IEnumerable<TSource> first, IEnumerable<TValue> second, Func<TSource, TValue> selector)
|
|
||||||
{
|
|
||||||
foreach (TSource item in first)
|
|
||||||
{
|
|
||||||
TValue value = selector(item);
|
|
||||||
if (second.Contains(value))
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IList<TValue> UnionAdd<TValue>(this IList<TValue> source, IEnumerable<TValue> toUnion)
|
|
||||||
{
|
|
||||||
foreach (TValue toUnionValue in toUnion)
|
|
||||||
{
|
|
||||||
if (!source.Contains(toUnionValue, EqualityComparer<TValue>.Default))
|
|
||||||
source.Add(toUnionValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Telegrator.Generators
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Exception thrown when a target is not found during code generation.
|
|
||||||
/// </summary>
|
|
||||||
internal class TargteterNotFoundException() : Exception() { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Exception thrown when a base class type is not found during code generation.
|
|
||||||
/// </summary>
|
|
||||||
internal class BaseClassTypeNotFoundException() : Exception() { }
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
|
||||||
<Configurations>Debug;Release;AnalyzersDebug</Configurations>
|
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
|
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using Microsoft.CodeAnalysis;
|
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
||||||
|
|
||||||
namespace Telegrator.Generators
|
|
||||||
{
|
|
||||||
internal static partial class TypeExtensions
|
|
||||||
{
|
|
||||||
public static INamedTypeSymbol TryGetNamedType(this BaseTypeDeclarationSyntax syntax, Compilation compilation)
|
|
||||||
{
|
|
||||||
SemanticModel semanticModel = compilation.GetSemanticModel(syntax.SyntaxTree);
|
|
||||||
return semanticModel.GetDeclaredSymbol(syntax)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetBaseTypeSyntaxName(this BaseTypeSyntax baseClassSyntax)
|
|
||||||
{
|
|
||||||
if (baseClassSyntax is PrimaryConstructorBaseTypeSyntax parimaryConstructor)
|
|
||||||
return parimaryConstructor.Type.ToString();
|
|
||||||
|
|
||||||
if (baseClassSyntax is SimpleBaseTypeSyntax simpleBaseType)
|
|
||||||
return simpleBaseType.Type.ToString();
|
|
||||||
|
|
||||||
throw new BaseClassTypeNotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsAssignableFrom(this ITypeSymbol symbol, string className)
|
|
||||||
{
|
|
||||||
if (symbol.BaseType == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (symbol.BaseType.Name == className)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return symbol.BaseType.IsAssignableFrom(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITypeSymbol? Cast(this ITypeSymbol symbol, string className)
|
|
||||||
{
|
|
||||||
if (symbol.BaseType == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (symbol.BaseType.Name == className)
|
|
||||||
return symbol.BaseType;
|
|
||||||
|
|
||||||
return symbol.BaseType.Cast(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CompilationUnitSyntax FindCompilationUnitSyntax(this SyntaxNode syntax)
|
|
||||||
{
|
|
||||||
while (syntax is not CompilationUnitSyntax)
|
|
||||||
syntax = syntax.Parent ?? throw new Exception();
|
|
||||||
|
|
||||||
return (CompilationUnitSyntax)syntax;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IList<TValue> UnionAdd<TValue>(this IList<TValue> source, IEnumerable<TValue> toUnion)
|
|
||||||
{
|
|
||||||
foreach (TValue toUnionValue in toUnion)
|
|
||||||
{
|
|
||||||
if (!source.Contains(toUnionValue, EqualityComparer<TValue>.Default))
|
|
||||||
source.Add(toUnionValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,18 +4,18 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<PackageProjectUrl></PackageProjectUrl>
|
<PackageProjectUrl></PackageProjectUrl>
|
||||||
<Title>Telegrator : Telegram.Bot mediator framework</Title>
|
<Title>Telegrator : Telegram.Bot mediator framework</Title>
|
||||||
<PackageIcon>telegrator_nuget.png</PackageIcon>
|
<PackageIcon>telegrator_nuget.png</PackageIcon>
|
||||||
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
||||||
<PackageTags>telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers</PackageTags>
|
<PackageTags>telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers</PackageTags>
|
||||||
<EnableNETAnalyzers>True</EnableNETAnalyzers>
|
<EnableNETAnalyzers>True</EnableNETAnalyzers>
|
||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Version>1.14.0</Version>
|
<Version>1.15.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Version>1.14.0</Version>
|
<Version>1.15.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Configurations>Debug;Release</Configurations>
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
+16
-8
@@ -9,8 +9,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Hosting", "Teleg
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Tests", "Telegrator.Tests\Telegrator.Tests.csproj", "{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Tests", "Telegrator.Tests\Telegrator.Tests.csproj", "{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Generators", "Telegrator.Generators\Telegrator.Generators.csproj", "{43927959-EB6D-4CBA-A652-2B7FC0C1DDA7}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36D591C7-65C7-A0D1-1CBC-10CDE441BDC8}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36D591C7-65C7-A0D1-1CBC-10CDE441BDC8}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
@@ -20,6 +18,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Analyzers", "Tel
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Hosting.Web", "Telegrator.Hosting.Web\Telegrator.Hosting.Web.csproj", "{98AB490F-6A36-CCFF-F6E6-B029D1665965}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.Hosting.Web", "Telegrator.Hosting.Web\Telegrator.Hosting.Web.csproj", "{98AB490F-6A36-CCFF-F6E6-B029D1665965}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.RoslynGenerators", "dev\Telegrator.RoslynGenerators\Telegrator.RoslynGenerators.csproj", "{93658B7F-C651-4C78-2CB1-2C0AE00C45B5}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegrator.RoslynExtensions", "dev\Telegrator.RoslynExtensions\Telegrator.RoslynExtensions.csproj", "{1E6980BE-32C1-A994-C329-B7C473411C87}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
AnalyzersDebug|Any CPU = AnalyzersDebug|Any CPU
|
AnalyzersDebug|Any CPU = AnalyzersDebug|Any CPU
|
||||||
@@ -45,12 +47,6 @@ Global
|
|||||||
{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}.Release|Any CPU.Build.0 = Release|Any CPU
|
{0926C71D-FE0C-4963-B08B-1CBAFF1E3276}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{43927959-EB6D-4CBA-A652-2B7FC0C1DDA7}.AnalyzersDebug|Any CPU.ActiveCfg = AnalyzersDebug|Any CPU
|
|
||||||
{43927959-EB6D-4CBA-A652-2B7FC0C1DDA7}.AnalyzersDebug|Any CPU.Build.0 = AnalyzersDebug|Any CPU
|
|
||||||
{43927959-EB6D-4CBA-A652-2B7FC0C1DDA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{43927959-EB6D-4CBA-A652-2B7FC0C1DDA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{43927959-EB6D-4CBA-A652-2B7FC0C1DDA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{43927959-EB6D-4CBA-A652-2B7FC0C1DDA7}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{8B6A32EA-ECF7-4CAB-A1E5-2392063C986D}.AnalyzersDebug|Any CPU.ActiveCfg = Release|Any CPU
|
{8B6A32EA-ECF7-4CAB-A1E5-2392063C986D}.AnalyzersDebug|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{8B6A32EA-ECF7-4CAB-A1E5-2392063C986D}.AnalyzersDebug|Any CPU.Build.0 = Release|Any CPU
|
{8B6A32EA-ECF7-4CAB-A1E5-2392063C986D}.AnalyzersDebug|Any CPU.Build.0 = Release|Any CPU
|
||||||
{8B6A32EA-ECF7-4CAB-A1E5-2392063C986D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{8B6A32EA-ECF7-4CAB-A1E5-2392063C986D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
@@ -63,6 +59,18 @@ Global
|
|||||||
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.Build.0 = Release|Any CPU
|
{98AB490F-6A36-CCFF-F6E6-B029D1665965}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{93658B7F-C651-4C78-2CB1-2C0AE00C45B5}.AnalyzersDebug|Any CPU.ActiveCfg = AnalyzersDebug|Any CPU
|
||||||
|
{93658B7F-C651-4C78-2CB1-2C0AE00C45B5}.AnalyzersDebug|Any CPU.Build.0 = AnalyzersDebug|Any CPU
|
||||||
|
{93658B7F-C651-4C78-2CB1-2C0AE00C45B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{93658B7F-C651-4C78-2CB1-2C0AE00C45B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{93658B7F-C651-4C78-2CB1-2C0AE00C45B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{93658B7F-C651-4C78-2CB1-2C0AE00C45B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1E6980BE-32C1-A994-C329-B7C473411C87}.AnalyzersDebug|Any CPU.ActiveCfg = AnalyzersDebug|Any CPU
|
||||||
|
{1E6980BE-32C1-A994-C329-B7C473411C87}.AnalyzersDebug|Any CPU.Build.0 = AnalyzersDebug|Any CPU
|
||||||
|
{1E6980BE-32C1-A994-C329-B7C473411C87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1E6980BE-32C1-A994-C329-B7C473411C87}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1E6980BE-32C1-A994-C329-B7C473411C87}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1E6980BE-32C1-A994-C329-B7C473411C87}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
using Telegram.Bot.Types;
|
||||||
|
using Telegram.Bot.Types.ReplyMarkups;
|
||||||
|
|
||||||
|
namespace Telegrator.Markups
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithCallbackData(string, string)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class CallbackButtonAttribute(string name, string data) : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public string Data { get; } = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithCallbackGame(string)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class GameButtonAttribute(string name, string data) : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public string Game { get; } = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithCopyText(string, CopyTextButton)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class CopyTextButtonAttribute(string name, CopyTextButton copyText) : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public CopyTextButton CopyText { get; } = copyText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithPay(string)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class PayRequestButtonAttribute(string name) : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithLoginUrl(string, LoginUrl)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class LoginButtonAttribute(string name, LoginUrl url) : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public LoginUrl Url { get; } = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithUrl(string, string)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class UrlRedirectButtonAttribute(string name, string url) : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public string Url { get; } = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithWebApp(string, WebAppInfo)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class WebAppButtonAttribute(string name, WebAppInfo webApp) : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public WebAppInfo AppInfo { get; } = webApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithSwitchInlineQuery(string, string)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class SwitchQueryButtonAttribute(string name, string switchInlineQuery = "") : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public string Query { get; } = switchInlineQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(string, string)"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public sealed class QueryCurrentButtonAttribute(string name, string switchInlineQueryCurrentChat = "") : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; } = name;
|
||||||
|
public string Query { get; } = switchInlineQueryCurrentChat;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Telegrator.Markups
|
||||||
|
{
|
||||||
|
internal class GeneratedReplyKeybooardMarkupAttributes
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,46 +5,37 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Configurations>Debug;Release</Configurations>
|
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<PackageProjectUrl></PackageProjectUrl>
|
|
||||||
<Title>Telegrator : Telegram.Bot mediator framework</Title>
|
|
||||||
<PackageIcon>telegrator_nuget.png</PackageIcon>
|
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
|
||||||
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
|
||||||
<PackageTags>telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers</PackageTags>
|
|
||||||
<EnableNETAnalyzers>True</EnableNETAnalyzers>
|
<EnableNETAnalyzers>True</EnableNETAnalyzers>
|
||||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||||
|
|
||||||
|
<Title>Telegrator : Telegram.Bot mediator framework</Title>
|
||||||
|
<PackageIcon>telegrator_nuget.png</PackageIcon>
|
||||||
|
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
||||||
|
<PackageTags>telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers</PackageTags>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
<Version>1.14.0</Version>
|
<Version>1.15.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\LICENSE">
|
<None Include="..\LICENSE" Pack="True" PackagePath="\" />
|
||||||
<Pack>True</Pack>
|
<None Include="..\README.md" Pack="True" PackagePath="\" />
|
||||||
<PackagePath>\</PackagePath>
|
<None Include="..\resources\telegrator_nuget.png" Pack="True" PackagePath="\" />
|
||||||
</None>
|
|
||||||
<None Include="..\README.md">
|
|
||||||
<Pack>True</Pack>
|
|
||||||
<PackagePath>\</PackagePath>
|
|
||||||
</None>
|
|
||||||
<None Include="..\resources\telegrator_nuget.png">
|
|
||||||
<Pack>True</Pack>
|
|
||||||
<PackagePath>\</PackagePath>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Telegram.Bot" Version="22.5.1" />
|
<PackageReference Include="Telegram.Bot" Version="22.5.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\Telegrator.Analyzers\bin\$(Configuration)\netstandard2.0\Telegrator.Analyzers.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
<None Include="..\Telegrator.Analyzers\bin\$(Configuration)\netstandard2.0\Telegrator.Analyzers.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Telegrator.Generators\Telegrator.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
<ProjectReference Include="..\dev\Telegrator.RoslynGenerators\Telegrator.RoslynGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
namespace Telegrator.RoslynExtensions
|
||||||
|
{
|
||||||
|
public static class CollectionsExtensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<TSource> Combine<TSource>(params IEnumerable<TSource>[] collections)
|
||||||
|
=> collections.SelectMany(x => x);
|
||||||
|
|
||||||
|
public static IEnumerable<TSource> IntersectBy<TSource, TValue>(this IEnumerable<TSource> first, IEnumerable<TValue> second, Func<TSource, TValue> selector)
|
||||||
|
{
|
||||||
|
foreach (TSource item in first)
|
||||||
|
{
|
||||||
|
TValue value = selector(item);
|
||||||
|
if (second.Contains(value))
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IList<TValue> UnionAdd<TValue>(this IList<TValue> source, IEnumerable<TValue> toUnion)
|
||||||
|
{
|
||||||
|
foreach (TValue toUnionValue in toUnion)
|
||||||
|
{
|
||||||
|
if (!source.Contains(toUnionValue, EqualityComparer<TValue>.Default))
|
||||||
|
source.Add(toUnionValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnionAdd<TSource>(this ICollection<TSource> collection, IEnumerable<TSource> target)
|
||||||
|
{
|
||||||
|
foreach (TSource item in target)
|
||||||
|
{
|
||||||
|
if (!collection.Contains(item))
|
||||||
|
collection.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnionAdd<TSource>(this SortedList<TSource, TSource> collection, IEnumerable<TSource> target)
|
||||||
|
{
|
||||||
|
foreach (TSource item in target)
|
||||||
|
{
|
||||||
|
if (!collection.Values.Contains(item))
|
||||||
|
collection.Add(item, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
foreach (T item in source)
|
||||||
|
{
|
||||||
|
if (predicate.Invoke(item))
|
||||||
|
return index;
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<T> Repeat<T>(this T item, int times)
|
||||||
|
=> Enumerable.Range(0, times - 1).Select(_ => item);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Telegrator.RoslynExtensions
|
||||||
|
{
|
||||||
|
public static class DiagnosticsHelper
|
||||||
|
{
|
||||||
|
public static Diagnostic Create(this DiagnosticDescriptor descriptor, Location? location, params object[] messageArgs)
|
||||||
|
=> Diagnostic.Create(descriptor, location, messageArgs);
|
||||||
|
|
||||||
|
public static void Report(this Diagnostic diagnostic, SourceProductionContext context)
|
||||||
|
=> context.ReportDiagnostic(diagnostic);
|
||||||
|
|
||||||
|
public static void Report(this DiagnosticDescriptor descriptor, SourceProductionContext context, Location? location, params object[] messageArgs)
|
||||||
|
=> descriptor.Create(location, messageArgs).Report(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Telegrator.RoslynExtensions;
|
||||||
|
|
||||||
|
public class TargteterNotFoundException() : Exception() { }
|
||||||
|
|
||||||
|
public class BaseClassTypeNotFoundException() : Exception() { }
|
||||||
|
|
||||||
|
public class AncestorNotFoundException : Exception { }
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
|
||||||
|
namespace Telegrator.RoslynExtensions
|
||||||
|
{
|
||||||
|
public static class MemberDeclarationSyntaxExtensions
|
||||||
|
{
|
||||||
|
private static SyntaxTrivia TabulationTrivia => SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, "\t");
|
||||||
|
private static SyntaxTrivia WhitespaceTrivia => SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " ");
|
||||||
|
private static SyntaxTrivia NewLineTrivia => SyntaxFactory.SyntaxTrivia(SyntaxKind.EndOfLineTrivia, "\n");
|
||||||
|
private static SyntaxToken Semicolon => SyntaxFactory.Token(SyntaxKind.SemicolonToken);
|
||||||
|
|
||||||
|
public static SyntaxTokenList Decorate(this SyntaxTokenList tokens)
|
||||||
|
=> new SyntaxTokenList(tokens.Select(token => token.WithoutTrivia().WithTrailingTrivia(WhitespaceTrivia)).ToArray());
|
||||||
|
|
||||||
|
public static T DecorateMember<T>(this T typeDeclaration, int times = 1) where T : MemberDeclarationSyntax => typeDeclaration
|
||||||
|
.WithoutTrivia().WithLeadingTrivia(TabulationTrivia.Repeat(times)).WithTrailingTrivia(NewLineTrivia);
|
||||||
|
|
||||||
|
public static NamespaceDeclarationSyntax Decorate(this NamespaceDeclarationSyntax namespaceDeclaration) => namespaceDeclaration
|
||||||
|
.WithName(namespaceDeclaration.Name.WithoutTrivia().WithLeadingTrivia(WhitespaceTrivia))
|
||||||
|
.WithOpenBraceToken(SyntaxFactory.Token(SyntaxKind.OpenBraceToken).WithLeadingTrivia(NewLineTrivia).WithTrailingTrivia(NewLineTrivia))
|
||||||
|
.WithCloseBraceToken(SyntaxFactory.Token(SyntaxKind.CloseBraceToken));
|
||||||
|
|
||||||
|
public static T Decorate<T>(this T typeDeclaration, int times = 1) where T : TypeDeclarationSyntax => (T)typeDeclaration
|
||||||
|
.WithoutTrivia().WithLeadingTrivia(TabulationTrivia.Repeat(times))
|
||||||
|
.WithIdentifier(typeDeclaration.Identifier.WithoutTrivia().WithLeadingTrivia(WhitespaceTrivia).WithTrailingTrivia(NewLineTrivia))
|
||||||
|
.WithOpenBraceToken(SyntaxFactory.Token(SyntaxKind.OpenBraceToken).WithLeadingTrivia(TabulationTrivia.Repeat(times)).WithTrailingTrivia(NewLineTrivia))
|
||||||
|
.WithCloseBraceToken(SyntaxFactory.Token(SyntaxKind.CloseBraceToken).WithLeadingTrivia(TabulationTrivia.Repeat(times)).WithTrailingTrivia(NewLineTrivia));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Telegrator.RoslynExtensions
|
||||||
|
{
|
||||||
|
public static class StringBuilderExtensions
|
||||||
|
{
|
||||||
|
public static StringBuilder AppendTabs(this StringBuilder builder, int count)
|
||||||
|
=> builder.Append(new string('\t', count));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
namespace Telegrator.RoslynExtensions
|
||||||
|
{
|
||||||
|
public static class StringExtensions
|
||||||
|
{
|
||||||
|
public static string FirstLetterToUpper(this string target)
|
||||||
|
{
|
||||||
|
char[] chars = target.ToCharArray();
|
||||||
|
int index = chars.IndexOf(char.IsLetter);
|
||||||
|
chars[index] = char.ToUpper(chars[index]);
|
||||||
|
return new string(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FirstLetterToLower(this string target)
|
||||||
|
{
|
||||||
|
char[] chars = target.ToCharArray();
|
||||||
|
int index = chars.IndexOf(char.IsLetter);
|
||||||
|
chars[index] = char.ToLower(chars[index]);
|
||||||
|
return new string(chars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Telegrator.RoslynExtensions;
|
||||||
|
|
||||||
|
public static class SymbolsExtensions
|
||||||
|
{
|
||||||
|
public static bool IsAssignableFrom(this ITypeSymbol symbol, string className)
|
||||||
|
{
|
||||||
|
if (symbol.BaseType == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (symbol.BaseType.Name == className)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return symbol.BaseType.IsAssignableFrom(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ITypeSymbol? Cast(this ITypeSymbol symbol, string className)
|
||||||
|
{
|
||||||
|
if (symbol.BaseType == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (symbol.BaseType.Name == className)
|
||||||
|
return symbol.BaseType;
|
||||||
|
|
||||||
|
return symbol.BaseType.Cast(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
|
||||||
|
namespace Telegrator.RoslynExtensions
|
||||||
|
{
|
||||||
|
public static class SyntaxNodesExtensions
|
||||||
|
{
|
||||||
|
public static T FindAncestor<T>(this SyntaxNode node) where T : SyntaxNode
|
||||||
|
{
|
||||||
|
if (node.Parent == null)
|
||||||
|
throw new AncestorNotFoundException();
|
||||||
|
|
||||||
|
if (node.Parent is T found)
|
||||||
|
return found;
|
||||||
|
|
||||||
|
return node.Parent.FindAncestor<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryFindAncestor<T>(this SyntaxNode node, out T syntax) where T : SyntaxNode
|
||||||
|
{
|
||||||
|
if (node.Parent == null)
|
||||||
|
{
|
||||||
|
syntax = null!;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.Parent is T found)
|
||||||
|
{
|
||||||
|
syntax = found;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.Parent.TryFindAncestor(out syntax);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static INamedTypeSymbol TryGetNamedType(this BaseTypeDeclarationSyntax syntax, Compilation compilation)
|
||||||
|
{
|
||||||
|
SemanticModel semanticModel = compilation.GetSemanticModel(syntax.SyntaxTree);
|
||||||
|
return semanticModel.GetDeclaredSymbol(syntax)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetBaseTypeSyntaxName(this BaseTypeSyntax baseClassSyntax)
|
||||||
|
{
|
||||||
|
if (baseClassSyntax is PrimaryConstructorBaseTypeSyntax parimaryConstructor)
|
||||||
|
return parimaryConstructor.Type.ToString();
|
||||||
|
|
||||||
|
if (baseClassSyntax is SimpleBaseTypeSyntax simpleBaseType)
|
||||||
|
return simpleBaseType.Type.ToString();
|
||||||
|
|
||||||
|
throw new BaseClassTypeNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int CountParentTree(this SyntaxNode node)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
SyntaxNode inspectNode = node;
|
||||||
|
|
||||||
|
while (inspectNode.Parent != null)
|
||||||
|
{
|
||||||
|
inspectNode = inspectNode.Parent;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SeparatedSyntaxList<TNode> ToSeparatedSyntaxList<TNode>(this IEnumerable<TNode> elements) where TNode : SyntaxNode
|
||||||
|
=> new SeparatedSyntaxList<TNode>().AddRange(elements);
|
||||||
|
|
||||||
|
public static SyntaxList<TNode> ToSyntaxList<TNode>(this IEnumerable<TNode> elements) where TNode : SyntaxNode
|
||||||
|
=> new SyntaxList<TNode>().AddRange(elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Telegrator.RoslynExtensions
|
||||||
|
{
|
||||||
|
public static class SyntaxTokenExtensions
|
||||||
|
{
|
||||||
|
public static bool HasModifiers(this SyntaxTokenList modifiers, params string[] expected)
|
||||||
|
{
|
||||||
|
return modifiers.Count(mod => expected.Contains(mod.ToString())) == expected.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<IncludeBuildOutput>False</IncludeBuildOutput>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
|
||||||
|
|
||||||
|
<PackageReference Include="PolySharp" Version="1.15.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+2
-2
@@ -3,9 +3,9 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Telegrator.RoslynExtensions;
|
||||||
|
|
||||||
#pragma warning disable CS0162
|
namespace Telegrator.RoslynGenerators
|
||||||
namespace Telegrator.Generators
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Source Generator для автоматической генерации Markdown-документации по публичному API Telegrator.
|
/// Source Generator для автоматической генерации Markdown-документации по публичному API Telegrator.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// This file is used by Code Analysis to maintain SuppressMessage
|
||||||
|
// attributes that are applied to this project.
|
||||||
|
// Project-level suppressions either have no target or are given
|
||||||
|
// a specific target and scoped to a namespace, type, member, etc.
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
[assembly: SuppressMessage("Style", "IDE0090")]
|
||||||
+4
-7
@@ -2,19 +2,16 @@
|
|||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Telegrator.RoslynExtensions;
|
||||||
|
|
||||||
namespace Telegrator.Generators
|
namespace Telegrator.RoslynGenerators
|
||||||
{
|
{
|
||||||
[Generator(LanguageNames.CSharp)]
|
[Generator(LanguageNames.CSharp)]
|
||||||
public class ImplicitHandlerBuilderExtensionsGenerator : IIncrementalGenerator
|
public class ImplicitHandlerBuilderExtensionsGenerator : IIncrementalGenerator
|
||||||
{
|
{
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
#if ANALYZERSDEBUG
|
|
||||||
Debugger.Launch();
|
|
||||||
#endif
|
|
||||||
IncrementalValueProvider<ImmutableArray<ClassDeclarationSyntax>> pipeline = context.SyntaxProvider
|
IncrementalValueProvider<ImmutableArray<ClassDeclarationSyntax>> pipeline = context.SyntaxProvider
|
||||||
.CreateSyntaxProvider(SyntaxPredicate, SyntaxTransform)
|
.CreateSyntaxProvider(SyntaxPredicate, SyntaxTransform)
|
||||||
.Where(declaration => declaration != null)
|
.Where(declaration => declaration != null)
|
||||||
@@ -68,7 +65,7 @@ namespace Telegrator.Generators
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
usingDirectives.UnionAdd(classDeclaration.FindCompilationUnitSyntax().Usings.Select(use => use.ToString()));
|
usingDirectives.UnionAdd(classDeclaration.FindAncestor<CompilationUnitSyntax>().Usings.Select(use => use.ToString()));
|
||||||
ParseClassDeclaration(sourceBuilder, classDeclaration, targeters);
|
ParseClassDeclaration(sourceBuilder, classDeclaration, targeters);
|
||||||
}
|
}
|
||||||
catch (TargteterNotFoundException)
|
catch (TargteterNotFoundException)
|
||||||
@@ -86,7 +83,7 @@ namespace Telegrator.Generators
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
usingDirectives.UnionAdd(classDeclaration.FindCompilationUnitSyntax().Usings.Select(use => use.ToString()));
|
usingDirectives.UnionAdd(classDeclaration.FindAncestor<CompilationUnitSyntax>().Usings.Select(use => use.ToString()));
|
||||||
ParseClassDeclaration(sourceBuilder, classDeclaration, targeters);
|
ParseClassDeclaration(sourceBuilder, classDeclaration, targeters);
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
|
<IsRoslynComponent>True</IsRoslynComponent>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Telegrator.RoslynExtensions\Telegrator.RoslynExtensions.csproj" PrivateAssets="all" />
|
||||||
|
<None Include="$(OutputPath)\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user