Skip to content

Commit

Permalink
Merge pull request #129 from ApiApprover/options
Browse files Browse the repository at this point in the history
Introduce Options to configure the generator
  • Loading branch information
danielmarbach committed Nov 8, 2019
2 parents 614e8b4 + ccb5a3a commit daf3b24
Show file tree
Hide file tree
Showing 21 changed files with 230 additions and 46 deletions.
30 changes: 23 additions & 7 deletions src/PublicApiGenerator/ApiGenerator.cs
Expand Up @@ -18,13 +18,13 @@ namespace PublicApiGenerator
{
public static class ApiGenerator
{
static readonly string[] defaultWhitelistedNamespacePrefixes = new string[0];

public static string GeneratePublicApi(Assembly assembly, Type[]? includeTypes = null, bool shouldIncludeAssemblyAttributes = true, string[]? whitelistedNamespacePrefixes = null, string[]? excludeAttributes = null)
public static string GeneratePublicApi(Assembly assembly, ApiGeneratorOptions? options = null)
{
if (assembly is null) throw new ArgumentNullException(nameof(assembly));

var attributeFilter = new AttributeFilter(excludeAttributes);
options ??= new ApiGeneratorOptions();

var attributeFilter = new AttributeFilter(options.ExcludeAttributes);

using (var assemblyResolver = new DefaultAssemblyResolver())
{
Expand All @@ -41,14 +41,30 @@ public static string GeneratePublicApi(Assembly assembly, Type[]? includeTypes =
{
return CreatePublicApiForAssembly(
asm,
typeDefinition => includeTypes == null || includeTypes.Any(type => type.FullName == typeDefinition.FullName && type.Assembly.FullName == typeDefinition.Module.Assembly.FullName),
shouldIncludeAssemblyAttributes,
whitelistedNamespacePrefixes ?? defaultWhitelistedNamespacePrefixes,
typeDefinition => options.IncludeTypes == null || options.IncludeTypes.Any(type => type.FullName == typeDefinition.FullName && type.Assembly.FullName == typeDefinition.Module.Assembly.FullName),
options.IncludeAssemblyAttributes,
options.WhitelistedNamespacePrefixes,
attributeFilter);
}
}
}

[Obsolete("Use `GeneratePublicApi(Assembly assembly, ApiGeneratorOptions? options = null)` instead. Will be removed in the next major.")]
public static string GeneratePublicApi(Assembly assembly, Type[]? includeTypes = null, bool shouldIncludeAssemblyAttributes = true, string[]? whitelistedNamespacePrefixes = null, string[]? excludeAttributes = null)
{
var options = new ApiGeneratorOptions
{
IncludeTypes = includeTypes,
IncludeAssemblyAttributes = shouldIncludeAssemblyAttributes,
ExcludeAttributes = excludeAttributes,
};
if (whitelistedNamespacePrefixes != null)
{
options.WhitelistedNamespacePrefixes = whitelistedNamespacePrefixes;
}
return GeneratePublicApi(assembly, options);
}

// TODO: Assembly references?
// TODO: Better handle namespaces - using statements? - requires non-qualified type names
static string CreatePublicApiForAssembly(AssemblyDefinition assembly, Func<TypeDefinition, bool> shouldIncludeType, bool shouldIncludeAssemblyAttributes, string[] whitelistedNamespacePrefixes, AttributeFilter attributeFilter)
Expand Down
49 changes: 49 additions & 0 deletions src/PublicApiGenerator/ApiGeneratorOptions.cs
@@ -0,0 +1,49 @@
using System;

namespace PublicApiGenerator
{
/// <summary>
/// Options to influence the ApiGenerator
/// </summary>
public class ApiGeneratorOptions
{
/// <summary>
/// Allows to control which types of the generated assembly should be included. If this option is specified all other types found in the assembly that are not present here will be exclude.
/// </summary>
public Type[]? IncludeTypes { get; set; }

/// <summary>
/// Instructs the generator to include assembly level attributes.
/// </summary>
/// <remarks>Defaults to true</remarks>
public bool IncludeAssemblyAttributes { get; set; } = true;

/// <summary>
/// Allows to whitelist certain namespace prefixes. For example by default types found in Microsoft or System namespaces are not treated as part of the public API.
/// </summary>
/// <example>
/// <code>
/// var options = new DefaultApiGeneratorOptions
/// {
/// WhitelistedNamespacePrefixes = new[] {"Microsoft.Whitelisted" }
/// };
/// </code>
/// </example>
public string[] WhitelistedNamespacePrefixes { get; set; } = DefaultWhitelistedNamespacePrefixes;

/// <summary>
/// Allows to exclude attributes by specifying the fullname of the attribute to exclude.
/// </summary>
/// <example>
///<code>
/// var options = new DefaultApiGeneratorOptions
/// {
/// ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.SimpleAttribute" }
/// };
/// </code>
/// </example>
public string[]? ExcludeAttributes { get; set; }

static readonly string[] DefaultWhitelistedNamespacePrefixes = Array.Empty<string>();
}
}
22 changes: 14 additions & 8 deletions src/PublicApiGeneratorTests/ApiGeneratorTestsBase.cs
@@ -1,6 +1,7 @@
using System;
using System.Reflection;
using System.Text.RegularExpressions;
using PublicApiGenerator;
using Xunit;

namespace PublicApiGeneratorTests
Expand All @@ -9,24 +10,29 @@ public abstract class ApiGeneratorTestsBase
{
private static readonly Regex StripEmptyLines = new Regex(@"^\s+$[\r\n]*", RegexOptions.Multiline | RegexOptions.Compiled);

protected void AssertPublicApi<T>(string expectedOutput, bool includeAssemblyAttributes = false, string[]? excludeAttributes = null)
protected void AssertPublicApi<T>(string expectedOutput, ApiGeneratorOptions? options = null)
{
AssertPublicApi(typeof(T), expectedOutput, includeAssemblyAttributes, excludeAttributes);
AssertPublicApi(typeof(T), expectedOutput, options);
}

protected void AssertPublicApi(Type type, string expectedOutput, bool includeAssemblyAttributes = false, string[]? excludeAttributes = null)
protected void AssertPublicApi(Type type, string expectedOutput, ApiGeneratorOptions? options = null)
{
AssertPublicApi(new[] { type }, expectedOutput, includeAssemblyAttributes, excludeAttributes: excludeAttributes);
AssertPublicApi(new[] { type }, expectedOutput, options);
}

protected void AssertPublicApi(Type[] types, string expectedOutput, bool includeAssemblyAttributes = false, string[]? whitelistedNamespacePrefixes = null, string[]? excludeAttributes = null)
protected void AssertPublicApi(Type[] types, string expectedOutput, ApiGeneratorOptions? options = null)
{
AssertPublicApi(types[0].Assembly, types, expectedOutput, includeAssemblyAttributes, whitelistedNamespacePrefixes, excludeAttributes);
options ??= new DefaultApiGeneratorOptions();
options.IncludeTypes = types;

AssertPublicApi(types[0].Assembly, expectedOutput, options);
}

private static void AssertPublicApi(Assembly assembly, Type[] types, string expectedOutput, bool includeAssemblyAttributes, string[]? whitelistedNamespacePrefixes, string[]? excludeAttributes)
private static void AssertPublicApi(Assembly assembly, string expectedOutput, ApiGeneratorOptions? options = null)
{
var actualOutput = PublicApiGenerator.ApiGenerator.GeneratePublicApi(assembly, types, includeAssemblyAttributes, whitelistedNamespacePrefixes, excludeAttributes);
options ??= new DefaultApiGeneratorOptions();

var actualOutput = ApiGenerator.GeneratePublicApi(assembly, options);
actualOutput = StripEmptyLines.Replace(actualOutput, string.Empty);
Assert.Equal(expectedOutput, actualOutput, ignoreCase: false, ignoreLineEndingDifferences: true,
ignoreWhiteSpaceDifferences: true);
Expand Down
3 changes: 2 additions & 1 deletion src/PublicApiGeneratorTests/Assembly_attributes.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

Expand Down Expand Up @@ -36,7 +37,7 @@ public class NotImportant
}
}";

AssertPublicApi<NotImportant>(api, true);
AssertPublicApi<NotImportant>(api, new ApiGeneratorOptions { IncludeAssemblyAttributes = true });
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/PublicApiGeneratorTests/Class_attributes.cs
@@ -1,4 +1,5 @@
using PublicApiGeneratorTests.Examples;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

namespace PublicApiGeneratorTests
Expand Down Expand Up @@ -277,6 +278,11 @@ public class ClassWithInternalAttribute
[Fact]
public void Should_skip_excluded_attribute()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] {"PublicApiGeneratorTests.Examples.Attribute_MM"}
};

AssertPublicApi<ClassWithMultipleAttributes>(
@"namespace PublicApiGeneratorTests.Examples
{
Expand All @@ -286,7 +292,7 @@ public class ClassWithMultipleAttributes
{
public ClassWithMultipleAttributes() { }
}
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.Attribute_MM" });
}", options);
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/PublicApiGeneratorTests/Class_event_attributes.cs
@@ -1,4 +1,5 @@
using System;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

Expand All @@ -24,6 +25,11 @@ public class ClassWithEventWithAttribute
[Fact]
public void Should_skip_excluded_attribute()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.SimpleAttribute" }
};

AssertPublicApi<ClassWithEventWithAttribute>(
@"namespace PublicApiGeneratorTests.Examples
{
Expand All @@ -32,7 +38,7 @@ public class ClassWithEventWithAttribute
public ClassWithEventWithAttribute() { }
public event System.EventHandler OnClicked;
}
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.SimpleAttribute" });
}", options);
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/PublicApiGeneratorTests/DefaultApiGeneratorOptions.cs
@@ -0,0 +1,12 @@
using PublicApiGenerator;

namespace PublicApiGeneratorTests
{
class DefaultApiGeneratorOptions : ApiGeneratorOptions
{
public DefaultApiGeneratorOptions()
{
IncludeAssemblyAttributes = false;
}
}
}
10 changes: 8 additions & 2 deletions src/PublicApiGeneratorTests/Delegate_attributes.cs
@@ -1,4 +1,5 @@
using PublicApiGeneratorTests.Examples;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

namespace PublicApiGeneratorTests
Expand Down Expand Up @@ -215,13 +216,18 @@ public void Should_output_attribute_for_parameter()
[Fact]
public void Should_skip_excluded_attribute()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.Attribute_ZZ" }
};

AssertPublicApi<DelegateWithMultipleAttributes>(
@"namespace PublicApiGeneratorTests.Examples
{
[PublicApiGeneratorTests.Examples.Attribute_AA]
[PublicApiGeneratorTests.Examples.Attribute_MM]
public delegate void DelegateWithMultipleAttributes();
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.Attribute_ZZ" });
}", options);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/PublicApiGeneratorTests/Field_attributes.cs
@@ -1,4 +1,5 @@
using PublicApiGeneratorTests.Examples;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

namespace PublicApiGeneratorTests
Expand Down Expand Up @@ -161,6 +162,11 @@ public class FieldWithMultipleAttributes
[Fact]
public void Should_skip_excluded_attributes()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.Attribute_MM", "PublicApiGeneratorTests.Examples.Attribute_ZZ" }
};

AssertPublicApi<FieldWithMultipleAttributes>(
@"namespace PublicApiGeneratorTests.Examples
{
Expand All @@ -170,7 +176,7 @@ public class FieldWithMultipleAttributes
public string Value;
public FieldWithMultipleAttributes() { }
}
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.Attribute_MM", "PublicApiGeneratorTests.Examples.Attribute_ZZ" });
}", options);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/PublicApiGeneratorTests/Interface_attributes.cs
@@ -1,4 +1,5 @@
using PublicApiGeneratorTests.Examples;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

namespace PublicApiGeneratorTests
Expand Down Expand Up @@ -154,11 +155,16 @@ public interface IInterfaceWithAttributeWithStringArrayInitialiser { }
[Fact]
public void Should_skip_excluded_attribute()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.SimpleAttribute" }
};

AssertPublicApi<IInterfaceWithSimpleAttribute>(
@"namespace PublicApiGeneratorTests.Examples
{
public interface IInterfaceWithSimpleAttribute { }
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.SimpleAttribute" });
}", options);
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/PublicApiGeneratorTests/Interface_event_attributes.cs
@@ -1,4 +1,5 @@
using System;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

Expand All @@ -23,14 +24,19 @@ public interface IInterfaceWithEventWithAttribute
[Fact]
public void Should_skip_excluded_attribute()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.SimpleAttribute" }
};

AssertPublicApi<IInterfaceWithEventWithAttribute>(
@"namespace PublicApiGeneratorTests.Examples
{
public interface IInterfaceWithEventWithAttribute
{
public event System.EventHandler OnClicked;
}
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.SimpleAttribute" });
}", options);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/PublicApiGeneratorTests/Interface_method_attributes.cs
@@ -1,4 +1,5 @@
using PublicApiGeneratorTests.Examples;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

namespace PublicApiGeneratorTests
Expand Down Expand Up @@ -132,6 +133,11 @@ public interface IMethodWithMultipleAttributes
[Fact]
public void Should_skip_excluded_attribute()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.AttributeWithNamedParameterAttribute" }
};

AssertPublicApi<IMethodsWithAttributeWithNamedParameters>(
@"namespace PublicApiGeneratorTests.Examples
{
Expand All @@ -140,7 +146,7 @@ public interface IMethodsWithAttributeWithNamedParameters
void Method1();
void Method2();
}
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.AttributeWithNamedParameterAttribute" });
}", options);
}
}

Expand Down
@@ -1,4 +1,5 @@
using PublicApiGeneratorTests.Examples;
using PublicApiGenerator;
using PublicApiGeneratorTests.Examples;
using Xunit;

namespace PublicApiGeneratorTests
Expand Down Expand Up @@ -129,14 +130,19 @@ public interface IMethodWithAttributesOnMethodAndReturnValue
[Fact]
public void Should_skip_excluded_attribute()
{
var options = new DefaultApiGeneratorOptions
{
ExcludeAttributes = new[] { "PublicApiGeneratorTests.Examples.AttributeWithNamedParameterAttribute" }
};

AssertPublicApi<IMethodReturnValueWithAttributeWithMultipleNamedParameters>(
@"namespace PublicApiGeneratorTests.Examples
{
public interface IMethodReturnValueWithAttributeWithMultipleNamedParameters
{
void Method();
}
}", excludeAttributes: new[] { "PublicApiGeneratorTests.Examples.AttributeWithNamedParameterAttribute" });
}", options);
}
}

Expand Down

0 comments on commit daf3b24

Please sign in to comment.