Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c6fe04a
the model for the input values of the examples
ArcturusZhang Aug 18, 2023
4238e1c
change the serializedname to be not-null
ArcturusZhang Aug 18, 2023
fab7fb8
protocol method should be good
ArcturusZhang Aug 18, 2023
9ef2711
implement the xml part
ArcturusZhang Aug 18, 2023
f359cd7
convenience method is almost done
ArcturusZhang Aug 18, 2023
8399caa
Merge remote-tracking branch 'origin/feature/v3' into new-refactor-sa…
ArcturusZhang Aug 18, 2023
2c849e4
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Aug 19, 2023
84f6346
fix the convenience sample and introduce the short version and all pa…
ArcturusZhang Aug 21, 2023
76f1848
fix the xml formatter issue
ArcturusZhang Aug 21, 2023
8c38768
fix
ArcturusZhang Aug 19, 2023
ccff33a
fix lro issue
ArcturusZhang Aug 21, 2023
48b66c7
Merge remote-tracking branch 'origin/feature/v3' into new-refactor-sa…
ArcturusZhang Aug 21, 2023
dcb4020
fix an issue when body is optional
ArcturusZhang Aug 21, 2023
691b904
fix another issue
ArcturusZhang Aug 22, 2023
fd461f8
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Aug 22, 2023
89b38a4
fix the endpoint issue
ArcturusZhang Aug 23, 2023
4a1ffa2
handles lro pageable as well
ArcturusZhang Aug 23, 2023
7ccdef4
fix more issues
ArcturusZhang Aug 23, 2023
429d15d
more regen
ArcturusZhang Aug 24, 2023
69ea321
fix another issue in client parameter promotion
ArcturusZhang Aug 24, 2023
1f01d86
met some issues on the serialization format - might need to reconside…
ArcturusZhang Aug 24, 2023
51ee632
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Aug 24, 2023
5e04864
Merge remote-tracking branch 'origin/feature/v3' into new-refactor-sa…
ArcturusZhang Sep 4, 2023
d2f0c88
Merge remote-tracking branch 'origin/feature/v3' into new-refactor-sa…
ArcturusZhang Sep 5, 2023
4cf1620
provided a more reliable way of writing framework types. type provide…
ArcturusZhang Sep 6, 2023
40e4f08
implemented the type provider part
ArcturusZhang Sep 6, 2023
17e96c4
a few refactor
ArcturusZhang Sep 6, 2023
727845f
regenerate everything
ArcturusZhang Sep 6, 2023
706c734
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Sep 6, 2023
66789dd
regenerate lowlevel projects
ArcturusZhang Sep 7, 2023
0197fce
change the implementation type of IList from array to List<T> and reg…
ArcturusZhang Sep 7, 2023
4a01516
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Sep 7, 2023
b38cf96
refactor around the xml writer
ArcturusZhang Sep 7, 2023
b39afd3
fix the issue in agrifood
ArcturusZhang Sep 7, 2023
546a827
solve the cast issue
ArcturusZhang Sep 7, 2023
d92e592
regenerate all projects
ArcturusZhang Sep 7, 2023
87d1355
resolve comments
ArcturusZhang Sep 12, 2023
8560c08
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Sep 12, 2023
902f3f9
regenerate
ArcturusZhang Sep 12, 2023
c47f3e3
use anonymous object syntax when we could, switch to dictionary when …
ArcturusZhang Sep 12, 2023
7ab2efc
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Sep 13, 2023
69df8b5
regenerate
ArcturusZhang Sep 13, 2023
989435f
Merge branch 'feature/v3' into new-refactor-sample-generator
ArcturusZhang Sep 14, 2023
8378c01
a few refactor and clean up
ArcturusZhang Sep 14, 2023
7c9b4af
regenerate
ArcturusZhang Sep 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1,642 changes: 1,032 additions & 610 deletions samples/AnomalyDetector/src/Generated/Docs/AnomalyDetectorClient.xml

Large diffs are not rendered by default.

1,545 changes: 1,013 additions & 532 deletions samples/AnomalyDetector/tests/Generated/Samples/Samples_AnomalyDetectorClient.cs

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ static GeneratedCodeWorkspace()
private static Task<Project>? _cachedProject;

private Project _project;
private Dictionary<string, string> _docFiles { get; init; }
private Dictionary<string, XmlDocumentFile> _xmlDocFiles { get; }

private GeneratedCodeWorkspace(Project generatedCodeProject)
{
_project = generatedCodeProject;
_docFiles = new Dictionary<string, string>();
_xmlDocFiles = new();
}

/// <summary>
Expand All @@ -86,10 +86,10 @@ public void AddGeneratedFile(string name, string text)
/// Add generated doc file.
/// </summary>
/// <param name="name">Name of the doc file, including the relative path to the "Generated" folder.</param>
/// <param name="text">Content of the doc file.</param>
public void AddGeneratedDocFile(string name, string text)
/// <param name="xmlDocument">Content of the doc file.</param>
public void AddGeneratedDocFile(string name, XmlDocumentFile xmlDocument)
{
_docFiles.Add(name, text);
_xmlDocFiles.Add(name, xmlDocument);
}

public async IAsyncEnumerable<(string Name, string Text)> GetGeneratedFilesAsync()
Expand All @@ -110,6 +110,9 @@ public void AddGeneratedDocFile(string name, string text)
documents.Add(Task.Run(() => ProcessDocument(compilation, document, suppressedTypeNames)));
}

var needProcessGeneratedDocs = _xmlDocFiles.Any();
var generatedDocs = new Dictionary<string, SyntaxTree>();

foreach (var task in documents)
{
var processed = await task;
Expand All @@ -118,11 +121,16 @@ public void AddGeneratedDocFile(string name, string text)
processed = await Formatter.FormatAsync(processed);
var text = await processed.GetSyntaxTreeAsync();
yield return (processed.Name, text!.ToString());
if (needProcessGeneratedDocs) // TODO -- this is a workaround. In HLC, in some cases, there are multiple documents with the same name added in this list, and we get "dictionary same key has been added" exception
generatedDocs.Add(processed.Name, text);
}

foreach (var doc in _docFiles)
foreach (var (docName, doc) in _xmlDocFiles)
{
yield return (doc.Key, doc.Value);
var xmlWriter = doc.XmlDocWriter;
var testDocument = generatedDocs[doc.TestFileName];
var content = await XmlFormatter.FormatAsync(xmlWriter, testDocument);
yield return (docName, content);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using AutoRest.CSharp.Generation.Writers;

namespace AutoRest.CSharp.AutoRest.Plugins
{
internal record XmlDocumentFile(string TestFileName, XmlDocWriter XmlDocWriter);
}
167 changes: 167 additions & 0 deletions src/AutoRest.CSharp/Common/AutoRest/Plugins/XmlFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using AutoRest.CSharp.Generation.Writers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace AutoRest.CSharp.AutoRest.Plugins
{
internal class XmlFormatter
{
internal static async Task<string> FormatAsync(XmlDocWriter writer, SyntaxTree syntaxTree)
{
var document = writer.Document;
var methods = await GetMethodsAsync(syntaxTree);
// first we need to get the members
var members = writer.Members;

foreach (var member in members)
{
// get the example element
var exampleElement = member.Element("example");
if (exampleElement == null)
continue;

foreach (var codeElement in exampleElement.Elements("code"))
{
var testMethodName = codeElement.Value;
// find the magic comment and replace it with real code
if (methods.TryGetValue(testMethodName, out var methodDeclaration))
{
var lines = GetLines(methodDeclaration.Body!);
var content = FormatContent(lines);
// this will give you
// <[[CDATA
// var our = code;
// ]]>
codeElement.ReplaceAll(new XCData(content));
}
}
}

var swriter = new XmlStringWriter();
XmlWriterSettings settings = new XmlWriterSettings { OmitXmlDeclaration = false, Indent = true };
using (XmlWriter xw = XmlWriter.Create(swriter, settings))
{
document.Save(xw);
}

return swriter.ToString();
}

private static string[] GetLines(BlockSyntax methodBlock)
{
if (!methodBlock.Statements.Any())
return Array.Empty<string>();

// here we have to get the string of all statements and then split by new lines
// this is because in the StatementSyntax, the NewLines (\n or \r\n) could appear at the end of the statement or at the beginning of the statement
// therefore to keep it simple, we just combine all the text together and then split by the new lines to trim the extra spaces in front of every line
var builder = new StringBuilder();
foreach (var statement in methodBlock.Statements)
{
builder.Append(statement.ToFullString());
}

return builder.ToString().Split(Environment.NewLine);
}

/// <summary>
/// This method trims the leading spaces of the lines, and it also adds proper amount of spaces to the content of spaces because of the bug of Roslyn: https://github.com/dotnet/roslyn/issues/8269
/// </summary>
/// <param name="lines"></param>
/// <returns></returns>
internal static string FormatContent(string[] lines)
{
if (!lines.Any())
return string.Empty;

var builder = new StringBuilder();

// find the first non-empty line
int lineNumber = -1;
for (int i = 0; i < lines.Length; i++)
{
var line = lines[i];
if (!string.IsNullOrWhiteSpace(line))
{
lineNumber = i;
break;
}
if (i > 0)
builder.AppendLine(); // we do not need a new line when it is the first line
builder.Append(line);
}

if (lineNumber < 0)
return string.Empty; // every line is whitespaces

// the following code is a temporarily workaround the Roslyn's format issue around collection initializers: https://github.com/dotnet/roslyn/issues/8269
// if Roslyn could properly format the collection initializers and everything, this code should be as simple as: take a amount of spaces on the first line, trim spaces with the same amount on every line
// since the code we are processing here has been formatted by Roslyn, we only take the cases that lines starts or ends with { or } to format.
var stack = new Stack<int>();
stack.Push(0);
const int spaceIncrement = 4;

for (int i = lineNumber; i < lines.Length; i++)
{
var line = lines[i].AsSpan();
// first we count how many leading spaces we are having on this line
int count = 0;
while (count < line.Length && char.IsWhiteSpace(line[count]))
{
count++;
}
var spaceCount = count;
// if the rest part of the line leads by a }, we should decrease the amount of leading spaces
if (count < line.Length && line[count] == '}')
{
stack.Pop();
}
// find out how many spaces we would like to prepend
var leadingSpaces = stack.Peek();
// if the rest part of the line leads by a {, we increment the leading space
if (count < line.Length && line[count] == '{')
{
stack.Push(stack.Peek() + spaceIncrement);
}
builder.AppendLine();
while (leadingSpaces > 0)
{
builder.Append(' ');
leadingSpaces--;
}
builder.Append(line.Slice(spaceCount));
}

return builder.ToString();
}

private static async Task<Dictionary<string, MethodDeclarationSyntax>> GetMethodsAsync(SyntaxTree syntaxTree)
{
var result = new Dictionary<string, MethodDeclarationSyntax>();
var root = await syntaxTree.GetRootAsync();

foreach (var method in root.DescendantNodes().OfType<MethodDeclarationSyntax>())
{
result.Add(method.Identifier.Text, method);
}

return result;
}

private class XmlStringWriter : StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
}
}
2 changes: 1 addition & 1 deletion src/AutoRest.CSharp/Common/Generation/Types/CSharpType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ private string ConvertParamName(bool useSquiggles)
var name = IsFrameworkType ? CodeWriter.GetTypeNameMapping(FrameworkType) ?? Name : Name;
if (IsNullable && IsValueType)
name += "?";
if (Arguments is not null && Arguments.Count() > 0)
if (Arguments is not null && Arguments.Length > 0)
{
name += useSquiggles ? "{" : "<";
name += string.Join(",", Arguments.Select(a => a.ConvertParamNameForDocs()));
Expand Down
2 changes: 2 additions & 0 deletions src/AutoRest.CSharp/Common/Generation/Types/TypeFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ internal static bool IsIEnumerableType(CSharpType type)

internal static bool IsIEnumerableOfT(CSharpType type) => type.IsFrameworkType && type.FrameworkType == typeof(IEnumerable<>);

internal static bool IsOperationOfT(CSharpType type) => type.IsFrameworkType && type.FrameworkType == typeof(Operation<>);

internal static bool IsIAsyncEnumerableOfT(CSharpType type) => type.IsFrameworkType && type.FrameworkType == typeof(IAsyncEnumerable<>);

internal static bool IsAsyncPageable(CSharpType type) => type.IsFrameworkType && type.FrameworkType == typeof(AsyncPageable<>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ public CodeWriter Literal(object? o)
double d => SyntaxFactory.Literal(d).ToString(),
float f => SyntaxFactory.Literal(f).ToString(),
bool b => b ? "true" : "false",
char c => SyntaxFactory.Literal(c).ToString(),
BinaryData bd => bd.ToArray().Length == 0 ? "new byte[] { }" : SyntaxFactory.Literal(bd.ToString()).ToString(),
_ => throw new NotImplementedException()
});
Expand Down
Loading