* remove merging primitive from .editorconfig and gitignore * use file scope namespace * remove file-scope name * fix formattags/v0.4.0.dev0
| @@ -1,5 +1,4 @@ | |||
| <<<<<<< HEAD | |||
| # EditorConfig is awesome:http://EditorConfig.org | |||
| # EditorConfig is awesome:http://EditorConfig.org | |||
| # top-most EditorConfig file | |||
| root = true | |||
| @@ -93,7 +92,6 @@ csharp_style_inlined_variable_declaration = true:error | |||
| csharp_style_throw_expression = true:suggestion | |||
| csharp_style_conditional_delegate_call = true:suggestion | |||
| csharp_style_deconstructed_variable_declaration = true:suggestion | |||
| ======= | |||
| ; EditorConfig to support per-solution formatting. | |||
| ; Use the EditorConfig VS add-in to make this work. | |||
| ; http://editorconfig.org/ | |||
| @@ -137,7 +135,6 @@ csharp_style_var_elsewhere = true:suggestion | |||
| # Disallow throw expressions. | |||
| csharp_style_throw_expression = false:suggestion | |||
| >>>>>>> agnext_main | |||
| # Newline settings | |||
| csharp_new_line_before_open_brace = all | |||
| @@ -146,7 +143,6 @@ csharp_new_line_before_catch = true | |||
| csharp_new_line_before_finally = true | |||
| csharp_new_line_before_members_in_object_initializers = true | |||
| csharp_new_line_before_members_in_anonymous_types = true | |||
| <<<<<<< HEAD | |||
| csharp_new_line_between_query_expression_clauses = true | |||
| # Identation options | |||
| @@ -236,7 +232,6 @@ dotnet_diagnostic.CA2016.severity = suggestion | |||
| # disable check for generated code | |||
| [*.generated.cs] | |||
| generated_code = true | |||
| ======= | |||
| # Namespace settings | |||
| csharp_style_namespace_declarations = file_scoped:silent | |||
| @@ -708,4 +703,3 @@ generated_code = true | |||
| # IDE1591 Missing XML comment for publicly visible type or member | |||
| dotnet_diagnostic.CS1591.severity = none | |||
| >>>>>>> agnext_main | |||
| @@ -1,6 +1,4 @@ | |||
| <<<<<<< HEAD | |||
| # gitignore file for C#/VS | |||
| ======= | |||
| ## Ignore Visual Studio temporary files, build results, and | |||
| ## files generated by popular Visual Studio add-ons. | |||
| ## | |||
| @@ -20,7 +18,6 @@ | |||
| mono_crash.* | |||
| output | |||
| >>>>>>> agnext_main | |||
| # Build results | |||
| [Dd]ebug/ | |||
| @@ -29,7 +26,6 @@ output | |||
| [Rr]eleases/ | |||
| x64/ | |||
| x86/ | |||
| <<<<<<< HEAD | |||
| build/ | |||
| bld/ | |||
| [Bb]in/ | |||
| @@ -51,7 +47,6 @@ output/ | |||
| # JetBrains Rider | |||
| .idea/ | |||
| ======= | |||
| [Ww][Ii][Nn]32/ | |||
| [Aa][Rr][Mm]/ | |||
| [Aa][Rr][Mm]64/ | |||
| @@ -525,4 +520,3 @@ sk-azfunc-server/local.settings.json | |||
| temp | |||
| .mono/** | |||
| **/values.xml | |||
| >>>>>>> agnext_main | |||
| @@ -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; } | |||
| /// <summary> | |||
| /// Gets or Sets Message | |||
| /// </summary> | |||
| [JsonPropertyName("message")] | |||
| public string Message { get; set; } | |||
| /// <summary> | |||
| /// Gets or Sets Message | |||
| /// </summary> | |||
| [JsonPropertyName("message")] | |||
| public string Message { get; set; } | |||
| /// <summary> | |||
| /// Gets or Sets Param | |||
| /// </summary> | |||
| [JsonPropertyName("param")] | |||
| public string? Param { get; set; } | |||
| /// <summary> | |||
| /// Gets or Sets Param | |||
| /// </summary> | |||
| [JsonPropertyName("param")] | |||
| public string? Param { get; set; } | |||
| /// <summary> | |||
| /// Gets or Sets Code | |||
| /// </summary> | |||
| [JsonPropertyName("code")] | |||
| public string? Code { get; set; } | |||
| } | |||
| /// <summary> | |||
| /// Gets or Sets Code | |||
| /// </summary> | |||
| [JsonPropertyName("code")] | |||
| public string? Code { get; set; } | |||
| } | |||
| @@ -10,286 +10,285 @@ using Microsoft.CodeAnalysis.CSharp; | |||
| 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<XText>().FirstOrDefault()?.Value; | |||
| } | |||
| if (parameter is not null) | |||
| { | |||
| var xml = XElement.Parse(parameter.ToString()); | |||
| return null; | |||
| } | |||
| return xml.Nodes().OfType<XText>().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<XmlNodeSyntax> content, string elementName) | |||
| { | |||
| return content.GetXmlElements(elementName).FirstOrDefault(); | |||
| } | |||
| public static IEnumerable<XmlNodeSyntax> GetXmlElements(this SyntaxList<XmlNodeSyntax> 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<T>(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<XmlNodeSyntax> content, string elementName) | |||
| public static SyntaxList<XmlNodeSyntax> WithoutFirstAndLastNewlines(this SyntaxList<XmlNodeSyntax> summaryContent) | |||
| { | |||
| if (summaryContent.Count == 0) | |||
| { | |||
| return content.GetXmlElements(elementName).FirstOrDefault(); | |||
| return summaryContent; | |||
| } | |||
| public static IEnumerable<XmlNodeSyntax> GetXmlElements(this SyntaxList<XmlNodeSyntax> 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<T>(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<XmlNodeSyntax> WithoutFirstAndLastNewlines(this SyntaxList<XmlNodeSyntax> 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 <para> 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 <para> 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) | |||
| /// <summary> | |||
| /// Adjust the leading and trailing trivia associated with <see cref="SyntaxKind.XmlTextLiteralNewLineToken"/> | |||
| /// tokens to ensure the formatter properly indents the exterior trivia. | |||
| /// </summary> | |||
| /// <typeparam name="T">The type of syntax node.</typeparam> | |||
| /// <param name="node">The syntax node to adjust tokens.</param> | |||
| /// <returns>A <see cref="SyntaxNode"/> equivalent to the input <paramref name="node"/>, adjusted by moving any | |||
| /// trailing trivia from <see cref="SyntaxKind.XmlTextLiteralNewLineToken"/> tokens to be leading trivia of the | |||
| /// following token.</returns> | |||
| public static T AdjustDocumentationCommentNewLineTrivia<T>(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<SyntaxToken, SyntaxToken>(token, next); | |||
| Dictionary<SyntaxToken, SyntaxToken> replacements = new Dictionary<SyntaxToken, SyntaxToken>(); | |||
| 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)); | |||
| } | |||
| /// <summary> | |||
| /// Adjust the leading and trailing trivia associated with <see cref="SyntaxKind.XmlTextLiteralNewLineToken"/> | |||
| /// tokens to ensure the formatter properly indents the exterior trivia. | |||
| /// </summary> | |||
| /// <typeparam name="T">The type of syntax node.</typeparam> | |||
| /// <param name="node">The syntax node to adjust tokens.</param> | |||
| /// <returns>A <see cref="SyntaxNode"/> equivalent to the input <paramref name="node"/>, adjusted by moving any | |||
| /// trailing trivia from <see cref="SyntaxKind.XmlTextLiteralNewLineToken"/> tokens to be leading trivia of the | |||
| /// following token.</returns> | |||
| public static T AdjustDocumentationCommentNewLineTrivia<T>(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<SyntaxToken, SyntaxToken>(token, next); | |||
| Dictionary<SyntaxToken, SyntaxToken> replacements = new Dictionary<SyntaxToken, SyntaxToken>(); | |||
| 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; | |||
| } | |||
| } | |||
| @@ -12,236 +12,235 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; | |||
| 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<PartialClassOutput?>( | |||
| (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<PartialClassOutput?>( | |||
| (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 = $@"/* <auto-generated> 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 = $@"/* <auto-generated> wrap json inside csharp block, as SG doesn't support generating non-source file | |||
| {json} | |||
| </auto-generated>*/"; | |||
| 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<SourceGeneratorFunctionContract> functionContracts) | |||
| { | |||
| public PartialClassOutput(string fullClassName, ClassDeclarationSyntax classDeclarationSyntax, IEnumerable<SourceGeneratorFunctionContract> 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<SourceGeneratorFunctionContract> FunctionContracts { get; } | |||
| } | |||
| public IEnumerable<SourceGeneratorFunctionContract> 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 <summary> 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 <summary> tag | |||
| var summary = documentationCommentTrivia?.Content.GetFirstXmlElement("summary"); | |||
| if (summary is not null && XElement.Parse(summary.ToString()) is XElement element) | |||
| { | |||
| functionDescription = element.Nodes().OfType<XText>().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 <summary> tag is not exist, then simply use the entire leading trivia as functionDescription | |||
| functionDescription = method.GetLeadingTrivia().ToString(); | |||
| functionDescription = element.Nodes().OfType<XText>().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 <summary> 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(), | |||
| }; | |||
| } | |||
| } | |||
| @@ -1,40 +1,39 @@ | |||
| // Copyright (c) Microsoft Corporation. All rights reserved. | |||
| // SourceGeneratorFunctionContract.cs | |||
| namespace AutoGen.SourceGenerator | |||
| namespace AutoGen.SourceGenerator; | |||
| internal class SourceGeneratorFunctionContract | |||
| { | |||
| internal class SourceGeneratorFunctionContract | |||
| { | |||
| public string? Namespace { get; set; } | |||
| public string? Namespace { get; set; } | |||
| public string? ClassName { get; set; } | |||
| public string? ClassName { get; set; } | |||
| public string? Name { get; set; } | |||
| public string? Name { get; set; } | |||
| public string? Description { get; set; } | |||
| public string? Description { get; set; } | |||
| public string? ReturnDescription { get; set; } | |||
| public string? ReturnDescription { get; set; } | |||
| public SourceGeneratorParameterContract[]? Parameters { get; set; } | |||
| public SourceGeneratorParameterContract[]? Parameters { get; set; } | |||
| public string? ReturnType { get; set; } | |||
| } | |||
| public string? ReturnType { get; set; } | |||
| } | |||
| internal class SourceGeneratorParameterContract | |||
| { | |||
| public string? Name { get; set; } | |||
| internal class SourceGeneratorParameterContract | |||
| { | |||
| public string? Name { get; set; } | |||
| public string? Description { get; set; } | |||
| public string? Description { get; set; } | |||
| public string? JsonType { get; set; } | |||
| public string? JsonType { get; set; } | |||
| public string? JsonItemType { get; set; } | |||
| public string? JsonItemType { get; set; } | |||
| public string? Type { get; set; } | |||
| public string? Type { get; set; } | |||
| public bool IsOptional { get; set; } | |||
| public bool IsOptional { get; set; } | |||
| public string? DefaultValue { get; set; } | |||
| public string? DefaultValue { get; set; } | |||
| } | |||
| } | |||