diff --git a/AutoSDK.slnx b/AutoSDK.slnx
index 39ffe9555d..3649d0d190 100644
--- a/AutoSDK.slnx
+++ b/AutoSDK.slnx
@@ -3,10 +3,10 @@
+
-
@@ -57,6 +57,7 @@
+
diff --git a/specs/petstore.yaml b/specs/petstore.yaml
index fa14a9781d..de31197cf9 100644
--- a/specs/petstore.yaml
+++ b/specs/petstore.yaml
@@ -73,7 +73,7 @@ paths:
content:
application/json:
schema:
- $ref: "#/components/schemas/Pet"
+ $ref: "#/components/schemas/PetStore.Pet"
default:
description: unexpected error
content:
@@ -82,7 +82,7 @@ paths:
$ref: "#/components/schemas/Error"
components:
schemas:
- Pet:
+ PetStore.Pet:
type: object
required:
- id
@@ -99,7 +99,7 @@ components:
type: array
maxItems: 100
items:
- $ref: "#/components/schemas/Pet"
+ $ref: "#/components/schemas/PetStore.Pet"
Error:
type: object
required:
diff --git a/src/libs/AutoSDK/Extensions/StringExtensions.cs b/src/libs/AutoSDK/Extensions/StringExtensions.cs
index d2b397e44a..0dd7e4d3e4 100644
--- a/src/libs/AutoSDK/Extensions/StringExtensions.cs
+++ b/src/libs/AutoSDK/Extensions/StringExtensions.cs
@@ -1,6 +1,4 @@
using System.Globalization;
-using Microsoft.OpenApi.Models;
-using Microsoft.OpenApi.Readers;
namespace AutoSDK.Extensions;
@@ -25,7 +23,7 @@ public static string Inject(this IEnumerable values, string emptyValue =
return text;
}
-
+
///
/// Makes the first letter of the name uppercase.
///
@@ -46,7 +44,7 @@ public static string ToPropertyName(this string input)
#endif
};
}
-
+
///
/// Makes the first letter of the name lowercase.
///
@@ -75,7 +73,7 @@ public static string ToParameterName(this string input)
#pragma warning restore CA1308 // Normalize strings to uppercase
};
}
-
+
///
/// Normalizes line endings to '\n' or your endings.
///
@@ -99,7 +97,7 @@ public static string NormalizeLineEndings(
return newText;
}
-
+
private static readonly char[] Separator = { '\n' };
///
@@ -121,85 +119,85 @@ public static string RemoveBlankLinesWhereOnlyWhitespaces(this string text)
.Split(Separator, StringSplitOptions.None)
.Where(static line => line.Length == 0 || !line.All(char.IsWhiteSpace)));
}
-
+
public static string AsArray(this string type)
{
return $"global::System.Collections.Generic.IList<{type}>";
}
-
+
public static string? WithPostfix(this string? type, string postfix)
{
if (type == null)
{
return null;
}
-
+
return type + postfix;
}
-
+
public static string ToXmlDocumentation(
this string text,
int level = 4,
bool returnIfSingleLine = false)
{
text = text ?? throw new ArgumentNullException(nameof(text));
-
+
var lines = text.Split(NewLine, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length == 0)
{
lines = [string.Empty];
}
-
+
if (returnIfSingleLine && lines.Length == 1)
{
return $"{lines[0]}";
}
-
+
var spaces = new string(' ', level);
var value = string.Join("\n", lines
.Select((line, i) => $"{spaces}/// {line}{(i != lines.Length - 1 ? "
" : string.Empty)}"));
-
+
return value;
}
-
+
public static string ToXmlDocumentationSummary(
this string text,
int level = 4)
{
text = text ?? throw new ArgumentNullException(nameof(text));
-
+
var spaces = new string(' ', level);
var value = ToXmlDocumentation(text, level);
-
+
return $@"///
{value}
{spaces}/// ";
}
-
+
public static string ToXmlDocumentationExample(
this string text,
int level = 4)
{
text = text ?? throw new ArgumentNullException(nameof(text));
-
+
if (string.IsNullOrWhiteSpace(text))
{
return string.Empty;
}
-
+
var value = ToXmlDocumentation(text, level, returnIfSingleLine: true);
if (!value.Contains("\n"))
{
return $"/// {value}";
}
-
+
var spaces = new string(' ', level);
-
+
return $@"///
{value}
{spaces}/// ";
}
-
+
public static string ToXmlDocumentationDefault(
this string text,
int level = 4)
@@ -210,20 +208,20 @@ public static string ToXmlDocumentationDefault(
{
return string.Empty;
}
-
+
var value = ToXmlDocumentation(text, level, returnIfSingleLine: true);
if (!value.Contains("\n"))
{
return $"/// {value}";
}
-
+
var spaces = new string(' ', level);
-
+
return $@"///
{value}
{spaces}/// ";
}
-
+
public static string ToXmlDocumentationForParam(
this string text,
string parameterName,
@@ -231,37 +229,37 @@ public static string ToXmlDocumentationForParam(
{
text = text ?? throw new ArgumentNullException(nameof(text));
parameterName = parameterName ?? throw new ArgumentNullException(nameof(parameterName));
-
+
var spaces = new string(' ', level);
var value = ToXmlDocumentation(text, level);
-
+
return string.IsNullOrWhiteSpace(text)
? $@"/// "
: $@"///
{value}
{spaces}/// ";
}
-
+
public static string UseWordSeparator(
this string propertyName,
params char[] separator)
{
propertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
-
+
if (!separator.Any(propertyName.Contains))
{
return propertyName;
}
-
+
return string.Join(
string.Empty,
propertyName
.Split(separator)
.Select(word => word.ToPropertyName()));
}
-
+
private readonly static string[] NewLine = { "\n" };
-
+
public static string AddIndent(
this string text,
int level)
@@ -271,14 +269,14 @@ public static string AddIndent(
{
return text;
}
-
+
var lines = text.Split(NewLine, StringSplitOptions.None);
var spaces = new string(' ', level * 4);
-
+
return string.Join("\n", lines
.Select(line => string.IsNullOrEmpty(line) ? line : $"{spaces}{line}"));
}
-
+
public static string FixPropertyName(
this string propertyName,
string className)
@@ -287,15 +285,29 @@ public static string FixPropertyName(
? $"{propertyName}1"
: propertyName;
}
-
+
public static string ToClassName(
this string text)
{
return text
.ToPropertyName()
- .UseWordSeparator('_', '-', '.', ' ', '\\', '/', '[', ']');
+ .UseWordSeparator('_', '-', ' ', '\\', '/', '[', ']')
+ .Split('.')
+ .Last();
}
-
+
+ public static string ToNamespace(
+ this string text)
+ {
+ if (string.IsNullOrWhiteSpace(text))
+ {
+ throw new ArgumentNullException(nameof(text));
+ }
+ return text
+ .Split('.')
+ .Last();
+ }
+
public static string ReplaceIfEquals(
this string text,
string oldValue,
diff --git a/src/libs/AutoSDK/Models/AnyOfData.cs b/src/libs/AutoSDK/Models/AnyOfData.cs
index 6e8ff7cf85..24f3cc29dc 100644
--- a/src/libs/AutoSDK/Models/AnyOfData.cs
+++ b/src/libs/AutoSDK/Models/AnyOfData.cs
@@ -1,8 +1,7 @@
-using System.Collections.Immutable;
using AutoSDK.Extensions;
using AutoSDK.Naming.AnyOfs;
-using AutoSDK.Naming.Properties;
using AutoSDK.Serialization.Json;
+using System.Collections.Immutable;
namespace AutoSDK.Models;
@@ -20,11 +19,11 @@ Settings Settings
)
{
public bool IsNamed => !string.IsNullOrWhiteSpace(Name);
-
+
public static AnyOfData FromSchemaContext(SchemaContext context)
{
context = context ?? throw new ArgumentNullException(nameof(context));
-
+
var children = context.Children
.Where(x => x.Hint == (context.IsAnyOf
? Hint.AnyOf
@@ -35,15 +34,14 @@ public static AnyOfData FromSchemaContext(SchemaContext context)
var className = context.Id.ToClassName();
TypeData? discriminatorType = null;
string? discriminatorPropertyName = null;
-
+
if (context.Schema.Discriminator != null &&
context.Schema.Discriminator.Mapping.Count != 0)
{
discriminatorType = context.Children.FirstOrDefault(x => x.Hint == Hint.Discriminator)?.TypeData;
- discriminatorPropertyName = context.Schema.Discriminator.PropertyName.ToPropertyName()
- .ToCSharpName(context.Settings, context.Parent);
+ discriminatorPropertyName = context.Schema.Discriminator.PropertyName.ToPropertyName();
}
-
+
var count = context.IsAnyOf
? context.Schema.AnyOf.Count
: context.IsOneOf
@@ -86,7 +84,7 @@ public static AnyOfData FromSchemaContext(SchemaContext context)
})
.ToImmutableArray().AsEquatableArray();
}
-
+
return new AnyOfData(
SubType: context.IsAnyOf
? "AnyOf"
diff --git a/src/libs/AutoSDK/Models/EndPointResponse.cs b/src/libs/AutoSDK/Models/EndPointResponse.cs
index 0702ffd3cc..13acf890ea 100644
--- a/src/libs/AutoSDK/Models/EndPointResponse.cs
+++ b/src/libs/AutoSDK/Models/EndPointResponse.cs
@@ -1,5 +1,5 @@
-using Microsoft.OpenApi.Models;
using AutoSDK.Extensions;
+using Microsoft.OpenApi.Models;
namespace AutoSDK.Models;
@@ -20,18 +20,18 @@ TypeData Type
public bool IsPattern => StatusCode.Contains("XX");
public int Min => int.TryParse(StatusCode.Replace("XX", "00"), out var code) ? code : 0;
public int Max => int.TryParse(StatusCode.Replace("XX", "99"), out var code) ? code : 0;
-
+
public static EndPointResponse Default => new(
StatusCode: "200",
Description: string.Empty,
MimeType: string.Empty,
ContentType: ContentType.String,
Type: TypeData.Default);
-
+
public static EndPointResponse FromResponse(KeyValuePair responseWithStatusCode, OperationContext operation)
{
operation = operation ?? throw new ArgumentNullException(nameof(operation));
-
+
var responses = responseWithStatusCode.Value?.ResolveIfRequired().Content?
.Select(x => (
StatusCode: responseWithStatusCode.Key,
@@ -46,9 +46,9 @@ public static EndPointResponse FromResponse(KeyValuePair responseContext?.TypeData,
+ _ => responseContext?.ResolvedReference?.TypeData,
};
if (responseType?.CSharpTypeWithoutNullability == "object")
{
@@ -77,7 +77,7 @@ public static EndPointResponse FromResponse(KeyValuePair p.Box()).ToImmutableArray(),
- Namespace: context.Settings.Namespace,
+ Namespace: context.TypeData.Namespace ?? throw new ArgumentNullException(context.ReferenceId),
Style: context.Schema.IsEnum() ? ModelStyle.Enumeration : context.Settings.ModelStyle,
Settings: context.Settings,
Properties: context.IsDerivedClass
diff --git a/src/libs/AutoSDK/Models/SchemaContext.cs b/src/libs/AutoSDK/Models/SchemaContext.cs
index fbfd891c91..89af8eee33 100644
--- a/src/libs/AutoSDK/Models/SchemaContext.cs
+++ b/src/libs/AutoSDK/Models/SchemaContext.cs
@@ -1,8 +1,7 @@
-using Microsoft.OpenApi.Models;
using AutoSDK.Extensions;
using AutoSDK.Naming.Models;
-using AutoSDK.Naming.Properties;
using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Models;
namespace AutoSDK.Models;
@@ -14,36 +13,36 @@ public class SchemaContext(
{
public SchemaContext? Parent { get; set; }
public IList Children { get; set; } = [];
-
+
public Settings Settings { get; set; } = settings;
public OpenApiSchema Schema { get; set; } = schema;
public string Id { get; set; } = id;
public string Type { get; set; } = type;
-
+
public string? ReferenceId { get; set; }
public bool IsReference => ReferenceId != null;
public SchemaContext? ResolvedReference { get; set; }
-
+
public IList Links { get; set; } = [];
-
+
public Hint? Hint { get; set; }
public int? Index { get; set; }
///
/// Used to constrain the recursion depth.
///
public int Depth { get; set; }
-
+
public string? PropertyName { get; set; }
public bool IsProperty => PropertyName != null;
public PropertyData? PropertyData { get; set; }
-
+
public string? ParameterName => Parameter?.Name;
public bool IsParameter => ParameterName != null;
public MethodParameter? ParameterData { get; set; }
-
+
public string? ComponentId { get; set; }
public bool IsComponent => ComponentId != null || ResolvedReference?.IsComponent == true;
-
+
public string? OperationPath { get; set; }
public OperationType? OperationType { get; set; }
public OpenApiOperation? Operation { get; set; }
@@ -53,35 +52,35 @@ public class SchemaContext(
public string? ResponseStatusCode { get; set; }
public OpenApiResponse? Response { get; set; }
public bool IsOperation => OperationPath != null;
-
+
public TypeData TypeData { get; set; } = TypeData.Default;
-
+
public bool IsClass =>
Type == "class" ||
IsDerivedClass;// || ResolvedReference?.IsClass == true;
//public ModelData? ClassData { get; set; }
public ModelData? ClassData => IsClass
? //IsReference
- //? ModelData.FromSchemaContext(ResolvedReference!)
- //:
+ //? ModelData.FromSchemaContext(ResolvedReference!)
+ //:
ModelData.FromSchemaContext(this)
: null;
-
+
public bool IsEnum => Type == "enum";// || ResolvedReference?.IsEnum == true;
//public ModelData? EnumData { get; set; }
public ModelData? EnumData => IsEnum
? //IsReference
- //? ModelData.FromSchemaContext(ResolvedReference!)
- //:
+ //? ModelData.FromSchemaContext(ResolvedReference!)
+ //:
ModelData.FromSchemaContext(this)
: null;
public string? ClassName { get; set; }
-
+
public AnyOfData? AnyOfData { get; set; }
public string? VariantName { get; set; }
-
+
public bool IsModel => IsClass || IsEnum || IsAnyOfLikeStructure && IsComponent;
-
+
public bool IsAnyOf => Schema.IsAnyOf();
public bool IsOneOf => Schema.IsOneOf();
public bool IsAllOf => Schema.IsAllOf() && !IsDerivedClass;
@@ -100,7 +99,7 @@ public class SchemaContext(
? Children.First(x => x.ReferenceId == allOf[1].Reference?.Id)
: Children.First(x => x.ReferenceId == allOf[0].Reference?.Id)
: throw new InvalidOperationException("Schema is not derived class.");
-
+
public SchemaContext BaseClassContext =>
Schema.IsAllOf() &&
Schema.AllOf is { Count: 2 } allOf
@@ -109,11 +108,11 @@ public class SchemaContext(
? Children.First(x => x.ReferenceId == allOf[0].Reference?.Id)
: Children.First(x => x.ReferenceId == allOf[1].Reference?.Id)
: throw new InvalidOperationException("Schema is not derived class.");
-
+
public bool IsAnyOfLikeStructure => IsAnyOf || IsOneOf || IsAllOf;
public bool IsNamedAnyOfLike => IsAnyOfLikeStructure &&
(IsComponent || Schema.Discriminator != null);
-
+
public IReadOnlyList ComputedProperties
{
get
@@ -122,7 +121,7 @@ public IReadOnlyList ComputedProperties
{
return [];
}
-
+
if (Schema.IsBinary() &&
Parent?.Children.Any(x => x.PropertyName == PropertyName + "name") != true)
{
@@ -150,7 +149,7 @@ PropertyData.Value with
}
public HashSet Tags { get; set; } = [];
-
+
private static string ComputeType(OpenApiSchema schema, bool isComponent)
{
if (schema.IsEnum())
@@ -158,9 +157,9 @@ private static string ComputeType(OpenApiSchema schema, bool isComponent)
return "enum";
}
if (schema.Type == "object")// &&
- // (isComponent ||
- // schema.Properties.Count > 0 ||
- // !schema.AdditionalPropertiesAllowed))
+ // (isComponent ||
+ // schema.Properties.Count > 0 ||
+ // !schema.AdditionalPropertiesAllowed))
{
return "class";
}
@@ -209,7 +208,7 @@ private static string ComputeType(OpenApiSchema schema, bool isComponent)
{
return "allOf";
}
-
+
return schema.Type ?? "class";
}
@@ -246,7 +245,7 @@ public static IReadOnlyList FromSchema(
return [new SchemaContext(
settings,
schema,
- id: schema.Reference.Id.ToCSharpName(settings, parent),
+ id: schema.Reference.Id,
type: "ref")
{
Parent = parent,
@@ -266,7 +265,7 @@ public static IReadOnlyList FromSchema(
Depth = depth,
}];
}
-
+
var context = new SchemaContext(
settings,
schema,
@@ -288,7 +287,7 @@ public static IReadOnlyList FromSchema(
Response = response,
Depth = depth,
};
-
+
var children = new List();
if (schema.Items != null)
{
@@ -308,7 +307,7 @@ public static IReadOnlyList FromSchema(
hint: Models.Hint.AdditionalProperties,
depth: depth + 1));
}
-
+
var i = 0;
foreach (var property in schema.Properties)
{
@@ -355,7 +354,7 @@ public static IReadOnlyList FromSchema(
index: i++,
depth: depth + 1));
}
-
+
if (schema.Discriminator != null)
{
children.AddRange(FromSchema(
@@ -364,7 +363,7 @@ public static IReadOnlyList FromSchema(
Type = "object",
Properties =
{
- [schema.Discriminator.PropertyName] = new OpenApiSchema
+ [schema.Discriminator.PropertyName.ToPropertyName()] = new OpenApiSchema
{
Type = "string",
Enum = schema.Discriminator.Mapping?.Keys
@@ -379,20 +378,20 @@ public static IReadOnlyList FromSchema(
hint: Models.Hint.Discriminator,
depth: depth + 1));
}
-
+
context.Children = children
.Where(x => x.Depth == depth + 1)
.ToList();
-
+
// We need to fix name, so it doesn't conflict with real used name() and not to be handled as name conflict.
if (schema.HasAllOfTypeForMetadata(propertyName: propertyName))
{
context.Id += "_AllOf1Wrapped";
}
-
- return [context, ..children];
+
+ return [context, .. children];
}
-
+
public void ComputeData(int level = 0, int maxDepth = 20)
{
// Prevent infinite recursion for circular references
@@ -400,13 +399,13 @@ public void ComputeData(int level = 0, int maxDepth = 20)
{
return;
}
-
+
ResolvedReference?.ComputeData(level + 1, maxDepth: maxDepth);
foreach (var child in Children)
{
child.ComputeData(level + 1, maxDepth: maxDepth);
}
-
+
TypeData = IsReference
? ResolvedReference?.TypeData ??
throw new InvalidOperationException("Resolved reference must have type data.")
@@ -432,7 +431,7 @@ public void ComputeData(int level = 0, int maxDepth = 20)
AnyOfData = global::AutoSDK.Models.AnyOfData.FromSchemaContext(this);
}
}
-
+
public bool HasAnyTag(params string[] tags)
{
return
@@ -440,19 +439,19 @@ public bool HasAnyTag(params string[] tags)
Tags.Any(tags.Contains) ||
Parent?.HasAnyTag(tags) == true;
}
-
+
public bool AnyParent(Func predicate)
{
predicate = predicate ?? throw new ArgumentNullException(nameof(predicate));
-
+
if (predicate(this))
{
return true;
}
-
+
return Parent?.AnyParent(predicate) == true;
}
-
+
public IReadOnlyCollection WithAllChildren(int level = 0, int maxDepth = 20)
{
// Prevent infinite recursion for circular references
@@ -460,21 +459,21 @@ public IReadOnlyCollection WithAllChildren(int level = 0, int max
{
return [];
}
-
+
if (IsReference)
{
- return [this, ..ResolvedReference!.WithAllChildren(level + 1, maxDepth: maxDepth)];
+ return [this, .. ResolvedReference!.WithAllChildren(level + 1, maxDepth: maxDepth)];
}
-
+
var result = new List { this };
foreach (var child in Children)
{
result.AddRange(child.WithAllChildren(level + 1, maxDepth: maxDepth));
}
-
+
return result;
}
-
+
public void ComputeTags(HashSet? parentTags = null, int level = 0, int maxDepth = 20)
{
// Prevent infinite recursion for circular references
@@ -482,7 +481,7 @@ public void ComputeTags(HashSet? parentTags = null, int level = 0, int m
{
return;
}
-
+
foreach (var tag in Operation?.Tags ?? [])
{
Tags.Add(tag.Name);
@@ -491,7 +490,7 @@ public void ComputeTags(HashSet? parentTags = null, int level = 0, int m
{
Tags.Add(tag);
}
-
+
foreach (var child in Children)
{
child.ComputeTags(Tags, level + 1, maxDepth: maxDepth);
diff --git a/src/libs/AutoSDK/Models/TypeData.cs b/src/libs/AutoSDK/Models/TypeData.cs
index 94bdb33bbb..9e0a03441f 100644
--- a/src/libs/AutoSDK/Models/TypeData.cs
+++ b/src/libs/AutoSDK/Models/TypeData.cs
@@ -55,8 +55,24 @@ public record struct TypeData(
Namespace: string.Empty,
IsDeprecated: false,
Settings: Settings.Default);
-
- public string CSharpTypeWithoutNullability => CSharpTypeRaw.TrimEnd('?');
+ ///
+ /// This method removes the namespace from the type,
+ /// if the type is in the ExcludeModels list.
+ /// This makes it possible to use global usings to define
+ /// outside of the generator where this type should come from.
+ ///
+ ///
+ private string GetCsharpTypeValue()
+ {
+ var typeName = CSharpTypeRaw.TrimEnd('?').Replace($"global::{Namespace}.", string.Empty);
+ if (Settings.ExcludeModels.Contains(typeName))
+ {
+ Namespace = string.Empty;
+ return typeName;
+ }
+ return CSharpTypeRaw;
+ }
+ public string CSharpTypeWithoutNullability => GetCsharpTypeValue();
public string CSharpTypeWithNullability => CSharpTypeWithoutNullability + "?";
public string ShortCSharpTypeWithoutNullability => CSharpTypeWithoutNullability.Replace($"global::{Namespace}.", string.Empty);
public string ShortCSharpTypeWithNullability => ShortCSharpTypeWithoutNullability + "?";
@@ -129,7 +145,7 @@ public static TypeData FromSchemaContext(SchemaContext context)
subTypes = [
context.Children
.FirstOrDefault(x => x is { Hint: Hint.ArrayItem } && x.TypeData != Default)
- ?.TypeData ??
+ ?.ResolvedReference?.TypeData ??
Default with
{
IsEnum = context.Schema.Items.IsEnum(),
@@ -162,6 +178,11 @@ Default with
}
var type = GetCSharpType(context);
+ if (context.Schema.Reference is not null &&
+ context.Settings.ExcludeModels.Contains(context.Schema.Reference.Id))
+ {
+ type = context.Schema.Reference.Id;
+ }
return new TypeData(
CSharpTypeRaw: type,
@@ -233,10 +254,12 @@ public static string GetCSharpType(SchemaContext context)
(_, _) when context.Schema.IsUnixTimestamp() => "global::System.DateTimeOffset",
(_, _) when context.Schema.IsArray() =>
- $"{context.Children.FirstOrDefault(x => x.Hint == Hint.ArrayItem)?.TypeData.CSharpTypeWithoutNullability}".AsArray(),
+ $"{(context.Children.FirstOrDefault(x => x.Hint == Hint.ArrayItem)?.IsReference == true ?
+ context.Children.FirstOrDefault(x => x.Hint == Hint.ArrayItem)?.ResolvedReference?.TypeData.CSharpTypeWithoutNullability :
+ context.Children.FirstOrDefault(x => x.Hint == Hint.ArrayItem)?.TypeData.CSharpTypeWithoutNullability)}".AsArray(),
// Fallback if `items` property is missing (openai specification)
("array", _) => "byte[]",
-
+
(_, _) when context.IsNamedAnyOfLike => $"global::{context.Settings.Namespace}.{context.Id}",
(_, _) when context.IsDerivedClass => $"global::{context.Settings.Namespace}.{context.Id}",
diff --git a/src/libs/AutoSDK/Naming/Models/ModelNameGenerator.cs b/src/libs/AutoSDK/Naming/Models/ModelNameGenerator.cs
index 98eaadd76e..2c1bb3e100 100644
--- a/src/libs/AutoSDK/Naming/Models/ModelNameGenerator.cs
+++ b/src/libs/AutoSDK/Naming/Models/ModelNameGenerator.cs
@@ -1,7 +1,7 @@
-using Microsoft.OpenApi.Models;
using AutoSDK.Extensions;
using AutoSDK.Models;
using AutoSDK.Naming.Properties;
+using Microsoft.OpenApi.Models;
namespace AutoSDK.Naming.Models;
@@ -19,11 +19,11 @@ public static string ComputeId(
{
if (propertyName != null)
{
- return propertyName.ToCSharpName(settings, parent);
+ return propertyName.ToPropertyName();
}
if (componentId != null)
{
- return componentId.ToCSharpName(settings, parent);
+ return componentId;
}
var helper = hint switch
@@ -37,7 +37,7 @@ public static string ComputeId(
//_ when propertyName != null => propertyName,
_ => null,
};
- var id = parent?.Id + helper?.ToCSharpName(settings, parent);
+ var id = parent?.Id + helper?.ToClassName();
if (string.IsNullOrWhiteSpace(id))
{
throw new InvalidOperationException("Id is required. Invalid info.");
@@ -45,11 +45,11 @@ public static string ComputeId(
return id;
}
-
+
public static string? ComputeHelperName(this SchemaContext context)
{
context = context ?? throw new ArgumentNullException(nameof(context));
-
+
return (context.Hint switch
{
Hint.ArrayItem => "Item",
@@ -60,16 +60,16 @@ public static string ComputeId(
Hint.Discriminator => "Discriminator",
_ when context.PropertyName != null => context.PropertyName,
_ => null,
- })?.ToCSharpName(context.Settings, context.Parent);
+ });
}
-
+
public static string ComputeClassName(this SchemaContext context)
{
context = context ?? throw new ArgumentNullException(nameof(context));
-
+
if (context.ComponentId != null)
{
- return context.ComponentId.ToCSharpName(context.Settings, context.Parent).ToClassName();
+ return context.ComponentId.ToClassName();
}
// NamingConvention.InnerClasses => Parents.IsEmpty ? Name : $"_{Name}",
@@ -80,7 +80,7 @@ public static string ComputeClassName(this SchemaContext context)
}
var className = id.ToClassName();
-
+
// Special case for anyOf/oneOf/allOf with a single non-basic type
if (context.Hint is Hint.AnyOf or Hint.OneOf or Hint.AllOf &&
context.Parent?.Children
@@ -89,7 +89,7 @@ public static string ComputeClassName(this SchemaContext context)
{
className = $"{context.Parent?.ComputeClassName()}";
}
-
+
// Special case for anyOf/oneOf/allOf with a single Enum type without reference
else if (context.Hint is Hint.AnyOf or Hint.OneOf or Hint.AllOf &&
context.Parent?.Children
@@ -98,27 +98,27 @@ public static string ComputeClassName(this SchemaContext context)
var variantName = ComputeHelperName(context)!;
className = className.Substring(0, className.Length - variantName.Length) + "Enum";
}
-
+
// Special case for array items with pluralized property name
if (context.Hint is Hint.ArrayItem &&
className.EndsWith("sItem", StringComparison.Ordinal))
{
className = className.Substring(0, className.Length - 5);
}
-
+
return className;
}
-
+
public static string ComputeId(SchemaContext context)
{
context = context ?? throw new ArgumentNullException(nameof(context));
-
+
context.ClassName = CSharpPropertyNameGenerator.SanitizeName(context.ComputeClassName(), context.Settings.ClsCompliantEnumPrefix);
context.Id = context.ClassName;
-
+
return context.Id;
}
-
+
public static void ResolveCollisions(IReadOnlyCollection contexts)
{
while (true)
@@ -133,7 +133,7 @@ public static void ResolveCollisions(IReadOnlyCollection contexts
{
break;
}
-
+
foreach (var group in contextsWithCollision)
{
var i = 2;
@@ -144,7 +144,7 @@ public static void ResolveCollisions(IReadOnlyCollection contexts
}
}
}
-
+
public static void ResolveCollisions(IReadOnlyCollection contexts)
{
while (true)
@@ -157,7 +157,7 @@ public static void ResolveCollisions(IReadOnlyCollection conte
{
break;
}
-
+
foreach (var group in schemasWithCollision)
{
var i = 2;
diff --git a/src/libs/AutoSDK/Naming/Properties/PropertyNameGenerator.cs b/src/libs/AutoSDK/Naming/Properties/PropertyNameGenerator.cs
index a36007a806..6a68154916 100644
--- a/src/libs/AutoSDK/Naming/Properties/PropertyNameGenerator.cs
+++ b/src/libs/AutoSDK/Naming/Properties/PropertyNameGenerator.cs
@@ -12,7 +12,7 @@ public static string ComputePropertyName(
var propertyName = context.PropertyName ?? throw new InvalidOperationException("Property name or parameter name is required.");
var name = propertyName.ToPropertyName();
-
+
name = HandleWordSeparators(name);
if (context.Parent != null)
@@ -24,7 +24,7 @@ public static string ComputePropertyName(
return name;
}
-
+
internal static string SanitizeName(string? name, string clsCompliantEnumPrefix, bool skipHandlingWordSeparators = false)
{
static bool InvalidFirstChar(char ch)
@@ -37,7 +37,7 @@ static bool InvalidSubsequentChar(char ch)
or >= 'a' and <= 'z'
or >= '0' and <= '9'
);
-
+
if (name is null || name.Length == 0)
{
return "";
@@ -54,7 +54,7 @@ static bool InvalidSubsequentChar(char ch)
? "_"
: clsCompliantEnumPrefix;
}
-
+
if (InvalidFirstChar(name[0]))
{
name = (string.IsNullOrWhiteSpace(clsCompliantEnumPrefix)
@@ -69,7 +69,7 @@ static bool InvalidSubsequentChar(char ch)
Span buf = stackalloc char[name.Length];
name.AsSpan().CopyTo(buf);
-
+
for (var i = 1; i < buf.Length; i++)
{
if (InvalidSubsequentChar(buf[i]))
@@ -86,20 +86,33 @@ internal static string HandleWordSeparators(string name)
{
return name
.ReplacePlusAndMinusOnStart()
- .UseWordSeparator('_', '+', '-', '.', '/', '(', '[', ']', ')');
+ .UseWordSeparator('_', '+', '-', '/', '(', '[', ']', ')');
}
- internal static string ToCSharpName(this string text, Settings settings, SchemaContext? parent)
+ ///
+ /// Parses the text and returns a C# namespace and a name.
+ /// The namespace is onyl the part of the namespace that is maybe used inside the openapi spec.
+ /// It doesn't include the namespace that is defined in the settings.
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static (string, string) ToCSharpName(this string text, Settings settings, SchemaContext? parent)
{
- var name = text.ToPropertyName();
-
- name = HandleWordSeparators(name);
-
- if (parent != null)
- {
- name = name.FixPropertyName(parent.Id);
- }
-
- return SanitizeName(name, settings.ClsCompliantEnumPrefix, true);
+ //var name = text.ToPropertyName();
+
+ //var name = HandleWordSeparators(text);
+
+ //if (parent != null)
+ //{
+ //name = name.FixPropertyName(parent.Id);
+ //}
+ var name = text;
+ var splittedName = name.Split('.');
+ return (
+ SanitizeName(string.Join(".", splittedName), string.Empty, true),
+ SanitizeName(splittedName.Last(), settings.ClsCompliantEnumPrefix, true)
+ );
}
}
\ No newline at end of file
diff --git a/src/libs/AutoSDK/Sources/Data.cs b/src/libs/AutoSDK/Sources/Data.cs
index 9c073c24a9..a8c755a4c6 100644
--- a/src/libs/AutoSDK/Sources/Data.cs
+++ b/src/libs/AutoSDK/Sources/Data.cs
@@ -1,12 +1,12 @@
-using System.Collections.Immutable;
-using System.Diagnostics;
-using Microsoft.OpenApi.Models;
-using AutoSDK.Extensions;
+using AutoSDK.Extensions;
using AutoSDK.Helpers;
using AutoSDK.Models;
using AutoSDK.Naming.Clients;
using AutoSDK.Naming.Models;
using AutoSDK.Serialization.Json;
+using Microsoft.OpenApi.Models;
+using System.Collections.Immutable;
+using System.Diagnostics;
namespace AutoSDK.Generation;
@@ -18,15 +18,15 @@ public static Models.Data Prepare(
{
var totalTime = Stopwatch.StartNew();
var traversalTreeTime = Stopwatch.StartNew();
-
+
var (text, settings) = tuple;
var openApiDocument = text.GetOpenApiDocument(settings, cancellationToken);
var schemas = openApiDocument.GetSchemas(settings);
-
+
traversalTreeTime.Stop();
-
+
var namingTime = Stopwatch.StartNew();
foreach (var schema in schemas.Where(x => x.IsModel))
@@ -35,26 +35,26 @@ public static Models.Data Prepare(
}
ModelNameGenerator.ResolveCollisions(schemas);
-
+
namingTime.Stop();
-
+
var resolveReferencesTime = Stopwatch.StartNew();
-
+
var componentSchemas = schemas
.Where(x => x.IsComponent)
.ToDictionary(x => x.ComponentId!, x => x);
-
+
foreach (var context in schemas.Where(x => x.IsReference))
{
context.ResolvedReference = componentSchemas[context.ReferenceId!];
context.Id = context.ResolvedReference.Id;
context.TypeData = context.ResolvedReference.TypeData;
-
+
context.ResolvedReference.Links.Add(context);
}
-
+
resolveReferencesTime.Stop();
-
+
var filteringTime = Stopwatch.StartNew();
var includedOperationIds = new HashSet(settings.IncludeOperationIds);
@@ -67,7 +67,7 @@ public static Models.Data Prepare(
{
excludedOperationIds.UnionWith(openApiDocument.FindAllOperationIdsForTag(tag));
}
-
+
// Find all tags used in operations besides the ones defined in the document
var allTags = openApiDocument.Tags!;
foreach (var operation in openApiDocument.Paths!
@@ -83,7 +83,7 @@ public static Models.Data Prepare(
}
}
}
-
+
if (settings.GroupByTags && allTags.Count < 2)
{
settings = settings with
@@ -103,49 +103,58 @@ public static Models.Data Prepare(
{
context.ComputeTags(maxDepth: maxDepth);
}
-
+
var includedModels = new HashSet(settings.IncludeModels);
var excludedModels = new HashSet(settings.ExcludeModels);
-
+
var isFilteringRequired = settings.IncludeTags.Length > 0 ||
settings.ExcludeTags.Length > 0 ||
includedModels.Count > 0 ||
excludedModels.Count > 0 ||
!settings.GenerateModels;
+
var filteredSchemas = isFilteringRequired
? schemas
.Where(x =>
- (settings.GenerateModels ||
- settings.GenerateSdk ||
- (x.Operation?.OperationId != null && includedOperationIds.Contains(x.Operation.OperationId))) &&
- (settings.IncludeTags.Length == 0 ||
- x.HasAnyTag(settings.IncludeTags.ToArray())) &&
- !x.HasAnyTag(settings.ExcludeTags.ToArray()) &&
- (!x.IsComponent && includedModels.Count == 0 ||
+ settings.GenerateModels ||
+ settings.GenerateSdk ||
+ (x.Operation?.OperationId != null && includedOperationIds.Contains(x.Operation.OperationId))
+ )
+ .Where(x =>
+ settings.IncludeTags.Length == 0 ||
+ x.HasAnyTag(settings.IncludeTags.ToArray())
+ )
+ .Where(x =>
+ settings.ExcludeTags.Length == 0 ||
+ !x.HasAnyTag(settings.ExcludeTags.ToArray())
+ )
+ .SelectMany(x => x.WithAllChildren())
+ .Where(x =>
+ !x.IsComponent && includedModels.Count == 0 ||
(includedModels.Count == 0 ||
includedModels.Contains(x.ComponentId!)) &&
- !excludedModels.Contains(x.ComponentId!)))
- .SelectMany(x => x.WithAllChildren())
+ !excludedModels.Contains(x.ComponentId!)
+ )
.Distinct()
.ToArray()
: schemas;
filteredSchemas = filteredSchemas
.Where(x => !x.HasAllOfTypeForMetadata())
.ToArray();
-
+
filteringTime.Stop();
-
+
var computeDataTime = Stopwatch.StartNew();
foreach (var schema in filteredSchemas)
{
schema.ComputeData();
}
-
+
computeDataTime.Stop();
-
+
var computeDataClassesTime = Stopwatch.StartNew();
-
+
var classes = filteredSchemas
.Where(x => x is { IsReference: false, IsAnyOfLikeStructure: false })
.Select(x => x.ClassData)
@@ -168,7 +177,7 @@ public static Models.Data Prepare(
var operations = openApiDocument.GetOperations(settings, filteredSchemas);
ModelNameGenerator.ResolveCollisions(operations);
-
+
var filteredOperations = settings.GenerateSdk || settings.GenerateMethods
? operations
.Where(operation =>
@@ -182,7 +191,7 @@ public static Models.Data Prepare(
{
return true;
}
-
+
return (includedOperationIds.Count == 0 ||
includedOperationIds.Contains(operation.MethodName) ||
(operation.Operation.OperationId != null && includedOperationIds.Contains(operation.Operation.OperationId))) &&
@@ -191,7 +200,7 @@ public static Models.Data Prepare(
})
.ToArray()
: [];
-
+
var methods = filteredOperations
.Select(EndPoint.FromSchema)
.ToImmutableArray();
@@ -223,8 +232,7 @@ public static Models.Data Prepare(
x.Settings.JsonSerializerType == JsonSerializerType.SystemTextJson &&
x.AnyOfData.HasValue &&
string.IsNullOrWhiteSpace(x.AnyOfData.Value.Name))
- .Select(x => $"global::{settings.Namespace}.JsonConverters.{x.AnyOfData?.SubType}JsonConverter<{
- string.Join(", ", x.Children
+ .Select(x => $"global::{settings.Namespace}.JsonConverters.{x.AnyOfData?.SubType}JsonConverter<{string.Join(", ", x.Children
.Where(y => y.Hint is Hint.AnyOf or Hint.OneOf or Hint.AllOf)
.Select(y => y.TypeData.CSharpTypeWithNullabilityForValueTypes))}>"))
// Unix Timestamp converter
@@ -232,7 +240,7 @@ public static Models.Data Prepare(
$"global::{settings.Namespace}.JsonConverters.UnixTimestampJsonConverter",
])
.ToImmutableArray();
-
+
var includedTags = allTags
.Where(x =>
(settings.IncludeTags.Length == 0 ||
@@ -277,7 +285,7 @@ .. includedTags.Select(tag => PropertyData.Default with
Converters: [])))
.ToArray();
}
-
+
var types =
settings.GenerateJsonSerializerContextTypes
? filteredSchemas
@@ -289,7 +297,7 @@ .. includedTags.Select(tag => PropertyData.Default with
.Select(x => x.First())
.ToImmutableArray()
: [];
-
+
classes = classes
.Select(x => x with
{
@@ -302,7 +310,7 @@ .. includedTags.Select(tag => PropertyData.Default with
SchemaContext = default!,
})
.ToImmutableArray();
-
+
return new Models.Data(
Classes: classes,
Enums: enums,
diff --git a/src/tests/AutoSDK.GeneratorTests/AutoSDK.GeneratorTests.csproj b/src/tests/AutoSDK.GeneratorTests/AutoSDK.GeneratorTests.csproj
new file mode 100644
index 0000000000..692c8a528c
--- /dev/null
+++ b/src/tests/AutoSDK.GeneratorTests/AutoSDK.GeneratorTests.csproj
@@ -0,0 +1,33 @@
+
+
+
+ net9.0
+ latest
+ enable
+ enable
+
+ true
+ AllMicrosoft
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/tests/AutoSDK.GeneratorTests/GenerationTests.cs b/src/tests/AutoSDK.GeneratorTests/GenerationTests.cs
new file mode 100644
index 0000000000..f46ebf2da3
--- /dev/null
+++ b/src/tests/AutoSDK.GeneratorTests/GenerationTests.cs
@@ -0,0 +1,74 @@
+using AutoSDK.GeneratorTests.Helpers;
+using AutoSDK.Models;
+using AutoSDK.SourceGenerators;
+using FluentAssertions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Immutable;
+
+namespace AutoSDK.GeneratorTests;
+
+[TestClass]
+public partial class GenerationTests
+{
+ [TestMethod]
+ public async Task ExcludeModelsAsync()
+ {
+ var compilation = CSharpCompilation.Create(
+ "compilation",
+ [
+ SyntaxFactory.ParseSyntaxTree("[assembly: System.CLSCompliantAttribute(true)]"),
+ ],
+ await H.Generators.Tests.Extensions.LatestReferenceAssemblies.Net90.ResolveAsync(null, CancellationToken.None),
+ new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
+
+ var openApiSpec = new CustomAdditionalText(
+ "petstore.yaml",
+ new H.Resource("petstore.yaml").AsString());
+ openApiSpec.Options.Add("OpenApiSpecification", "true");
+ var additionalFiles = new[] { openApiSpec }.ToImmutableArray();
+ var optionsProvider = new AdditionalTextOptionsProvider(new()
+ {
+ [nameof(Settings.ExcludeModels)] = "PetStore.Pet;",
+ [nameof(Settings.Namespace)] = "TestNamespace",
+ [nameof(Settings.ClassName)] = "PetClient",
+ });
+
+ var driver = CSharpGeneratorDriver.Create(
+ new IIncrementalGenerator[] { new SdkGenerator() }
+ .Select(GeneratorExtensions.AsSourceGenerator)
+ .ToArray())
+ .AddAdditionalTexts(additionalFiles);
+ driver = driver.WithUpdatedAnalyzerConfigOptions(optionsProvider);
+
+ driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var diagnostics);
+ var generatedClasses = outputCompilation.SyntaxTrees
+ .SelectMany(x => x.GetRoot().DescendantNodes())
+ .OfType()
+ .SelectMany(x => x.Members.OfType())
+ .ToArray();
+ generatedClasses.Where(c => c.Identifier.Text == "Pet").Should().BeEmpty();
+
+ // If a model is excluded, it should be refered with global usings, because their is no easy way to find the model.
+ generatedClasses.Select(c => c.Members.OfType())
+ .SelectMany(x => x)
+ .Where(m =>
+ {
+ var symbole = outputCompilation.GetSemanticModel(m.SyntaxTree).GetSymbolInfo(m.ReturnType).Symbol as INamedTypeSymbol;
+ if (symbole is null)
+ {
+ return false;
+ }
+ var listSymbole = symbole.TypeArguments.FirstOrDefault() as INamedTypeSymbol;
+ var petType = listSymbole?.TypeArguments.FirstOrDefault();
+ if (petType is null)
+ {
+ return false;
+ }
+ return petType.ContainingNamespace.Name.StartsWith("TestNamespace") &&
+ petType.Name == "Pet";
+ })
+ .Should().BeEmpty();
+ }
+}
diff --git a/src/tests/AutoSDK.GeneratorTests/Helpers/AdditionalTextOptionsProvider.cs b/src/tests/AutoSDK.GeneratorTests/Helpers/AdditionalTextOptionsProvider.cs
new file mode 100644
index 0000000000..f39c92c73c
--- /dev/null
+++ b/src/tests/AutoSDK.GeneratorTests/Helpers/AdditionalTextOptionsProvider.cs
@@ -0,0 +1,45 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace AutoSDK.GeneratorTests.Helpers;
+
+public class AdditionalTextOptionsProvider : AnalyzerConfigOptionsProvider
+{
+ private readonly Dictionary globalOptions = [];
+
+ public AdditionalTextOptionsProvider(Dictionary? globalOptions = null)
+ {
+ if (globalOptions is not null && globalOptions.Count != 0)
+ {
+ this.globalOptions = globalOptions.
+ ToDictionary(
+ k => $"build_property.AutoSDK_{k.Key}",
+ v => v.Value
+ );
+ }
+ }
+ public override AnalyzerConfigOptions GlobalOptions => new DictionaryAnalyzerConfigOptions(globalOptions);
+
+ //
+ // Summary:
+ // Gets options for a given file.
+ public override AnalyzerConfigOptions GetOptions(AdditionalText textFile)
+ {
+ if (textFile is not CustomAdditionalText customTextFile)
+ {
+ throw new ArgumentException("Invalid type", nameof(textFile));
+ }
+ return new DictionaryAnalyzerConfigOptions(
+ customTextFile.Options
+ .ToDictionary(
+ k => $"build_metadata.AdditionalFiles.AutoSDK_{k.Key}",
+ v => v.Value
+ )
+ );
+ }
+
+ public override AnalyzerConfigOptions GetOptions(SyntaxTree tree)
+ {
+ return new DictionaryAnalyzerConfigOptions([]);
+ }
+}
diff --git a/src/tests/AutoSDK.GeneratorTests/Helpers/CSharpIncrementalSourceGeneratorVerifier.cs b/src/tests/AutoSDK.GeneratorTests/Helpers/CSharpIncrementalSourceGeneratorVerifier.cs
new file mode 100644
index 0000000000..5ecf6a43a6
--- /dev/null
+++ b/src/tests/AutoSDK.GeneratorTests/Helpers/CSharpIncrementalSourceGeneratorVerifier.cs
@@ -0,0 +1,41 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Testing;
+using System.Collections.Immutable;
+
+namespace AutoSDK.GeneratorTests.Helpers;
+
+internal static class CSharpIncrementalSourceGeneratorVerifier
+ where TSourceGenerator : IIncrementalGenerator, new()
+{
+ public class Test : CSharpSourceGeneratorTest
+ {
+ public Test()
+ {
+ }
+
+ protected override CompilationOptions CreateCompilationOptions()
+ {
+ var compilationOptions = base.CreateCompilationOptions();
+ return compilationOptions.WithSpecificDiagnosticOptions(
+ compilationOptions.SpecificDiagnosticOptions.SetItems(GetNullableWarningsFromCompiler()));
+ }
+
+ public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default;
+
+ private static ImmutableDictionary GetNullableWarningsFromCompiler()
+ {
+ string[] args = { "/warnaserror:nullable" };
+ var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory);
+ var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
+
+ return nullableWarnings;
+ }
+
+ protected override ParseOptions CreateParseOptions()
+ {
+ return ((CSharpParseOptions)base.CreateParseOptions()).WithLanguageVersion(LanguageVersion);
+ }
+ }
+}
diff --git a/src/tests/AutoSDK.GeneratorTests/Helpers/CustomAdditionalText.cs b/src/tests/AutoSDK.GeneratorTests/Helpers/CustomAdditionalText.cs
new file mode 100644
index 0000000000..f5ef81aa7b
--- /dev/null
+++ b/src/tests/AutoSDK.GeneratorTests/Helpers/CustomAdditionalText.cs
@@ -0,0 +1,18 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+
+namespace AutoSDK.GeneratorTests.Helpers;
+
+public class CustomAdditionalText(string path, string text) : AdditionalText
+{
+ public string Text { get; } = text;
+
+ public override string Path { get; } = path;
+
+ public override SourceText GetText(CancellationToken cancellationToken = default)
+ {
+ return SourceText.From(Text);
+ }
+
+ public Dictionary Options { get; } = new Dictionary();
+}
diff --git a/src/tests/AutoSDK.GeneratorTests/Helpers/DictionaryAnalyzerConfigOptions.cs b/src/tests/AutoSDK.GeneratorTests/Helpers/DictionaryAnalyzerConfigOptions.cs
new file mode 100644
index 0000000000..6bb37f48f5
--- /dev/null
+++ b/src/tests/AutoSDK.GeneratorTests/Helpers/DictionaryAnalyzerConfigOptions.cs
@@ -0,0 +1,34 @@
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace AutoSDK.GeneratorTests.Helpers;
+
+///
+///
+///
+public sealed class DictionaryAnalyzerConfigOptions : AnalyzerConfigOptions
+{
+ private Dictionary Properties { get; }
+
+ ///
+ ///
+ ///
+ ///
+ public DictionaryAnalyzerConfigOptions(Dictionary properties)
+ {
+ Properties = properties;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool TryGetValue(string key, out string value)
+ {
+ var result = Properties.TryGetValue(key, out var newValue);
+ value = newValue ?? string.Empty;
+
+ return result;
+ }
+}
diff --git a/src/tests/AutoSDK.GeneratorTests/MSTestSettings.cs b/src/tests/AutoSDK.GeneratorTests/MSTestSettings.cs
new file mode 100644
index 0000000000..aaf278c844
--- /dev/null
+++ b/src/tests/AutoSDK.GeneratorTests/MSTestSettings.cs
@@ -0,0 +1 @@
+[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
diff --git a/src/tests/AutoSDK.UnitTests/DataTests.cs b/src/tests/AutoSDK.UnitTests/DataTests.cs
index 844b1f3c89..ece630628e 100644
--- a/src/tests/AutoSDK.UnitTests/DataTests.cs
+++ b/src/tests/AutoSDK.UnitTests/DataTests.cs
@@ -1,5 +1,6 @@
using AutoSDK.Generation;
using AutoSDK.Naming.Methods;
+using System.Collections.Immutable;
namespace AutoSDK.UnitTests;
@@ -62,4 +63,26 @@ DefaultSettings with
})),
resourceName: Path.GetFileNameWithoutExtension(resourceName));
}
+
+ [TestMethod]
+ public void ExcludeModels()
+ {
+ var processedSchema = Data.Prepare(
+ (
+ new H.Resource("petstore.yaml").AsString(),
+ DefaultSettings with
+ {
+ GenerateJsonSerializerContextTypes = true,
+ MethodNamingConvention = MethodNamingConvention.OperationIdWithDots,
+ IgnoreOpenApiErrors = true,
+ ExcludeModels = new[] { "Pet" }.ToImmutableArray(),
+
+ }
+ ));
+
+ var result = processedSchema.Classes
+ .Where(x => x.ClassName.Contains("Pet"))
+ .ToArray();
+ Assert.IsEmpty(result);
+ }
}
\ No newline at end of file