* Added ReplyKeyboardMarkupGenerator

* Added set of markup attributes dedicatedf to map a keyboard using partial methods
This commit is contained in:
2025-08-16 13:13:34 +04:00
parent cdd03a3e0e
commit cf598ea91e
32 changed files with 829 additions and 284 deletions
@@ -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,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")]
@@ -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>