Skip to content

Commit

Permalink
Add XML Doc snippet support (#11808)
Browse files Browse the repository at this point in the history
  • Loading branch information
pakrym authored May 11, 2020
1 parent 3a027e4 commit fda02f7
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 12 deletions.
49 changes: 49 additions & 0 deletions eng/SnippetGenerator/CSharpProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Linq;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;

namespace SnippetGenerator
{
public class CSharpProcessor
{
private static readonly string _snippetFormat = "{3} <code snippet=\"{0}\">{1}{2} </code>";
private static readonly Regex _snippetRegex = new Regex("^(?<indent>\\s*)\\/{3}\\s*<code snippet=\\\"(?<name>[\\w:]+)\\\">.*?\\/{3}\\s*<\\/code>",
RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);

public static string Process(string markdown, Func<string, string> snippetProvider)
{
return _snippetRegex.Replace(markdown, match =>
{
var name = match.Groups["name"].Value;
var prefix = match.Groups["indent"].Value + "///";
var snippetText = snippetProvider(name);
var builder = new StringBuilder();
foreach (var line in snippetText.Split(Environment.NewLine))
{
builder.Append(prefix);
if (!string.IsNullOrWhiteSpace(line))
{
builder.Append(" ");
}
builder.AppendLine(SecurityElement.Escape(line));
}
if (builder.Length > 0)
{
builder.Length -= Environment.NewLine.Length;
}
return string.Format(_snippetFormat, name, Environment.NewLine, builder, prefix);
});
}

}
}
37 changes: 26 additions & 11 deletions eng/SnippetGenerator/DirectoryProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,35 +37,50 @@ public DirectoryProcessor(string directory)

public void Process()
{
foreach (var mdFile in Directory.EnumerateFiles(_directory, "*.md", SearchOption.AllDirectories))
{
Console.WriteLine($"Processing {mdFile}");

var text = File.ReadAllText(mdFile);
bool changed = false;
List<string> files = new List<string>();
files.AddRange(Directory.EnumerateFiles(_directory, "*.md", SearchOption.AllDirectories));
files.AddRange(Directory.EnumerateFiles(_directory, "*.cs", SearchOption.AllDirectories));

text = MarkdownProcessor.Process(text, s =>
foreach (var file in files)
{
string SnippetProvider(string s)
{
var selectedSnippets = _snippets.Value.Where(snip => snip.Name == s).ToArray();
if (selectedSnippets.Length > 1)
{
throw new InvalidOperationException($"Multiple snippets with the name '{s}' defined '{_directory}'");
}

if (selectedSnippets.Length == 0)
{
throw new InvalidOperationException($"Snippet '{s}' not found in directory '{_directory}'");
}

var selectedSnippet = selectedSnippets.Single();
Console.WriteLine($"Replaced {selectedSnippet.Name}");
changed = true;
Console.WriteLine($"Replaced {selectedSnippet.Name} in {file}");
return FormatSnippet(selectedSnippet.Text);
});
}

var originalText = File.ReadAllText(file);

string text;
switch (Path.GetExtension(file))
{
case ".md":
text = MarkdownProcessor.Process(originalText, SnippetProvider);
break;
case ".cs":
text = CSharpProcessor.Process(originalText, SnippetProvider);
break;
default:
throw new NotSupportedException(file);
}

if (changed)
if (text != originalText)
{
_utf8EncodingWithoutBOM = new UTF8Encoding(false);
File.WriteAllText(mdFile, text, _utf8EncodingWithoutBOM);
File.WriteAllText(file, text, _utf8EncodingWithoutBOM);
}
}
}
Expand Down
33 changes: 32 additions & 1 deletion sdk/core/Azure.Core/src/AsyncPageable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
Expand All @@ -13,6 +13,37 @@ namespace Azure
/// iterate over.
/// </summary>
/// <typeparam name="T">The type of the values.</typeparam>
/// <example>
/// Example of enumerating an AsyncPageable using the <c> async foreach </c> loop:
/// <code snippet="Snippet:AsyncPageable">
/// // call a service method, which returns AsyncPageable&lt;T&gt;
/// AsyncPageable&lt;SecretProperties&gt; allSecretProperties = client.GetPropertiesOfSecretsAsync();
///
/// await foreach (SecretProperties secretProperties in allSecretProperties)
/// {
/// Console.WriteLine(secretProperties.Name);
/// }
/// </code>
/// or using a while loop:
/// <code snippet="Snippet:AsyncPageableLoop">
/// // call a service method, which returns AsyncPageable&lt;T&gt;
/// AsyncPageable&lt;SecretProperties&gt; allSecretProperties = client.GetPropertiesOfSecretsAsync();
///
/// IAsyncEnumerator&lt;SecretProperties&gt; enumerator = allSecretProperties.GetAsyncEnumerator();
/// try
/// {
/// while (await enumerator.MoveNextAsync())
/// {
/// SecretProperties secretProperties = enumerator.Current;
/// Console.WriteLine(secretProperties.Name);
/// }
/// }
/// finally
/// {
/// await enumerator.DisposeAsync();
/// }
/// </code>
/// </example>
public abstract class AsyncPageable<T> : IAsyncEnumerable<T> where T : notnull
{
/// <summary>
Expand Down

0 comments on commit fda02f7

Please sign in to comment.