diff --git a/dotnet/src/AutoGen.Mistral/DTOs/Error.cs b/dotnet/src/AutoGen.Mistral/DTOs/Error.cs
index 8bddcfc776c6..79a2c2e2f662 100644
--- a/dotnet/src/AutoGen.Mistral/DTOs/Error.cs
+++ b/dotnet/src/AutoGen.Mistral/DTOs/Error.cs
@@ -3,37 +3,36 @@
using System.Text.Json.Serialization;
-namespace AutoGen.Mistral
+namespace AutoGen.Mistral;
+
+public class Error
{
- public class Error
+ public Error(string type, string message, string? param = default(string), string? code = default(string))
{
- public Error(string type, string message, string? param = default(string), string? code = default(string))
- {
- Type = type;
- Message = message;
- Param = param;
- Code = code;
- }
+ Type = type;
+ Message = message;
+ Param = param;
+ Code = code;
+ }
- [JsonPropertyName("type")]
- public string Type { get; set; }
+ [JsonPropertyName("type")]
+ public string Type { get; set; }
- ///
- /// Gets or Sets Message
- ///
- [JsonPropertyName("message")]
- public string Message { get; set; }
+ ///
+ /// Gets or Sets Message
+ ///
+ [JsonPropertyName("message")]
+ public string Message { get; set; }
- ///
- /// Gets or Sets Param
- ///
- [JsonPropertyName("param")]
- public string? Param { get; set; }
+ ///
+ /// Gets or Sets Param
+ ///
+ [JsonPropertyName("param")]
+ public string? Param { get; set; }
- ///
- /// Gets or Sets Code
- ///
- [JsonPropertyName("code")]
- public string? Code { get; set; }
- }
+ ///
+ /// Gets or Sets Code
+ ///
+ [JsonPropertyName("code")]
+ public string? Code { get; set; }
}
diff --git a/dotnet/src/AutoGen.SourceGenerator/DocumentCommentExtension.cs b/dotnet/src/AutoGen.SourceGenerator/DocumentCommentExtension.cs
index 0892d597a7bb..14db58a4b540 100644
--- a/dotnet/src/AutoGen.SourceGenerator/DocumentCommentExtension.cs
+++ b/dotnet/src/AutoGen.SourceGenerator/DocumentCommentExtension.cs
@@ -10,286 +10,285 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
// copyright: https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/StyleCop.Analyzers/StyleCop.Analyzers/Helpers/DocumentationCommentExtensions.cs#L17
-namespace AutoGen.SourceGenerator
+namespace AutoGen.SourceGenerator;
+
+internal static class DocumentCommentExtension
{
- internal static class DocumentCommentExtension
+ public static bool IsMissingOrDefault(this SyntaxToken token)
+ {
+ return token.IsKind(SyntaxKind.None)
+ || token.IsMissing;
+ }
+
+ public static string? GetParameterDescriptionFromDocumentationCommentTriviaSyntax(this DocumentationCommentTriviaSyntax documentationCommentTrivia, string parameterName)
{
- public static bool IsMissingOrDefault(this SyntaxToken token)
+ var parameterElements = documentationCommentTrivia.Content.GetXmlElements("param");
+
+ var parameter = parameterElements.FirstOrDefault(element =>
{
- return token.IsKind(SyntaxKind.None)
- || token.IsMissing;
- }
+ var xml = XElement.Parse(element.ToString());
+ var nameAttribute = xml.Attribute("name");
+ return nameAttribute != null && nameAttribute.Value == parameterName;
+ });
- public static string? GetParameterDescriptionFromDocumentationCommentTriviaSyntax(this DocumentationCommentTriviaSyntax documentationCommentTrivia, string parameterName)
+ if (parameter is not null)
{
- var parameterElements = documentationCommentTrivia.Content.GetXmlElements("param");
+ var xml = XElement.Parse(parameter.ToString());
- var parameter = parameterElements.FirstOrDefault(element =>
- {
- var xml = XElement.Parse(element.ToString());
- var nameAttribute = xml.Attribute("name");
- return nameAttribute != null && nameAttribute.Value == parameterName;
- });
+ return xml.Nodes().OfType().FirstOrDefault()?.Value;
+ }
- if (parameter is not null)
- {
- var xml = XElement.Parse(parameter.ToString());
+ return null;
+ }
- return xml.Nodes().OfType().FirstOrDefault()?.Value;
- }
+ public static string? GetNamespaceNameFromClassDeclarationSyntax(this ClassDeclarationSyntax classDeclaration)
+ {
+ return classDeclaration.Parent is NamespaceDeclarationSyntax namespaceDeclarationSyntax ? namespaceDeclarationSyntax.Name.ToString()
+ : classDeclaration.Parent is FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax ? fileScopedNamespaceDeclarationSyntax.Name.ToString()
+ : null;
+ }
+ public static DocumentationCommentTriviaSyntax? GetDocumentationCommentTriviaSyntax(this SyntaxNode node)
+ {
+ if (node == null)
+ {
return null;
}
- public static string? GetNamespaceNameFromClassDeclarationSyntax(this ClassDeclarationSyntax classDeclaration)
+ foreach (var leadingTrivia in node.GetLeadingTrivia())
{
- return classDeclaration.Parent is NamespaceDeclarationSyntax namespaceDeclarationSyntax ? namespaceDeclarationSyntax.Name.ToString()
- : classDeclaration.Parent is FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax ? fileScopedNamespaceDeclarationSyntax.Name.ToString()
- : null;
+ if (leadingTrivia.GetStructure() is DocumentationCommentTriviaSyntax structure)
+ {
+ return structure;
+ }
}
- public static DocumentationCommentTriviaSyntax? GetDocumentationCommentTriviaSyntax(this SyntaxNode node)
+ return null;
+ }
+
+ public static XmlNodeSyntax GetFirstXmlElement(this SyntaxList content, string elementName)
+ {
+ return content.GetXmlElements(elementName).FirstOrDefault();
+ }
+
+ public static IEnumerable GetXmlElements(this SyntaxList content, string elementName)
+ {
+ foreach (XmlNodeSyntax syntax in content)
{
- if (node == null)
+ if (syntax is XmlEmptyElementSyntax emptyElement)
{
- return null;
+ if (string.Equals(elementName, emptyElement.Name.ToString(), StringComparison.Ordinal))
+ {
+ yield return emptyElement;
+ }
+
+ continue;
}
- foreach (var leadingTrivia in node.GetLeadingTrivia())
+ if (syntax is XmlElementSyntax elementSyntax)
{
- if (leadingTrivia.GetStructure() is DocumentationCommentTriviaSyntax structure)
+ if (string.Equals(elementName, elementSyntax.StartTag?.Name?.ToString(), StringComparison.Ordinal))
{
- return structure;
+ yield return elementSyntax;
}
- }
- return null;
+ continue;
+ }
}
+ }
+
+ public static T ReplaceExteriorTrivia(this T node, SyntaxTrivia trivia)
+ where T : XmlNodeSyntax
+ {
+ // Make sure to include a space after the '///' characters.
+ SyntaxTrivia triviaWithSpace = SyntaxFactory.DocumentationCommentExterior(trivia.ToString() + " ");
+
+ return node.ReplaceTrivia(
+ node.DescendantTrivia(descendIntoTrivia: true).Where(i => i.IsKind(SyntaxKind.DocumentationCommentExteriorTrivia)),
+ (originalTrivia, rewrittenTrivia) => SelectExteriorTrivia(rewrittenTrivia, trivia, triviaWithSpace));
+ }
- public static XmlNodeSyntax GetFirstXmlElement(this SyntaxList content, string elementName)
+ public static SyntaxList WithoutFirstAndLastNewlines(this SyntaxList summaryContent)
+ {
+ if (summaryContent.Count == 0)
{
- return content.GetXmlElements(elementName).FirstOrDefault();
+ return summaryContent;
}
- public static IEnumerable GetXmlElements(this SyntaxList content, string elementName)
+ if (!(summaryContent[0] is XmlTextSyntax firstSyntax))
{
- foreach (XmlNodeSyntax syntax in content)
- {
- if (syntax is XmlEmptyElementSyntax emptyElement)
- {
- if (string.Equals(elementName, emptyElement.Name.ToString(), StringComparison.Ordinal))
- {
- yield return emptyElement;
- }
-
- continue;
- }
-
- if (syntax is XmlElementSyntax elementSyntax)
- {
- if (string.Equals(elementName, elementSyntax.StartTag?.Name?.ToString(), StringComparison.Ordinal))
- {
- yield return elementSyntax;
- }
-
- continue;
- }
- }
+ return summaryContent;
}
- public static T ReplaceExteriorTrivia(this T node, SyntaxTrivia trivia)
- where T : XmlNodeSyntax
+ if (!(summaryContent[summaryContent.Count - 1] is XmlTextSyntax lastSyntax))
{
- // Make sure to include a space after the '///' characters.
- SyntaxTrivia triviaWithSpace = SyntaxFactory.DocumentationCommentExterior(trivia.ToString() + " ");
-
- return node.ReplaceTrivia(
- node.DescendantTrivia(descendIntoTrivia: true).Where(i => i.IsKind(SyntaxKind.DocumentationCommentExteriorTrivia)),
- (originalTrivia, rewrittenTrivia) => SelectExteriorTrivia(rewrittenTrivia, trivia, triviaWithSpace));
+ return summaryContent;
}
- public static SyntaxList WithoutFirstAndLastNewlines(this SyntaxList summaryContent)
+ SyntaxTokenList firstSyntaxTokens = firstSyntax.TextTokens;
+
+ int removeFromStart;
+ if (IsXmlNewLine(firstSyntaxTokens[0]))
+ {
+ removeFromStart = 1;
+ }
+ else
{
- if (summaryContent.Count == 0)
+ if (!IsXmlWhitespace(firstSyntaxTokens[0]))
{
return summaryContent;
}
- if (!(summaryContent[0] is XmlTextSyntax firstSyntax))
+ if (!IsXmlNewLine(firstSyntaxTokens[1]))
{
return summaryContent;
}
- if (!(summaryContent[summaryContent.Count - 1] is XmlTextSyntax lastSyntax))
- {
- return summaryContent;
- }
+ removeFromStart = 2;
+ }
- SyntaxTokenList firstSyntaxTokens = firstSyntax.TextTokens;
+ SyntaxTokenList lastSyntaxTokens = lastSyntax.TextTokens;
- int removeFromStart;
- if (IsXmlNewLine(firstSyntaxTokens[0]))
- {
- removeFromStart = 1;
- }
- else
+ int removeFromEnd;
+ if (IsXmlNewLine(lastSyntaxTokens[lastSyntaxTokens.Count - 1]))
+ {
+ removeFromEnd = 1;
+ }
+ else
+ {
+ if (!IsXmlWhitespace(lastSyntaxTokens[lastSyntaxTokens.Count - 1]))
{
- if (!IsXmlWhitespace(firstSyntaxTokens[0]))
- {
- return summaryContent;
- }
-
- if (!IsXmlNewLine(firstSyntaxTokens[1]))
- {
- return summaryContent;
- }
-
- removeFromStart = 2;
+ return summaryContent;
}
- SyntaxTokenList lastSyntaxTokens = lastSyntax.TextTokens;
-
- int removeFromEnd;
- if (IsXmlNewLine(lastSyntaxTokens[lastSyntaxTokens.Count - 1]))
+ if (!IsXmlNewLine(lastSyntaxTokens[lastSyntaxTokens.Count - 2]))
{
- removeFromEnd = 1;
+ return summaryContent;
}
- else
- {
- if (!IsXmlWhitespace(lastSyntaxTokens[lastSyntaxTokens.Count - 1]))
- {
- return summaryContent;
- }
- if (!IsXmlNewLine(lastSyntaxTokens[lastSyntaxTokens.Count - 2]))
- {
- return summaryContent;
- }
+ removeFromEnd = 2;
+ }
- removeFromEnd = 2;
- }
+ for (int i = 0; i < removeFromStart; i++)
+ {
+ firstSyntaxTokens = firstSyntaxTokens.RemoveAt(0);
+ }
- for (int i = 0; i < removeFromStart; i++)
- {
- firstSyntaxTokens = firstSyntaxTokens.RemoveAt(0);
- }
+ if (firstSyntax == lastSyntax)
+ {
+ lastSyntaxTokens = firstSyntaxTokens;
+ }
- if (firstSyntax == lastSyntax)
+ for (int i = 0; i < removeFromEnd; i++)
+ {
+ if (!lastSyntaxTokens.Any())
{
- lastSyntaxTokens = firstSyntaxTokens;
+ break;
}
- for (int i = 0; i < removeFromEnd; i++)
- {
- if (!lastSyntaxTokens.Any())
- {
- break;
- }
+ lastSyntaxTokens = lastSyntaxTokens.RemoveAt(lastSyntaxTokens.Count - 1);
+ }
- lastSyntaxTokens = lastSyntaxTokens.RemoveAt(lastSyntaxTokens.Count - 1);
- }
+ summaryContent = summaryContent.RemoveAt(summaryContent.Count - 1);
+ if (lastSyntaxTokens.Count != 0)
+ {
+ summaryContent = summaryContent.Add(lastSyntax.WithTextTokens(lastSyntaxTokens));
+ }
- summaryContent = summaryContent.RemoveAt(summaryContent.Count - 1);
- if (lastSyntaxTokens.Count != 0)
+ if (firstSyntax != lastSyntax)
+ {
+ summaryContent = summaryContent.RemoveAt(0);
+ if (firstSyntaxTokens.Count != 0)
{
- summaryContent = summaryContent.Add(lastSyntax.WithTextTokens(lastSyntaxTokens));
+ summaryContent = summaryContent.Insert(0, firstSyntax.WithTextTokens(firstSyntaxTokens));
}
+ }
- if (firstSyntax != lastSyntax)
- {
- summaryContent = summaryContent.RemoveAt(0);
- if (firstSyntaxTokens.Count != 0)
- {
- summaryContent = summaryContent.Insert(0, firstSyntax.WithTextTokens(firstSyntaxTokens));
- }
- }
+ if (summaryContent.Count > 0)
+ {
+ // Make sure to remove the leading trivia
+ summaryContent = summaryContent.Replace(summaryContent[0], summaryContent[0].WithLeadingTrivia());
- if (summaryContent.Count > 0)
+ // Remove leading spaces (between the start tag and the start of the paragraph content)
+ if (summaryContent[0] is XmlTextSyntax firstTextSyntax && firstTextSyntax.TextTokens.Count > 0)
{
- // Make sure to remove the leading trivia
- summaryContent = summaryContent.Replace(summaryContent[0], summaryContent[0].WithLeadingTrivia());
-
- // Remove leading spaces (between the start tag and the start of the paragraph content)
- if (summaryContent[0] is XmlTextSyntax firstTextSyntax && firstTextSyntax.TextTokens.Count > 0)
+ SyntaxToken firstTextToken = firstTextSyntax.TextTokens[0];
+ string firstTokenText = firstTextToken.Text;
+ string trimmed = firstTokenText.TrimStart();
+ if (trimmed != firstTokenText)
{
- SyntaxToken firstTextToken = firstTextSyntax.TextTokens[0];
- string firstTokenText = firstTextToken.Text;
- string trimmed = firstTokenText.TrimStart();
- if (trimmed != firstTokenText)
- {
- SyntaxToken newFirstToken = SyntaxFactory.Token(
- firstTextToken.LeadingTrivia,
- firstTextToken.Kind(),
- trimmed,
- firstTextToken.ValueText.TrimStart(),
- firstTextToken.TrailingTrivia);
-
- summaryContent = summaryContent.Replace(firstTextSyntax, firstTextSyntax.ReplaceToken(firstTextToken, newFirstToken));
- }
+ SyntaxToken newFirstToken = SyntaxFactory.Token(
+ firstTextToken.LeadingTrivia,
+ firstTextToken.Kind(),
+ trimmed,
+ firstTextToken.ValueText.TrimStart(),
+ firstTextToken.TrailingTrivia);
+
+ summaryContent = summaryContent.Replace(firstTextSyntax, firstTextSyntax.ReplaceToken(firstTextToken, newFirstToken));
}
}
-
- return summaryContent;
}
- public static bool IsXmlNewLine(this SyntaxToken node)
- {
- return node.IsKind(SyntaxKind.XmlTextLiteralNewLineToken);
- }
+ return summaryContent;
+ }
+
+ public static bool IsXmlNewLine(this SyntaxToken node)
+ {
+ return node.IsKind(SyntaxKind.XmlTextLiteralNewLineToken);
+ }
+
+ public static bool IsXmlWhitespace(this SyntaxToken node)
+ {
+ return node.IsKind(SyntaxKind.XmlTextLiteralToken)
+ && string.IsNullOrWhiteSpace(node.Text);
+ }
- public static bool IsXmlWhitespace(this SyntaxToken node)
+ ///
+ /// Adjust the leading and trailing trivia associated with
+ /// tokens to ensure the formatter properly indents the exterior trivia.
+ ///
+ /// The type of syntax node.
+ /// The syntax node to adjust tokens.
+ /// A equivalent to the input , adjusted by moving any
+ /// trailing trivia from tokens to be leading trivia of the
+ /// following token.
+ public static T AdjustDocumentationCommentNewLineTrivia(this T node)
+ where T : SyntaxNode
+ {
+ var tokensForAdjustment =
+ from token in node.DescendantTokens()
+ where token.IsKind(SyntaxKind.XmlTextLiteralNewLineToken)
+ where token.HasTrailingTrivia
+ let next = token.GetNextToken(includeZeroWidth: true, includeSkipped: true, includeDirectives: true, includeDocumentationComments: true)
+ where !next.IsMissingOrDefault()
+ select new KeyValuePair(token, next);
+
+ Dictionary replacements = new Dictionary();
+ foreach (var pair in tokensForAdjustment)
{
- return node.IsKind(SyntaxKind.XmlTextLiteralToken)
- && string.IsNullOrWhiteSpace(node.Text);
+ replacements[pair.Key] = pair.Key.WithTrailingTrivia();
+ replacements[pair.Value] = pair.Value.WithLeadingTrivia(pair.Value.LeadingTrivia.InsertRange(0, pair.Key.TrailingTrivia));
}
- ///
- /// Adjust the leading and trailing trivia associated with
- /// tokens to ensure the formatter properly indents the exterior trivia.
- ///
- /// The type of syntax node.
- /// The syntax node to adjust tokens.
- /// A equivalent to the input , adjusted by moving any
- /// trailing trivia from tokens to be leading trivia of the
- /// following token.
- public static T AdjustDocumentationCommentNewLineTrivia(this T node)
- where T : SyntaxNode
- {
- var tokensForAdjustment =
- from token in node.DescendantTokens()
- where token.IsKind(SyntaxKind.XmlTextLiteralNewLineToken)
- where token.HasTrailingTrivia
- let next = token.GetNextToken(includeZeroWidth: true, includeSkipped: true, includeDirectives: true, includeDocumentationComments: true)
- where !next.IsMissingOrDefault()
- select new KeyValuePair(token, next);
-
- Dictionary replacements = new Dictionary();
- foreach (var pair in tokensForAdjustment)
- {
- replacements[pair.Key] = pair.Key.WithTrailingTrivia();
- replacements[pair.Value] = pair.Value.WithLeadingTrivia(pair.Value.LeadingTrivia.InsertRange(0, pair.Key.TrailingTrivia));
- }
+ return node.ReplaceTokens(replacements.Keys, (originalToken, rewrittenToken) => replacements[originalToken]);
+ }
- return node.ReplaceTokens(replacements.Keys, (originalToken, rewrittenToken) => replacements[originalToken]);
- }
+ public static XmlNameSyntax? GetName(this XmlNodeSyntax element)
+ {
+ return (element as XmlElementSyntax)?.StartTag?.Name
+ ?? (element as XmlEmptyElementSyntax)?.Name;
+ }
- public static XmlNameSyntax? GetName(this XmlNodeSyntax element)
+ private static SyntaxTrivia SelectExteriorTrivia(SyntaxTrivia rewrittenTrivia, SyntaxTrivia trivia, SyntaxTrivia triviaWithSpace)
+ {
+ // if the trivia had a trailing space, make sure to preserve it
+ if (rewrittenTrivia.ToString().EndsWith(" "))
{
- return (element as XmlElementSyntax)?.StartTag?.Name
- ?? (element as XmlEmptyElementSyntax)?.Name;
+ return triviaWithSpace;
}
- private static SyntaxTrivia SelectExteriorTrivia(SyntaxTrivia rewrittenTrivia, SyntaxTrivia trivia, SyntaxTrivia triviaWithSpace)
- {
- // if the trivia had a trailing space, make sure to preserve it
- if (rewrittenTrivia.ToString().EndsWith(" "))
- {
- return triviaWithSpace;
- }
-
- // otherwise the space is part of the leading trivia of the following token, so don't add an extra one to
- // the exterior trivia
- return trivia;
- }
+ // otherwise the space is part of the leading trivia of the following token, so don't add an extra one to
+ // the exterior trivia
+ return trivia;
}
}
diff --git a/dotnet/src/AutoGen.SourceGenerator/FunctionCallGenerator.cs b/dotnet/src/AutoGen.SourceGenerator/FunctionCallGenerator.cs
index 4fa6169f7c3c..d5813682030e 100644
--- a/dotnet/src/AutoGen.SourceGenerator/FunctionCallGenerator.cs
+++ b/dotnet/src/AutoGen.SourceGenerator/FunctionCallGenerator.cs
@@ -12,236 +12,235 @@
using Microsoft.CodeAnalysis.Text;
using Newtonsoft.Json;
-namespace AutoGen.SourceGenerator
+namespace AutoGen.SourceGenerator;
+
+[Generator]
+public partial class FunctionCallGenerator : IIncrementalGenerator
{
- [Generator]
- public partial class FunctionCallGenerator : IIncrementalGenerator
- {
- private const string FUNCTION_CALL_ATTRIBUTION = "AutoGen.Core.FunctionAttribute";
+ private const string FUNCTION_CALL_ATTRIBUTION = "AutoGen.Core.FunctionAttribute";
- public void Initialize(IncrementalGeneratorInitializationContext context)
- {
+ public void Initialize(IncrementalGeneratorInitializationContext context)
+ {
#if LAUNCH_DEBUGGER
- if (!System.Diagnostics.Debugger.IsAttached)
- {
- System.Diagnostics.Debugger.Launch();
- }
+ if (!System.Diagnostics.Debugger.IsAttached)
+ {
+ System.Diagnostics.Debugger.Launch();
+ }
#endif
- var optionProvider = context.AnalyzerConfigOptionsProvider.Select((provider, ct) =>
+ var optionProvider = context.AnalyzerConfigOptionsProvider.Select((provider, ct) =>
+ {
+ var generateFunctionDefinitionContract = provider.GlobalOptions.TryGetValue("build_property.EnableContract", out var value) && value?.ToLowerInvariant() == "true";
+
+ return generateFunctionDefinitionContract;
+ });
+ // step 1
+ // filter syntax tree and search syntax node that satisfied the following conditions
+ // - is partial class
+ var partialClassSyntaxProvider = context.SyntaxProvider.CreateSyntaxProvider(
+ (node, ct) =>
+ {
+ return node is ClassDeclarationSyntax classDeclarationSyntax && classDeclarationSyntax.Modifiers.Any(SyntaxKind.PartialKeyword);
+ },
+ (ctx, ct) =>
{
- var generateFunctionDefinitionContract = provider.GlobalOptions.TryGetValue("build_property.EnableContract", out var value) && value?.ToLowerInvariant() == "true";
+ // first check if any method of the class has FunctionAttribution attribute
+ // if not, then return null
+ var filePath = ctx.Node.SyntaxTree.FilePath;
+ var fileName = Path.GetFileNameWithoutExtension(filePath);
+
+ var classDeclarationSyntax = ctx.Node as ClassDeclarationSyntax;
+ var nameSpace = classDeclarationSyntax?.Parent as NamespaceDeclarationSyntax;
+ var fullClassName = $"{nameSpace?.Name}.{classDeclarationSyntax!.Identifier}";
+ if (classDeclarationSyntax == null)
+ {
+ return null;
+ }
- return generateFunctionDefinitionContract;
- });
- // step 1
- // filter syntax tree and search syntax node that satisfied the following conditions
- // - is partial class
- var partialClassSyntaxProvider = context.SyntaxProvider.CreateSyntaxProvider(
- (node, ct) =>
+ if (!classDeclarationSyntax.Members.Any(member => member.AttributeLists.Any(attributeList => attributeList.Attributes.Any(attribute =>
{
- return node is ClassDeclarationSyntax classDeclarationSyntax && classDeclarationSyntax.Modifiers.Any(SyntaxKind.PartialKeyword);
- },
- (ctx, ct) =>
+ return ctx.SemanticModel.GetSymbolInfo(attribute).Symbol is IMethodSymbol methodSymbol && methodSymbol.ContainingType.ToDisplayString() == FUNCTION_CALL_ATTRIBUTION;
+ }))))
{
- // first check if any method of the class has FunctionAttribution attribute
- // if not, then return null
- var filePath = ctx.Node.SyntaxTree.FilePath;
- var fileName = Path.GetFileNameWithoutExtension(filePath);
-
- var classDeclarationSyntax = ctx.Node as ClassDeclarationSyntax;
- var nameSpace = classDeclarationSyntax?.Parent as NamespaceDeclarationSyntax;
- var fullClassName = $"{nameSpace?.Name}.{classDeclarationSyntax!.Identifier}";
- if (classDeclarationSyntax == null)
- {
- return null;
- }
-
- if (!classDeclarationSyntax.Members.Any(member => member.AttributeLists.Any(attributeList => attributeList.Attributes.Any(attribute =>
- {
- return ctx.SemanticModel.GetSymbolInfo(attribute).Symbol is IMethodSymbol methodSymbol && methodSymbol.ContainingType.ToDisplayString() == FUNCTION_CALL_ATTRIBUTION;
- }))))
- {
- return null;
- }
+ return null;
+ }
- // collect methods that has FunctionAttribution attribute
- var methodDeclarationSyntaxes = classDeclarationSyntax.Members.Where(member => member.AttributeLists.Any(attributeList => attributeList.Attributes.Any(attribute =>
- {
- return ctx.SemanticModel.GetSymbolInfo(attribute).Symbol is IMethodSymbol methodSymbol && methodSymbol.ContainingType.ToDisplayString() == FUNCTION_CALL_ATTRIBUTION;
- })))
- .Select(member => member as MethodDeclarationSyntax)
- .Where(method => method != null);
-
- var className = classDeclarationSyntax.Identifier.ToString();
- var namespaceName = classDeclarationSyntax.GetNamespaceNameFromClassDeclarationSyntax();
- var functionContracts = methodDeclarationSyntaxes.Select(method => CreateFunctionContract(method!, className, namespaceName));
-
- return new PartialClassOutput(fullClassName, classDeclarationSyntax, functionContracts);
- })
- .Where(node => node != null)
- .Collect();
-
- var aggregateProvider = optionProvider.Combine(partialClassSyntaxProvider);
- // step 2
- context.RegisterSourceOutput(aggregateProvider,
- (ctx, source) =>
+ // collect methods that has FunctionAttribution attribute
+ var methodDeclarationSyntaxes = classDeclarationSyntax.Members.Where(member => member.AttributeLists.Any(attributeList => attributeList.Attributes.Any(attribute =>
{
- var groups = source.Right.GroupBy(item => item!.FullClassName);
- foreach (var group in groups)
+ return ctx.SemanticModel.GetSymbolInfo(attribute).Symbol is IMethodSymbol methodSymbol && methodSymbol.ContainingType.ToDisplayString() == FUNCTION_CALL_ATTRIBUTION;
+ })))
+ .Select(member => member as MethodDeclarationSyntax)
+ .Where(method => method != null);
+
+ var className = classDeclarationSyntax.Identifier.ToString();
+ var namespaceName = classDeclarationSyntax.GetNamespaceNameFromClassDeclarationSyntax();
+ var functionContracts = methodDeclarationSyntaxes.Select(method => CreateFunctionContract(method!, className, namespaceName));
+
+ return new PartialClassOutput(fullClassName, classDeclarationSyntax, functionContracts);
+ })
+ .Where(node => node != null)
+ .Collect();
+
+ var aggregateProvider = optionProvider.Combine(partialClassSyntaxProvider);
+ // step 2
+ context.RegisterSourceOutput(aggregateProvider,
+ (ctx, source) =>
+ {
+ var groups = source.Right.GroupBy(item => item!.FullClassName);
+ foreach (var group in groups)
+ {
+ var functionContracts = group.SelectMany(item => item!.FunctionContracts).ToArray();
+ var className = group.First()!.ClassDeclarationSyntax.Identifier.ToString();
+ var namespaceName = group.First()!.ClassDeclarationSyntax.GetNamespaceNameFromClassDeclarationSyntax() ?? string.Empty;
+ var functionTT = new FunctionCallTemplate
{
- var functionContracts = group.SelectMany(item => item!.FunctionContracts).ToArray();
- var className = group.First()!.ClassDeclarationSyntax.Identifier.ToString();
- var namespaceName = group.First()!.ClassDeclarationSyntax.GetNamespaceNameFromClassDeclarationSyntax() ?? string.Empty;
- var functionTT = new FunctionCallTemplate
- {
- NameSpace = namespaceName,
- ClassName = className,
- FunctionContracts = functionContracts.ToArray(),
- };
+ NameSpace = namespaceName,
+ ClassName = className,
+ FunctionContracts = functionContracts.ToArray(),
+ };
- var functionSource = functionTT.TransformText();
- var fileName = $"{className}.generated.cs";
+ var functionSource = functionTT.TransformText();
+ var fileName = $"{className}.generated.cs";
- ctx.AddSource(fileName, SourceText.From(functionSource, System.Text.Encoding.UTF8));
- File.WriteAllText(Path.Combine(Path.GetTempPath(), fileName), functionSource);
- }
+ ctx.AddSource(fileName, SourceText.From(functionSource, System.Text.Encoding.UTF8));
+ File.WriteAllText(Path.Combine(Path.GetTempPath(), fileName), functionSource);
+ }
- if (source.Left)
- {
- var overallFunctionDefinition = source.Right.SelectMany(x => x!.FunctionContracts.Select(y => new { fullClassName = x.FullClassName, y = y }));
- var overallFunctionDefinitionObject = overallFunctionDefinition.Select(
- x => new
+ if (source.Left)
+ {
+ var overallFunctionDefinition = source.Right.SelectMany(x => x!.FunctionContracts.Select(y => new { fullClassName = x.FullClassName, y = y }));
+ var overallFunctionDefinitionObject = overallFunctionDefinition.Select(
+ x => new
+ {
+ fullClassName = x.fullClassName,
+ functionDefinition = new
{
- fullClassName = x.fullClassName,
- functionDefinition = new
+ x.y.Name,
+ x.y.Description,
+ x.y.ReturnType,
+ Parameters = x.y.Parameters.Select(y => new
{
- x.y.Name,
- x.y.Description,
- x.y.ReturnType,
- Parameters = x.y.Parameters.Select(y => new
- {
- y.Name,
- y.Description,
- y.JsonType,
- y.JsonItemType,
- y.Type,
- y.IsOptional,
- y.DefaultValue,
- }),
- },
- });
-
- var json = JsonConvert.SerializeObject(overallFunctionDefinitionObject, formatting: Formatting.Indented);
- // wrap json inside csharp block, as SG doesn't support generating non-source file
- json = $@"/* wrap json inside csharp block, as SG doesn't support generating non-source file
+ y.Name,
+ y.Description,
+ y.JsonType,
+ y.JsonItemType,
+ y.Type,
+ y.IsOptional,
+ y.DefaultValue,
+ }),
+ },
+ });
+
+ var json = JsonConvert.SerializeObject(overallFunctionDefinitionObject, formatting: Formatting.Indented);
+ // wrap json inside csharp block, as SG doesn't support generating non-source file
+ json = $@"/* wrap json inside csharp block, as SG doesn't support generating non-source file
{json}
*/";
- ctx.AddSource("FunctionDefinition.json", SourceText.From(json, System.Text.Encoding.UTF8));
- }
- });
- }
+ ctx.AddSource("FunctionDefinition.json", SourceText.From(json, System.Text.Encoding.UTF8));
+ }
+ });
+ }
- private class PartialClassOutput
+ private class PartialClassOutput
+ {
+ public PartialClassOutput(string fullClassName, ClassDeclarationSyntax classDeclarationSyntax, IEnumerable functionContracts)
{
- public PartialClassOutput(string fullClassName, ClassDeclarationSyntax classDeclarationSyntax, IEnumerable functionContracts)
- {
- FullClassName = fullClassName;
- ClassDeclarationSyntax = classDeclarationSyntax;
- FunctionContracts = functionContracts;
- }
+ FullClassName = fullClassName;
+ ClassDeclarationSyntax = classDeclarationSyntax;
+ FunctionContracts = functionContracts;
+ }
- public string FullClassName { get; }
+ public string FullClassName { get; }
- public ClassDeclarationSyntax ClassDeclarationSyntax { get; }
+ public ClassDeclarationSyntax ClassDeclarationSyntax { get; }
- public IEnumerable FunctionContracts { get; }
- }
+ public IEnumerable FunctionContracts { get; }
+ }
- private SourceGeneratorFunctionContract CreateFunctionContract(MethodDeclarationSyntax method, string? className, string? namespaceName)
- {
- // get function_call attribute
- var functionCallAttribute = method.AttributeLists.SelectMany(attributeList => attributeList.Attributes)
- .FirstOrDefault(attribute => attribute.Name.ToString() == FUNCTION_CALL_ATTRIBUTION);
- // get document string if exist
- var documentationCommentTrivia = method.GetDocumentationCommentTriviaSyntax();
+ private SourceGeneratorFunctionContract CreateFunctionContract(MethodDeclarationSyntax method, string? className, string? namespaceName)
+ {
+ // get function_call attribute
+ var functionCallAttribute = method.AttributeLists.SelectMany(attributeList => attributeList.Attributes)
+ .FirstOrDefault(attribute => attribute.Name.ToString() == FUNCTION_CALL_ATTRIBUTION);
+ // get document string if exist
+ var documentationCommentTrivia = method.GetDocumentationCommentTriviaSyntax();
- var functionName = method.Identifier.ToString();
- var functionDescription = functionCallAttribute?.ArgumentList?.Arguments.FirstOrDefault(argument => argument.NameEquals?.Name.ToString() == "Description")?.Expression.ToString() ?? string.Empty;
+ var functionName = method.Identifier.ToString();
+ var functionDescription = functionCallAttribute?.ArgumentList?.Arguments.FirstOrDefault(argument => argument.NameEquals?.Name.ToString() == "Description")?.Expression.ToString() ?? string.Empty;
- if (string.IsNullOrEmpty(functionDescription))
+ if (string.IsNullOrEmpty(functionDescription))
+ {
+ // if functionDescription is empty, then try to get it from documentationCommentTrivia
+ // firstly, try getting from tag
+ var summary = documentationCommentTrivia?.Content.GetFirstXmlElement("summary");
+ if (summary is not null && XElement.Parse(summary.ToString()) is XElement element)
{
- // if functionDescription is empty, then try to get it from documentationCommentTrivia
- // firstly, try getting from tag
- var summary = documentationCommentTrivia?.Content.GetFirstXmlElement("summary");
- if (summary is not null && XElement.Parse(summary.ToString()) is XElement element)
- {
- functionDescription = element.Nodes().OfType().FirstOrDefault()?.Value;
-
- // remove [space...][//|///][space...] from functionDescription
- // replace [^\S\r\n]+[\/]+\s* with empty string
- functionDescription = System.Text.RegularExpressions.Regex.Replace(functionDescription, @"[^\S\r\n]+\/[\/]+\s*", string.Empty);
- }
- else
- {
- // if tag is not exist, then simply use the entire leading trivia as functionDescription
- functionDescription = method.GetLeadingTrivia().ToString();
+ functionDescription = element.Nodes().OfType().FirstOrDefault()?.Value;
- // remove [space...][//|///][space...] from functionDescription
- // replace [^\S\r\n]+[\/]+\s* with empty string
- functionDescription = System.Text.RegularExpressions.Regex.Replace(functionDescription, @"[^\S\r\n]+\/[\/]+\s*", string.Empty);
- }
+ // remove [space...][//|///][space...] from functionDescription
+ // replace [^\S\r\n]+[\/]+\s* with empty string
+ functionDescription = System.Text.RegularExpressions.Regex.Replace(functionDescription, @"[^\S\r\n]+\/[\/]+\s*", string.Empty);
}
-
- // get parameters
- var parameters = method.ParameterList.Parameters.Select(parameter =>
+ else
{
- var description = $"{parameter.Identifier}. type is {parameter.Type}";
+ // if tag is not exist, then simply use the entire leading trivia as functionDescription
+ functionDescription = method.GetLeadingTrivia().ToString();
- // try to get parameter description from documentationCommentTrivia
- var parameterDocumentationComment = documentationCommentTrivia?.GetParameterDescriptionFromDocumentationCommentTriviaSyntax(parameter.Identifier.ToString());
- if (parameterDocumentationComment is not null)
- {
- description = parameterDocumentationComment.ToString();
- // remove [space...][//|///][space...] from functionDescription
- // replace [^\S\r\n]+[\/]+\s* with empty string
- description = System.Text.RegularExpressions.Regex.Replace(description, @"[^\S\r\n]+\/[\/]+\s*", string.Empty);
- }
- var jsonItemType = parameter.Type!.ToString().EndsWith("[]") ? parameter.Type!.ToString().Substring(0, parameter.Type!.ToString().Length - 2) : null;
- return new SourceGeneratorParameterContract
- {
- Name = parameter.Identifier.ToString(),
- JsonType = parameter.Type!.ToString() switch
- {
- "string" => "string",
- "string[]" => "array",
- "System.Int32" or "int" => "integer",
- "System.Int64" or "long" => "integer",
- "System.Single" or "float" => "number",
- "System.Double" or "double" => "number",
- "System.Boolean" or "bool" => "boolean",
- "System.DateTime" => "string",
- "System.Guid" => "string",
- "System.Object" => "object",
- _ => "object",
- },
- JsonItemType = jsonItemType,
- Type = parameter.Type!.ToString(),
- Description = description,
- IsOptional = parameter.Default != null,
- // if Default is null or "null", then DefaultValue is null
- DefaultValue = parameter.Default?.ToString() == "null" ? null : parameter.Default?.Value.ToString(),
- };
- });
+ // remove [space...][//|///][space...] from functionDescription
+ // replace [^\S\r\n]+[\/]+\s* with empty string
+ functionDescription = System.Text.RegularExpressions.Regex.Replace(functionDescription, @"[^\S\r\n]+\/[\/]+\s*", string.Empty);
+ }
+ }
+
+ // get parameters
+ var parameters = method.ParameterList.Parameters.Select(parameter =>
+ {
+ var description = $"{parameter.Identifier}. type is {parameter.Type}";
- return new SourceGeneratorFunctionContract
+ // try to get parameter description from documentationCommentTrivia
+ var parameterDocumentationComment = documentationCommentTrivia?.GetParameterDescriptionFromDocumentationCommentTriviaSyntax(parameter.Identifier.ToString());
+ if (parameterDocumentationComment is not null)
{
- ClassName = className,
- Namespace = namespaceName,
- Name = functionName,
- Description = functionDescription?.Trim() ?? functionName,
- Parameters = parameters.ToArray(),
- ReturnType = method.ReturnType.ToString(),
+ description = parameterDocumentationComment.ToString();
+ // remove [space...][//|///][space...] from functionDescription
+ // replace [^\S\r\n]+[\/]+\s* with empty string
+ description = System.Text.RegularExpressions.Regex.Replace(description, @"[^\S\r\n]+\/[\/]+\s*", string.Empty);
+ }
+ var jsonItemType = parameter.Type!.ToString().EndsWith("[]") ? parameter.Type!.ToString().Substring(0, parameter.Type!.ToString().Length - 2) : null;
+ return new SourceGeneratorParameterContract
+ {
+ Name = parameter.Identifier.ToString(),
+ JsonType = parameter.Type!.ToString() switch
+ {
+ "string" => "string",
+ "string[]" => "array",
+ "System.Int32" or "int" => "integer",
+ "System.Int64" or "long" => "integer",
+ "System.Single" or "float" => "number",
+ "System.Double" or "double" => "number",
+ "System.Boolean" or "bool" => "boolean",
+ "System.DateTime" => "string",
+ "System.Guid" => "string",
+ "System.Object" => "object",
+ _ => "object",
+ },
+ JsonItemType = jsonItemType,
+ Type = parameter.Type!.ToString(),
+ Description = description,
+ IsOptional = parameter.Default != null,
+ // if Default is null or "null", then DefaultValue is null
+ DefaultValue = parameter.Default?.ToString() == "null" ? null : parameter.Default?.Value.ToString(),
};
- }
+ });
+
+ return new SourceGeneratorFunctionContract
+ {
+ ClassName = className,
+ Namespace = namespaceName,
+ Name = functionName,
+ Description = functionDescription?.Trim() ?? functionName,
+ Parameters = parameters.ToArray(),
+ ReturnType = method.ReturnType.ToString(),
+ };
}
}