Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add XML Doc snippet support #11808

Merged
merged 5 commits into from
May 11, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions eng/SnippetGenerator/CSharpProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Linq;
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("^(?<ident>\\s*)\\/{3}\\s*<code snippet=\\\"(?<name>[\\w:]+)\\\">.*?\\/{3}\\s*<\\/code>",
pakrym marked this conversation as resolved.
Show resolved Hide resolved
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["ident"].Value + "/// ";

var snippetText = snippetProvider(name);
var text =
string.Join(Environment.NewLine,
snippetText.Split(Environment.NewLine).Select(l=>prefix + l));

return string.Format(_snippetFormat, name, Environment.NewLine, text, 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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to dramatically increase the number of files that get scanned. I wonder if it'd be more efficient to do it line by line? Not something to fix now, but might be worth filing a tracking bug for. (Doing a couple of perf measurements and speeding this up might make a good Tech Talk for the team?)


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">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea what will happen if we run this through our ref doc generation tools? Might want to hold off on merging this until we're through with the release so @scbedd and @chidozieononiwu don't have any fun surprises.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my question was more about whether a custom snippet attribute on the <code> element would cause any problems with the doc generation tools. It shouldn't, but I've found previous generations of doc generation tools like Sandcastle to be very finicky. Might be worth an extra doc generation test after we merge it as a sanity check between releases.

/// // call a service method, which returns AsyncPageable<T>
/// AsyncPageable<SecretProperties> 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<T>
/// AsyncPageable<SecretProperties> allSecretProperties = client.GetPropertiesOfSecretsAsync();
///
/// IAsyncEnumerator<SecretProperties> 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