diff --git a/.editorconfig b/.editorconfig
index 5c4c2f7..29d599f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -33,7 +33,7 @@ trim_trailing_whitespace = true
# MSBuild project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,props,targets}]
-indent_size = 2
+indent_size = 4
# Xml config files
[*.{ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}]
@@ -84,7 +84,7 @@ dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
# Constants are PascalCase
dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
-dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
+dotnet_naming_rule.constants_should_be_pascal_case.style = non_private_static_field_style
dotnet_naming_symbols.constants.applicable_kinds = field, local
dotnet_naming_symbols.constants.required_modifiers = const
@@ -94,7 +94,7 @@ dotnet_naming_style.constant_style.capitalization = pascal_case
# Static fields are camelCase
dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
-dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
+dotnet_naming_rule.static_fields_should_be_camel_case.style = camel_case_style
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
@@ -104,7 +104,7 @@ dotnet_naming_style.static_field_style.capitalization = camel_case
# Instance fields are camelCase
dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
-dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
+dotnet_naming_rule.instance_fields_should_be_camel_case.style = camel_case_style
dotnet_naming_symbols.instance_fields.applicable_kinds = field
@@ -122,7 +122,7 @@ dotnet_naming_style.camel_case_style.capitalization = camel_case
# Local functions are PascalCase
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
-dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
+dotnet_naming_rule.local_functions_should_be_pascal_case.style = non_private_static_field_style
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
@@ -131,7 +131,7 @@ dotnet_naming_style.local_function_style.capitalization = pascal_case
# By default, name items with PascalCase
dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
-dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
+dotnet_naming_rule.members_should_be_pascal_case.style = non_private_static_field_style
dotnet_naming_symbols.all_members.applicable_kinds = *
@@ -209,6 +209,7 @@ dotnet_diagnostic.SA1130.severity = silent
# IDE1006: Naming Styles - StyleCop handles these for us
dotnet_diagnostic.IDE1006.severity = none
+dotnet_diagnostic.IDE0290.severity = silent
dotnet_diagnostic.DOC100.severity = silent
dotnet_diagnostic.DOC104.severity = warning
@@ -226,7 +227,7 @@ csharp_prefer_simple_using_statement = true:suggestion
csharp_style_namespace_declarations = file_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
-csharp_style_prefer_primary_constructors = true:suggestion
+csharp_style_prefer_primary_constructors = false:silent
csharp_prefer_system_threading_lock = true:suggestion
csharp_style_expression_bodied_lambdas = when_on_single_line:silent
csharp_style_expression_bodied_local_functions = when_on_single_line:silent
diff --git a/.runsettings b/.runsettings
new file mode 100644
index 0000000..b4601e7
--- /dev/null
+++ b/.runsettings
@@ -0,0 +1,11 @@
+
+
+
+
+
+ true
+ false
+ 5
+
+
+
diff --git a/nvim-diff.runsettings b/nvim-diff.runsettings
new file mode 100644
index 0000000..017ba6f
--- /dev/null
+++ b/nvim-diff.runsettings
@@ -0,0 +1,11 @@
+
+
+
+
+ Neovim
+ false
+ false
+ 5
+
+
+
diff --git a/src/SharpSchema.Annotations.Source/SharpSchema.Annotations.Source.csproj b/src/SharpSchema.Annotations.Source/SharpSchema.Annotations.Source.csproj
index 38285dd..ef4752a 100644
--- a/src/SharpSchema.Annotations.Source/SharpSchema.Annotations.Source.csproj
+++ b/src/SharpSchema.Annotations.Source/SharpSchema.Annotations.Source.csproj
@@ -14,4 +14,10 @@
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/src/SharpSchema.Generator/Accessibilities.cs b/src/SharpSchema.Annotations/AccessibilityMode.cs
similarity index 83%
rename from src/SharpSchema.Generator/Accessibilities.cs
rename to src/SharpSchema.Annotations/AccessibilityMode.cs
index 78f45f9..2dadef7 100644
--- a/src/SharpSchema.Generator/Accessibilities.cs
+++ b/src/SharpSchema.Annotations/AccessibilityMode.cs
@@ -1,10 +1,17 @@
-namespace SharpSchema.Generator;
+using System;
+
+namespace SharpSchema.Annotations;
///
/// Specifies the allowed accessibilities.
///
[Flags]
-public enum Accessibilities
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+enum AccessibilityMode
{
///
/// Indicates public accessibility.
diff --git a/src/SharpSchema.Generator/DictionaryKeyMode.cs b/src/SharpSchema.Annotations/DictionaryKeyMode.cs
similarity index 84%
rename from src/SharpSchema.Generator/DictionaryKeyMode.cs
rename to src/SharpSchema.Annotations/DictionaryKeyMode.cs
index c1f482e..8ddb3df 100644
--- a/src/SharpSchema.Generator/DictionaryKeyMode.cs
+++ b/src/SharpSchema.Annotations/DictionaryKeyMode.cs
@@ -1,11 +1,16 @@
-using Json.Schema;
-
-namespace SharpSchema.Generator;
+
+namespace SharpSchema.Annotations;
///
/// Specifies the mode for dictionary keys.
///
-public enum DictionaryKeyMode
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+enum DictionaryKeyMode
+
{
///
/// Loose mode allows any type of dictionary key,
diff --git a/src/SharpSchema.Generator/EnumHandling.cs b/src/SharpSchema.Annotations/EnumMode.cs
similarity index 73%
rename from src/SharpSchema.Generator/EnumHandling.cs
rename to src/SharpSchema.Annotations/EnumMode.cs
index 8782410..f284800 100644
--- a/src/SharpSchema.Generator/EnumHandling.cs
+++ b/src/SharpSchema.Annotations/EnumMode.cs
@@ -1,9 +1,14 @@
-namespace SharpSchema.Generator;
+namespace SharpSchema.Annotations;
///
/// Specifies how enums are handled in the generated code.
///
-public enum EnumHandling
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+enum EnumMode
{
///
/// Enum values are represented as strings.
diff --git a/src/SharpSchema.Annotations/GeneratorOptions.cs b/src/SharpSchema.Annotations/GeneratorOptions.cs
new file mode 100644
index 0000000..188e71e
--- /dev/null
+++ b/src/SharpSchema.Annotations/GeneratorOptions.cs
@@ -0,0 +1,42 @@
+using SharpSchema.Annotations;
+
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+namespace SharpSchema.Generator;
+#pragma warning restore IDE0130 // Namespace does not match folder structure
+
+///
+/// Represents the options for the generator.
+///
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+record GeneratorOptions(
+ AccessibilityMode AccessibilityMode = AccessibilityMode.Public,
+ TraversalMode TraversalMode = TraversalMode.Bases,
+ DictionaryKeyMode DictionaryKeyMode = DictionaryKeyMode.Loose,
+ EnumMode EnumMode = EnumMode.String,
+ NumberMode NumberMode = NumberMode.StrictDefs)
+{
+ ///
+ /// Initializes a new instance of the class by copying the values from another instance.
+ ///
+ /// The instance to copy values from.
+ public GeneratorOptions(GeneratorOptions options)
+ {
+ if (options is null)
+ throw new System.ArgumentNullException(nameof(options));
+
+ AccessibilityMode = options.AccessibilityMode;
+ TraversalMode = options.TraversalMode;
+ DictionaryKeyMode = options.DictionaryKeyMode;
+ EnumMode = options.EnumMode;
+ NumberMode = options.NumberMode;
+ }
+
+ ///
+ /// Gets the default generator options.
+ ///
+ public static GeneratorOptions Default { get; } = new GeneratorOptions();
+}
diff --git a/src/SharpSchema.Annotations/NumberMode.cs b/src/SharpSchema.Annotations/NumberMode.cs
new file mode 100644
index 0000000..0c1d0ce
--- /dev/null
+++ b/src/SharpSchema.Annotations/NumberMode.cs
@@ -0,0 +1,29 @@
+namespace SharpSchema.Annotations;
+
+///
+/// Specifies the mode for handling numeric types in the schema generation.
+///
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+enum NumberMode
+{
+ ///
+ /// Uses the best matching type for numbers, adding range validation based on .NET type.
+ /// Numeric subschema placed in $defs, and referenced inline.
+ ///
+ StrictDefs,
+
+ ///
+ /// Uses the best matching type for numbers, adding range validation based on .NET type.
+ /// Numeric subschema are always placed inline.
+ ///
+ StrictInline,
+
+ ///
+ /// Uses the best matching json type for numbers, without adding range validation.
+ ///
+ JsonNative,
+}
diff --git a/src/SharpSchema.Annotations/SchemaAccessibilityModeAttribute.cs b/src/SharpSchema.Annotations/SchemaAccessibilityModeAttribute.cs
new file mode 100644
index 0000000..f068991
--- /dev/null
+++ b/src/SharpSchema.Annotations/SchemaAccessibilityModeAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+
+#nullable enable
+
+namespace SharpSchema.Annotations;
+
+///
+/// Overrides the default traversal option for a given type.
+///
+[AttributeUsage(SchemaAttribute.SupportedTypes)]
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+class SchemaAccessibilityModeAttribute(AccessibilityMode value) : SchemaAttribute
+{
+ ///
+ /// Gets the accessibility option for the type.
+ ///
+ public AccessibilityMode Value { get; } = value;
+}
diff --git a/src/SharpSchema.Annotations/SchemaConstAttribute.cs b/src/SharpSchema.Annotations/SchemaConstAttribute.cs
index b522bbd..1c7d178 100644
--- a/src/SharpSchema.Annotations/SchemaConstAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaConstAttribute.cs
@@ -9,10 +9,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaConstAttribute(object value) : SchemaAttribute
+public
#else
-internal class SchemaConstAttribute(object value) : SchemaAttribute
+internal
#endif
+class SchemaConstAttribute(object value) : SchemaAttribute
{
///
/// Gets the constant value.
diff --git a/src/SharpSchema.Annotations/SchemaDictionaryKeyModeAttribute.cs b/src/SharpSchema.Annotations/SchemaDictionaryKeyModeAttribute.cs
new file mode 100644
index 0000000..3740bfc
--- /dev/null
+++ b/src/SharpSchema.Annotations/SchemaDictionaryKeyModeAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+
+#nullable enable
+
+namespace SharpSchema.Annotations;
+
+///
+/// Overrides the default dictionary key mode for a given type.
+///
+[AttributeUsage(SchemaAttribute.SupportedMembers)]
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+class SchemaDictionaryKeyModeAttribute(DictionaryKeyMode value) : SchemaAttribute
+{
+ ///
+ /// Gets the dictionary key mode.
+ ///
+ public DictionaryKeyMode Value { get; } = value;
+}
diff --git a/src/SharpSchema.Annotations/SchemaEnumModeAttribute.cs b/src/SharpSchema.Annotations/SchemaEnumModeAttribute.cs
new file mode 100644
index 0000000..87e8b8f
--- /dev/null
+++ b/src/SharpSchema.Annotations/SchemaEnumModeAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+
+#nullable enable
+
+namespace SharpSchema.Annotations;
+
+///
+/// Overrides the default enum mode for a given type.
+///
+[AttributeUsage(AttributeTargets.Enum)]
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+class SchemaEnumModeAttribute(EnumMode value) : SchemaAttribute
+{
+ ///
+ /// Gets the enum mode.
+ ///
+ public EnumMode Value { get; } = value;
+}
diff --git a/src/SharpSchema.Annotations/SchemaEnumValueAttribute.cs b/src/SharpSchema.Annotations/SchemaEnumValueAttribute.cs
index 308ef9c..a965168 100644
--- a/src/SharpSchema.Annotations/SchemaEnumValueAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaEnumValueAttribute.cs
@@ -9,10 +9,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(AttributeTargets.Field)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaEnumValueAttribute(string value) : SchemaAttribute
+public
#else
-internal class SchemaEnumValueAttribute(string value) : SchemaAttribute
+internal
#endif
+class SchemaEnumValueAttribute(string value) : SchemaAttribute
{
///
/// Gets the value of the enum member.
diff --git a/src/SharpSchema.Annotations/SchemaFormatAttribute.cs b/src/SharpSchema.Annotations/SchemaFormatAttribute.cs
index 179ccc5..5e488d6 100644
--- a/src/SharpSchema.Annotations/SchemaFormatAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaFormatAttribute.cs
@@ -12,10 +12,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaFormatAttribute(string format) : SchemaAttribute
+public
#else
-internal class SchemaFormatAttribute(string format) : SchemaAttribute
+internal
#endif
+class SchemaFormatAttribute(string format) : SchemaAttribute
{
///
/// Gets the format of the schema.
diff --git a/src/SharpSchema.Annotations/SchemaIgnoreAttribute.cs b/src/SharpSchema.Annotations/SchemaIgnoreAttribute.cs
index b4b65f6..7243e7a 100644
--- a/src/SharpSchema.Annotations/SchemaIgnoreAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaIgnoreAttribute.cs
@@ -9,9 +9,10 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedTypes | SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaIgnoreAttribute : SchemaAttribute
+public
#else
-internal class SchemaIgnoreAttribute : SchemaAttribute
+internal
#endif
+class SchemaIgnoreAttribute : SchemaAttribute
{
}
diff --git a/src/SharpSchema.Annotations/SchemaItemsRangeAttribute.cs b/src/SharpSchema.Annotations/SchemaItemsRangeAttribute.cs
index 4ac058f..3fa2c08 100644
--- a/src/SharpSchema.Annotations/SchemaItemsRangeAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaItemsRangeAttribute.cs
@@ -12,10 +12,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaItemsRangeAttribute : SchemaAttribute
+public
#else
-internal class SchemaItemsRangeAttribute : SchemaAttribute
+internal
#endif
+class SchemaItemsRangeAttribute : SchemaAttribute
{
///
/// Gets or sets the minimum items allowed for the array.
diff --git a/src/SharpSchema.Annotations/SchemaLengthRangeAttribute.cs b/src/SharpSchema.Annotations/SchemaLengthRangeAttribute.cs
index 771753b..a35967e 100644
--- a/src/SharpSchema.Annotations/SchemaLengthRangeAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaLengthRangeAttribute.cs
@@ -12,10 +12,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaLengthRangeAttribute : SchemaAttribute
+public
#else
-internal class SchemaLengthRangeAttribute : SchemaAttribute
+internal
#endif
+class SchemaLengthRangeAttribute : SchemaAttribute
{
///
/// Gets or sets the minimum length allowed for the schema.
diff --git a/src/SharpSchema.Annotations/SchemaMetaAttribute.cs b/src/SharpSchema.Annotations/SchemaMetaAttribute.cs
index 30abe25..7c40a77 100644
--- a/src/SharpSchema.Annotations/SchemaMetaAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaMetaAttribute.cs
@@ -11,10 +11,11 @@ namespace SharpSchema.Annotations;
[ExcludeFromCodeCoverage]
[AttributeUsage(SupportedTypes | SupportedMembers | EnumTargets)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaMetaAttribute : SchemaAttribute
+public
#else
-internal class SchemaMetaAttribute : SchemaAttribute
+internal
#endif
+class SchemaMetaAttribute : SchemaAttribute
{
///
/// Gets or sets the title of the schema.
diff --git a/src/SharpSchema.Annotations/SchemaOverrideAttribute.cs b/src/SharpSchema.Annotations/SchemaOverrideAttribute.cs
index 165baa6..16ce9f6 100644
--- a/src/SharpSchema.Annotations/SchemaOverrideAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaOverrideAttribute.cs
@@ -12,10 +12,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedTypes | SupportedMembers | EnumTargets)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaOverrideAttribute(string value) : SchemaAttribute
+public
#else
-internal class SchemaOverrideAttribute(string value) : SchemaAttribute
+internal
#endif
+class SchemaOverrideAttribute(string value) : SchemaAttribute
{
///
/// Gets the overridden value for the schema.
diff --git a/src/SharpSchema.Annotations/SchemaPropertiesRangeAttribute.cs b/src/SharpSchema.Annotations/SchemaPropertiesRangeAttribute.cs
index 4468348..0c0d375 100644
--- a/src/SharpSchema.Annotations/SchemaPropertiesRangeAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaPropertiesRangeAttribute.cs
@@ -12,10 +12,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedTypes | SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaPropertiesRangeAttribute : SchemaAttribute
+public
#else
-internal class SchemaPropertiesRangeAttribute : SchemaAttribute
+internal
#endif
+class SchemaPropertiesRangeAttribute : SchemaAttribute
{
///
/// Gets or sets the minimum number of properties allowed in a schema.
diff --git a/src/SharpSchema.Annotations/SchemaRegexAttribute.cs b/src/SharpSchema.Annotations/SchemaRegexAttribute.cs
index e721548..953895b 100644
--- a/src/SharpSchema.Annotations/SchemaRegexAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaRegexAttribute.cs
@@ -12,10 +12,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaRegexAttribute(string pattern) : SchemaAttribute
+public
#else
-internal class SchemaRegexAttribute(string pattern) : SchemaAttribute
+internal
#endif
+class SchemaRegexAttribute(string pattern) : SchemaAttribute
{
///
/// Gets the regular expression pattern.
diff --git a/src/SharpSchema.Annotations/SchemaRequiredAttribute.cs b/src/SharpSchema.Annotations/SchemaRequiredAttribute.cs
index d0bce15..4f8b0d3 100644
--- a/src/SharpSchema.Annotations/SchemaRequiredAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaRequiredAttribute.cs
@@ -9,10 +9,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaRequiredAttribute(bool isRequired = true) : SchemaAttribute
+public
#else
-internal class SchemaRequiredAttribute(bool isRequired = true) : SchemaAttribute
+internal
#endif
+class SchemaRequiredAttribute(bool isRequired = true) : SchemaAttribute
{
///
/// Gets a value indicating whether the property is required.
diff --git a/src/SharpSchema.Annotations/SchemaRootAttribute.cs b/src/SharpSchema.Annotations/SchemaRootAttribute.cs
index 550b1b9..fa2e4fe 100644
--- a/src/SharpSchema.Annotations/SchemaRootAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaRootAttribute.cs
@@ -9,10 +9,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedTypes)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaRootAttribute : SchemaAttribute
+public
#else
-internal class SchemaRootAttribute : SchemaAttribute
+internal
#endif
+class SchemaRootAttribute : SchemaAttribute
{
///
/// Gets or sets the file name of the schema.
diff --git a/src/SharpSchema.Annotations/SchemaTraversalModeAttribute.cs b/src/SharpSchema.Annotations/SchemaTraversalModeAttribute.cs
new file mode 100644
index 0000000..7474f56
--- /dev/null
+++ b/src/SharpSchema.Annotations/SchemaTraversalModeAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+
+#nullable enable
+
+namespace SharpSchema.Annotations;
+
+///
+/// Overrides the default traversal option for a given type.
+///
+[AttributeUsage(SchemaAttribute.SupportedTypes)]
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+class SchemaTraversalModeAttribute(TraversalMode value) : SchemaAttribute
+{
+ ///
+ /// Gets the traversal option for the type.
+ ///
+ public TraversalMode Value { get; } = value;
+}
diff --git a/src/SharpSchema.Annotations/SchemaValueRangeAttribute.cs b/src/SharpSchema.Annotations/SchemaValueRangeAttribute.cs
index 709e9f2..e1045e0 100644
--- a/src/SharpSchema.Annotations/SchemaValueRangeAttribute.cs
+++ b/src/SharpSchema.Annotations/SchemaValueRangeAttribute.cs
@@ -12,10 +12,11 @@ namespace SharpSchema.Annotations;
///
[AttributeUsage(SupportedMembers)]
#if SHARPSCHEMA_ASSEMBLY
-public class SchemaValueRangeAttribute : SchemaAttribute
+public
#else
-internal class SchemaValueRangeAttribute : SchemaAttribute
+internal
#endif
+class SchemaValueRangeAttribute : SchemaAttribute
{
///
/// Gets or sets the minimum value allowed for the property.
diff --git a/src/SharpSchema.Annotations/SharpSchema.Annotations.csproj b/src/SharpSchema.Annotations/SharpSchema.Annotations.csproj
index 1a8ef26..7235686 100644
--- a/src/SharpSchema.Annotations/SharpSchema.Annotations.csproj
+++ b/src/SharpSchema.Annotations/SharpSchema.Annotations.csproj
@@ -8,4 +8,10 @@
Annotations library for the SharpSchema project.
SHARPSCHEMA_ASSEMBLY
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/src/SharpSchema.Generator/Traversal.cs b/src/SharpSchema.Annotations/TraversalMode.cs
similarity index 80%
rename from src/SharpSchema.Generator/Traversal.cs
rename to src/SharpSchema.Annotations/TraversalMode.cs
index d11bd1c..46c9c1c 100644
--- a/src/SharpSchema.Generator/Traversal.cs
+++ b/src/SharpSchema.Annotations/TraversalMode.cs
@@ -1,10 +1,17 @@
-namespace SharpSchema.Generator;
+using System;
+
+namespace SharpSchema.Annotations;
///
/// Specifies the traversal options for symbols.
///
[Flags]
-public enum Traversal
+#if SHARPSCHEMA_ASSEMBLY
+public
+#else
+internal
+#endif
+enum TraversalMode
{
///
/// Traverse only the symbol itself.
diff --git a/src/SharpSchema.Generator/GeneratorOptions.cs b/src/SharpSchema.Generator/GeneratorOptions.cs
deleted file mode 100644
index 8a4a249..0000000
--- a/src/SharpSchema.Generator/GeneratorOptions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace SharpSchema.Generator;
-
-///
-/// The options for the generator.
-///
-/// The accessibilities to consider.
-/// The traversal options.
-/// The mode for dictionary keys.
-/// The options for handling enums.
-public record GeneratorOptions(
- Accessibilities Accessibilities = Accessibilities.Public,
- Traversal Traversal = Traversal.SymbolOnly,
- DictionaryKeyMode DictionaryKeyMode = DictionaryKeyMode.Loose,
- EnumHandling EnumHandling = EnumHandling.String)
-{
- ///
- /// Gets the default generator options.
- ///
- public static GeneratorOptions Default { get; } = new GeneratorOptions();
-}
diff --git a/src/SharpSchema.Generator/GenericTypeSymbolVisitor.cs b/src/SharpSchema.Generator/GenericTypeSymbolVisitor.cs
deleted file mode 100644
index e69de29..0000000
diff --git a/src/SharpSchema.Generator/LeafDeclaredTypeSyntaxVisitor.cs b/src/SharpSchema.Generator/LeafDeclaredTypeSyntaxVisitor.cs
deleted file mode 100644
index a12120f..0000000
--- a/src/SharpSchema.Generator/LeafDeclaredTypeSyntaxVisitor.cs
+++ /dev/null
@@ -1,355 +0,0 @@
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis;
-using SharpSchema.Generator.Utilities;
-using SharpSchema.Generator.Model;
-using Json.Schema;
-using System.Text.Json.Nodes;
-
-namespace SharpSchema.Generator;
-
-using Builder = JsonSchemaBuilder;
-using Metadata = Model.Metadata;
-
-internal class LeafDeclaredTypeSyntaxVisitor : CSharpSyntaxVisitor
-{
- private readonly Compilation _compilation;
- private readonly GeneratorOptions _options;
- private readonly SemanticModelCache _semanticModelCache;
- private readonly Metadata.SymbolVisitor _metadataVisitor;
- private readonly CollectionSymbolVisitor _collectionVisitor;
- private readonly Dictionary _cachedTypeSchemas;
- private readonly Dictionary _cachedBaseSchemas;
-
- public LeafDeclaredTypeSyntaxVisitor(Compilation compilation, GeneratorOptions options)
- {
- _compilation = compilation;
- _options = options;
- _semanticModelCache = new(compilation);
- _metadataVisitor = new();
- _collectionVisitor = new(options, compilation, this);
- _cachedTypeSchemas = [];
- _cachedBaseSchemas = [];
- }
-
- internal GeneratorOptions Options => _options;
-
- public IReadOnlyDictionary? GetCachedSchemas()
- {
- if (_cachedTypeSchemas.Count == 0)
- return null;
-
- return _cachedTypeSchemas.ToDictionary(
- p => p.Key,
- p => p.Value.Build());
- }
-
- public override Builder? Visit(SyntaxNode? node)
- {
- if (node is null)
- return null;
-
- using var trace = Tracer.Enter($"[LEAF] {node.Kind()}");
- return base.Visit(node);
- }
-
- public override Builder? VisitQualifiedName(QualifiedNameSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.ToString());
-
- TypeInfo typeInfo = _semanticModelCache.GetSemanticModel(node).GetTypeInfo(node);
- if (typeInfo.ConvertedType is not ITypeSymbol typeSymbol)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for qualified name '{node}'.");
-
- return this.Visit(typeSymbol.FindBaseTypeDeclaration());
- }
-
- public override Builder? VisitClassDeclaration(ClassDeclarationSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Identifier.Text);
- return VisitTypeDeclaration(node);
- }
-
- public override Builder? VisitStructDeclaration(StructDeclarationSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Identifier.Text);
- return VisitTypeDeclaration(node);
- }
-
- public override Builder? VisitRecordDeclaration(RecordDeclarationSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Identifier.Text);
- return VisitTypeDeclaration(node);
- }
-
- public override Builder? VisitSimpleBaseType(SimpleBaseTypeSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Type.ToString());
- if (node.Type is not IdentifierNameSyntax nameSyntax)
- return CommonSchemas.UnsupportedObject($"The base type syntax is not supported for generation '{node.Type}'.");
-
- if (_semanticModelCache.GetSemanticModel(node).GetTypeInfo(node.Type).Type is not INamedTypeSymbol baseTypeSymbol)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for base type '{node.Type}'.");
-
- string cacheKey = baseTypeSymbol.GetDefCacheKey();
- if (!_cachedBaseSchemas.TryGetValue(cacheKey, out Builder? cachedSchema))
- {
- cachedSchema = baseTypeSymbol.FindTypeDeclaration()?.CreateTypeSchema(this);
- if (cachedSchema is not null)
- {
- _cachedBaseSchemas[cacheKey] = cachedSchema;
- }
- }
-
- return cachedSchema;
- }
-
- public override Builder? VisitEnumDeclaration(EnumDeclarationSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Identifier.Text);
-
- if (node.GetDeclaredSymbol(_semanticModelCache) is not INamedTypeSymbol enumSymbol)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for enum '{node.Identifier}'.");
-
- if (enumSymbol.GetOverrideSchema() is Builder overrideSchema)
- return overrideSchema;
-
- string cacheKey = enumSymbol.GetDefCacheKey();
- if (!_cachedTypeSchemas.TryGetValue(cacheKey, out Builder? cachedSchema))
- {
-
- Metadata metadata = Throw.ForUnexpectedNull(_metadataVisitor.Visit(enumSymbol));
-
- Builder builder = EnumSymbolVisitor.Instance.Visit(enumSymbol, _options) ??
- CommonSchemas.UnsupportedObject($"Failed to build schema for enum '{node.Identifier}'.");
-
- _cachedTypeSchemas[cacheKey] = builder.ApplyMetadata(metadata);
- }
-
- return CommonSchemas.DefRef(cacheKey);
- }
-
- public override Builder? VisitPropertyDeclaration(PropertyDeclarationSyntax node)
- {
- Throw.IfNullArgument(node);
-
- using var trace = Tracer.Enter(node.Identifier.Text);
-
- if (node.GetDeclaredSymbol(_semanticModelCache) is not IPropertySymbol propertySymbol)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for property '{node.Identifier}'.");
-
- if (!_options.ShouldProcess(propertySymbol))
- return null;
-
- if (propertySymbol.GetOverrideSchema() is Builder overrideSchema)
- return overrideSchema;
-
- Metadata metadata = Throw.ForUnexpectedNull(_metadataVisitor.Visit(propertySymbol));
-
- return GetPropertySchema(node.Type, metadata, node.Initializer?.Value);
- }
-
- public override Builder? VisitParameter(ParameterSyntax node)
- {
- Throw.IfNullArgument(node);
-
- using var trace = Tracer.Enter(node.Identifier.Text);
-
- if (node.GetDeclaredSymbol(_semanticModelCache) is not IParameterSymbol parameterSymbol)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for parameter '{node.Identifier}'.");
-
- if (!_options.ShouldProcess(parameterSymbol))
- return null;
-
- if (parameterSymbol.GetOverrideSchema() is Builder overrideSchema)
- return overrideSchema;
-
- Metadata metadata = Throw.ForUnexpectedNull(_metadataVisitor.Visit(parameterSymbol));
-
- TypeSyntax? typeSyntax = node.Type;
- if (typeSyntax is null)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for parameter type '{typeSyntax}'.");
-
- return GetPropertySchema(typeSyntax, metadata, node.Default?.Value);
- }
-
- public override Builder? VisitIdentifierName(IdentifierNameSyntax node)
- {
- Throw.IfNullArgument(node);
-
- using var trace = Tracer.Enter(node.Identifier.Text);
-
- TypeInfo typeInfo = _semanticModelCache.GetSemanticModel(node).GetTypeInfo(node);
- if (typeInfo.ConvertedType is not ITypeSymbol typeSymbol)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for identifier '{node.Identifier}'.");
-
- return this.Visit(typeSymbol.FindBaseTypeDeclaration())
- ?? CommonSchemas.UnsupportedObject($"Could not find declaration for identifier '{node.Identifier}'.");
- }
-
- public override Builder? VisitGenericName(GenericNameSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Identifier.Text);
-
- if (node.IsUnboundGenericName)
- return CommonSchemas.UnsupportedObject($"Failed to evaluate unbound generic type '{node.Identifier}'.");
-
- SemanticModel semanticModel = _semanticModelCache.GetSemanticModel(node);
-
- if (semanticModel.GetTypeInfo(node).Type is not INamedTypeSymbol boundTypeSymbol)
- return CommonSchemas.UnsupportedObject($"Node '{node.Identifier.Text}' does not produce a type symbol.");
-
- Builder? collectionBuilder = _collectionVisitor.Visit(boundTypeSymbol);
- if (collectionBuilder is not null)
- return collectionBuilder;
-
- return this.Visit(boundTypeSymbol.FindTypeDeclaration());
- }
-
- public override Builder? VisitNullableType(NullableTypeSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Kind().ToString());
-
- return CommonSchemas.Nullable(
- Throw.ForUnexpectedNull(
- node.ElementType.Accept(this)));
- }
-
- public override Builder? VisitPredefinedType(PredefinedTypeSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Keyword.Text);
-
- if (_semanticModelCache.GetSemanticModel(node).GetTypeInfo(node).Type is not INamedTypeSymbol typeSymbol)
- {
- return CommonSchemas.UnsupportedObject($"Failed to build schema for predefined type '{node}'.");
- }
-
- if (typeSymbol.IsJsonDefinedType(out Builder? valueTypeSchema))
- {
- return valueTypeSchema;
- }
-
- return CommonSchemas.UnsupportedObject($"Unexpected built-in type '{node.Keyword.Text}'.");
- }
-
- public override Builder? VisitArrayType(ArrayTypeSyntax node)
- {
- Throw.IfNullArgument(node);
- using var trace = Tracer.Enter(node.Kind().ToString());
-
- Builder? elementSchema = node.ElementType.Accept(this);
- if (elementSchema is null)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for array element type '{node.ElementType}'.");
-
- return CommonSchemas.ArrayOf(elementSchema);
- }
-
- private Builder? VisitTypeDeclaration(TypeDeclarationSyntax node)
- {
- if (_semanticModelCache.GetSemanticModel(node).GetDeclaredSymbol(node) is not INamedTypeSymbol typeSymbol)
- return CommonSchemas.UnsupportedObject($"Failed building schema for {node.Identifier.ValueText}");
-
- string typeId = typeSymbol.GetDefCacheKey();
- if (_cachedTypeSchemas.TryGetValue(typeId, out _))
- return CommonSchemas.DefRef(typeId);
-
- if (typeSymbol.GetOverrideSchema() is Builder overrideSchema)
- return overrideSchema;
-
- // Handle abstract types
- if (typeSymbol.IsAbstract)
- {
- List oneOfBuilders = [];
- foreach (INamedTypeSymbol concrete in GetConcreteSubtypes(typeSymbol))
- {
- TypeDeclarationSyntax? decl = concrete.FindTypeDeclaration();
- if (decl is not null)
- {
- var subtypeBuilder = this.Visit(decl);
- if (subtypeBuilder is not null)
- oneOfBuilders.Add(subtypeBuilder);
- }
- }
-
- if (oneOfBuilders.Count > 0)
- {
- Builder abstractBuilder = CommonSchemas.Object; // Create a new def builder.
- abstractBuilder = abstractBuilder.OneOf([.. oneOfBuilders]);
- _cachedTypeSchemas[typeId] = abstractBuilder;
-
- return CommonSchemas.DefRef(typeId);
- }
- }
-
- // Regular concrete type.
- Builder builder = node.CreateTypeSchema(this);
-
- _cachedTypeSchemas[typeId] = builder;
- return CommonSchemas.DefRef(typeId);
- }
-
- // Helper to get all concrete subtypes of an abstract class.
- private IEnumerable GetConcreteSubtypes(INamedTypeSymbol abstractType)
- {
- using var trace = Tracer.Enter(abstractType.Name);
- foreach (SyntaxTree tree in _compilation.SyntaxTrees)
- {
- SemanticModel model = _compilation.GetSemanticModel(tree);
- foreach (var node in tree.GetRoot().DescendantNodes().OfType())
- {
- if (model.GetDeclaredSymbol(node) is not INamedTypeSymbol symbol)
- continue;
-
- if (!symbol.IsAbstract && symbol.InheritsFrom(abstractType))
- {
- trace.WriteLine($"Found concrete subtype: {symbol.Name}");
- yield return symbol;
- }
- }
- }
- }
-
- private Builder GetPropertySchema(TypeSyntax typeSyntax, Metadata metadata, ExpressionSyntax? defaultExpression)
- {
- SemanticModel semanticModel = _semanticModelCache.GetSemanticModel(typeSyntax);
- if (semanticModel.GetTypeInfo(typeSyntax).Type is not ITypeSymbol typeSymbol || !typeSymbol.IsValidForGeneration())
- return CommonSchemas.UnsupportedObject($"Failed to build schema for type '{typeSyntax}'.");
-
- Builder? propertyBuilder = null;
-
- // These kinds are never directly cached
- if (typeSyntax.Kind() is SyntaxKind.NullableType or SyntaxKind.ArrayType or SyntaxKind.PredefinedType)
- propertyBuilder = this.Visit(typeSyntax);
-
- string typeId = typeSymbol.GetDefCacheKey();
- if (propertyBuilder is null && _cachedTypeSchemas.TryGetValue(typeId, out _))
- propertyBuilder = CommonSchemas.DefRef(typeId);
-
- if (propertyBuilder is null && this.Visit(typeSyntax) is Builder builder)
- propertyBuilder = builder;
-
- if (propertyBuilder is null)
- return CommonSchemas.UnsupportedObject($"Failed to build schema for type '{typeSymbol.Name}'.");
-
- propertyBuilder.ApplyMetadata(metadata);
-
- JsonNode? defaultValue = null;
- if (defaultExpression is not null && semanticModel.GetConstantValue(defaultExpression) is { HasValue: true } constantValue)
- {
- defaultValue = JsonValue.Create(constantValue.Value);
- }
-
- return defaultValue is not null
- ? propertyBuilder.Default(defaultValue)
- : propertyBuilder;
- }
-}
diff --git a/src/SharpSchema.Generator/LeafSyntaxVisitor.Unsupported.cs b/src/SharpSchema.Generator/LeafSyntaxVisitor.Unsupported.cs
new file mode 100644
index 0000000..ef0ec9a
--- /dev/null
+++ b/src/SharpSchema.Generator/LeafSyntaxVisitor.Unsupported.cs
@@ -0,0 +1,21 @@
+namespace SharpSchema.Generator;
+
+internal partial class LeafSyntaxVisitor
+{
+ internal static class Unsupported
+ {
+ public const string EnumMessage = "Failed to build schema for enum '{0}'.";
+ public const string IdentifierMessage = "Failed to build schema for identifier '{0}'.";
+ public const string DeclarationMessage = "Could not find declaration for identifier '{0}'.";
+ public const string UnboundGenericMessage = "Failed to evaluate unbound generic type '{0}'.";
+ public const string TypeSymbolMessage = "Node '{0}' does not produce a type symbol.";
+ public const string DictionaryElementMessage = "Failed to build schema for dictionary element type '{0}'.";
+ public const string KeyTypeMessage = "Key type '{0}' is not supported.";
+ public const string ArrayElementMessage = "Failed to build schema for array element type '{0}'.";
+ public const string GenericTypeMessage = "Failed to build schema for generic type '{0}'.";
+ public const string NullableElementMessage = "Failed to build schema for nullable element type '{0}'.";
+ public const string PredefinedTypeMessage = "Failed to build schema for predefined type '{0}'.";
+ public const string TypeMessage = "Failed to build schema for type '{0}'.";
+ public const string SymbolMessage = "Failed building schema for {0}";
+ }
+}
diff --git a/src/SharpSchema.Generator/LeafSyntaxVisitor.cs b/src/SharpSchema.Generator/LeafSyntaxVisitor.cs
new file mode 100644
index 0000000..f5d0c41
--- /dev/null
+++ b/src/SharpSchema.Generator/LeafSyntaxVisitor.cs
@@ -0,0 +1,346 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Text.Json.Nodes;
+using Json.Schema;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using SharpSchema.Annotations;
+using SharpSchema.Generator.Model;
+using SharpSchema.Generator.Resolvers;
+using SharpSchema.Generator.Utilities;
+
+namespace SharpSchema.Generator;
+
+using Builder = JsonSchemaBuilder;
+
+internal partial class LeafSyntaxVisitor : CSharpSyntaxVisitor
+{
+ private readonly RootContext _context;
+ private readonly GeneratorOptions _options;
+
+ public LeafSyntaxVisitor(RootContext context, GeneratorOptions options)
+ {
+ _context = context;
+ _options = options;
+ }
+
+ [ExcludeFromCodeCoverage]
+ public override Builder? DefaultVisit(SyntaxNode node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope scope = Tracer.Enter($"{node.Kind()} {node.GetLocation().GetLineSpan().StartLinePosition.Line}");
+ return null;
+ }
+
+ public override Builder? VisitQualifiedName(QualifiedNameSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Right.Identifier.Text);
+ return this.Visit(node.Right);
+ }
+
+ public override Builder? VisitClassDeclaration(ClassDeclarationSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Identifier.Text);
+ return this.VisitTypeDeclaration(node, trace);
+ }
+
+ public override Builder? VisitStructDeclaration(StructDeclarationSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Identifier.Text);
+ return this.VisitTypeDeclaration(node, trace);
+ }
+
+ public override Builder? VisitRecordDeclaration(RecordDeclarationSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Identifier.Text);
+ return this.VisitTypeDeclaration(node, trace);
+ }
+
+ public override Builder? VisitEnumDeclaration(EnumDeclarationSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Identifier.Text);
+
+ if (node.GetDeclaredSymbol(_context.SemanticModelCache) is not INamedTypeSymbol enumSymbol)
+ return CommonSchemas.UnsupportedObject(Unsupported.EnumMessage, node.Identifier);
+
+ if (enumSymbol.GetOverrideSchema() is Builder overrideSchema)
+ return overrideSchema;
+
+ string cacheKey = enumSymbol.GetDefCacheKey();
+ if (_context.CachedTypeSchemas.TryGetValue(cacheKey, out Builder? cachedSchema))
+ return CommonSchemas.DefRef(cacheKey);
+
+ MemberMeta metadata = Throw.IfUnexpectedNull(MemberMeta.SymbolVisitor.Default.Visit(enumSymbol));
+
+ Builder builder = EnumResolver.Resolve(enumSymbol, _options) ??
+ CommonSchemas.UnsupportedObject(Unsupported.EnumMessage, node.Identifier);
+
+ _context.CachedTypeSchemas[cacheKey] = builder.ApplyMemberMeta(metadata);
+
+ return CommonSchemas.DefRef(cacheKey);
+ }
+
+ public override Builder? VisitIdentifierName(IdentifierNameSyntax node)
+ {
+ Throw.IfNullArgument(node);
+
+ using Tracer.TraceScope trace = Tracer.Enter(node.Identifier.Text);
+
+ TypeInfo typeInfo = node.GetTypeInfo(_context.SemanticModelCache);
+ if (typeInfo.ConvertedType is not ITypeSymbol typeSymbol)
+ return CommonSchemas.UnsupportedObject(Unsupported.IdentifierMessage, node.Identifier);
+
+ if (typeSymbol.FindDeclaringSyntax() is SyntaxNode syntaxNode)
+ return this.Visit(syntaxNode);
+
+ return null;
+ }
+
+ public override Builder? VisitGenericName(GenericNameSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Identifier.Text);
+
+ if (node.IsUnboundGenericName)
+ return CommonSchemas.UnsupportedObject(Unsupported.UnboundGenericMessage, node.Identifier);
+
+ if (node.GetTypeInfo(_context.SemanticModelCache).Type is not INamedTypeSymbol boundTypeSymbol)
+ return CommonSchemas.UnsupportedObject(Unsupported.TypeSymbolMessage, node.Identifier.Text);
+
+ if (boundTypeSymbol.HasUnresolvedTypeArguments())
+ {
+ trace.WriteLine("Unresolved type arguments found.");
+ return null;
+ }
+
+ var (kind, keyType, elementSymbol) = _context.CollectionResolver.Resolve(boundTypeSymbol);
+
+ return kind switch
+ {
+ CollectionKind.Dictionary => HandleDictionaryType(node, keyType, elementSymbol),
+ CollectionKind.Array => HandleArrayType(node, elementSymbol),
+ _ => HandleGenericType(node, boundTypeSymbol)
+ };
+
+ // -- Local functions --
+
+ Builder? HandleDictionaryType(GenericNameSyntax node, SchemaValueType keyType, ITypeSymbol elementSymbol)
+ {
+ if (node.TypeArgumentList.Arguments[^1].Accept(this) is not Builder elementSchema)
+ return CommonSchemas.UnsupportedObject(Unsupported.DictionaryElementMessage, elementSymbol.Name);
+
+ if (keyType is SchemaValueType.String)
+ return CommonSchemas.Object.AdditionalProperties(elementSchema);
+
+ return _options.DictionaryKeyMode switch
+ {
+ DictionaryKeyMode.Skip => null,
+ DictionaryKeyMode.Strict => CommonSchemas.UnsupportedObject(Unsupported.KeyTypeMessage, keyType),
+ DictionaryKeyMode.Loose => CommonSchemas.Object
+ .Comment($"Key type '{keyType}' must be convertible to string")
+ .AdditionalProperties(elementSchema),
+ DictionaryKeyMode.Silent => CommonSchemas.Object
+ .AdditionalProperties(elementSchema),
+ _ => Throw.UnknownEnumValue(_options.DictionaryKeyMode)
+ };
+ }
+
+ Builder? HandleArrayType(GenericNameSyntax node, ITypeSymbol elementSymbol)
+ {
+ Builder? elementSchema = node.TypeArgumentList.Arguments[^1].Accept(this);
+ if (elementSchema is null)
+ return CommonSchemas.UnsupportedObject(Unsupported.ArrayElementMessage, elementSymbol);
+
+ return CommonSchemas.ArrayOf(elementSchema);
+ }
+
+ Builder? HandleGenericType(GenericNameSyntax node, INamedTypeSymbol boundTypeSymbol)
+ {
+ Builder? boundTypeBuilder = Visit(boundTypeSymbol.FindDeclaringSyntax());
+ if (boundTypeBuilder is null)
+ return CommonSchemas.UnsupportedObject(Unsupported.GenericTypeMessage, node.Identifier);
+
+ // Add to the oneOf for the unbound generic type
+ INamedTypeSymbol unboundGeneric = boundTypeSymbol.ConstructUnboundGenericType();
+ string cacheKey = unboundGeneric.GetDefCacheKey();
+
+ if (_context.CachedTypeSchemas.TryGetValue(cacheKey, out Builder? cachedSchema) &&
+ cachedSchema.Get()?.Schemas is IReadOnlyList currentOneOf)
+ {
+ _context.CachedTypeSchemas[cacheKey] = cachedSchema.OneOf(currentOneOf.Append(boundTypeBuilder));
+ }
+ else if (_context.CachedTypeSchemas.TryGetValue(cacheKey, out cachedSchema))
+ {
+ _context.CachedTypeSchemas[cacheKey] = CommonSchemas.Object.OneOf(cachedSchema, boundTypeBuilder);
+ }
+
+ return boundTypeBuilder;
+ }
+ }
+
+ public override Builder? VisitNullableType(NullableTypeSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Kind().ToString());
+
+ if (node.ElementType.Accept(this) is Builder elementSchema)
+ return CommonSchemas.Nullable(elementSchema);
+
+ return null;
+ }
+
+ public override Builder? VisitPredefinedType(PredefinedTypeSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Keyword.Text);
+
+ if (node.Keyword.IsKind(SyntaxKind.StringKeyword))
+ return CommonSchemas.String;
+
+ if (node.Keyword.IsKind(SyntaxKind.BoolKeyword))
+ return CommonSchemas.Boolean;
+
+ if (_context.SemanticModelCache.GetSemanticModel(node).GetTypeInfo(node).Type is not INamedTypeSymbol typeSymbol)
+ return CommonSchemas.UnsupportedObject(Unsupported.PredefinedTypeMessage, node);
+
+ bool shouldCache = _options.NumberMode is NumberMode.StrictDefs;
+ string cacheKey = typeSymbol.GetDefCacheKey();
+
+ if (shouldCache && _context.CachedTypeSchemas.TryGetValue(cacheKey, out Builder? cachedSchema))
+ return CommonSchemas.DefRef(cacheKey);
+
+ if (!typeSymbol.IsJsonDefinedType(_options.NumberMode, out Builder? valueTypeSchema))
+ valueTypeSchema = CommonSchemas.UnsupportedObject(Unsupported.PredefinedTypeMessage, node.Keyword.Text);
+
+ if (shouldCache)
+ {
+ _context.CachedTypeSchemas[cacheKey] = valueTypeSchema;
+ return CommonSchemas.DefRef(cacheKey);
+ }
+
+ return valueTypeSchema;
+ }
+
+ public override Builder? VisitArrayType(ArrayTypeSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Kind().ToString());
+
+ if (node.ElementType.Accept(this) is Builder elementSchema)
+ return CommonSchemas.ArrayOf(elementSchema);
+
+ return null;
+ }
+
+ public override Builder? VisitPropertyDeclaration(PropertyDeclarationSyntax node)
+ {
+ Throw.IfNullArgument(node);
+ using Tracer.TraceScope trace = Tracer.Enter(node.Identifier.Text);
+
+ Builder? typeBuilder = node.Type.Accept(this);
+ if (typeBuilder is null)
+ return null;
+
+ if (node.ExpressionBody is ArrowExpressionClauseSyntax aec
+ && GetConstantValue(aec.Expression) is JsonNode constantValue)
+ {
+ typeBuilder = CommonSchemas.Const(constantValue);
+ }
+ else if (ExtractDefaultValue(node) is JsonNode defaultValue)
+ {
+ typeBuilder = typeBuilder.Default(defaultValue);
+ }
+
+ return typeBuilder;
+
+ // -- Local functions --
+
+ JsonNode? ExtractDefaultValue(PropertyDeclarationSyntax propertyDeclaration)
+ {
+ return propertyDeclaration.Initializer is EqualsValueClauseSyntax evc
+ ? GetConstantValue(evc.Value)
+ : null;
+ }
+
+ JsonNode? GetConstantValue(SyntaxNode node)
+ {
+ SemanticModel sm = _context.SemanticModelCache.GetSemanticModel(node);
+ return sm.GetConstantValue(node) is Optional
internal static class SymbolExtensions
{
- public static AttributeHandler GetAttributeHandler(this ISymbol symbol, Traversal traversal = Traversal.SymbolOnly)
+ public static AttributeHandler GetAttributeHandler(this ISymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
where T : Attribute
{
return new AttributeHandler(GetAttributeData(symbol, traversal));
}
+ public static AttributeHandler GetAttributeHandler(this IPropertySymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ where T : Attribute
+ {
+ return new AttributeHandler(GetAttributeData(symbol, traversal));
+ }
+
+ public static AttributeHandler GetAttributeHandler(this IFieldSymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ where T : Attribute
+ {
+ return new AttributeHandler(GetAttributeData(symbol, traversal));
+ }
+
+ public static AttributeHandler GetAttributeHandler(this IParameterSymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ where T : Attribute
+ {
+ return new AttributeHandler(GetAttributeData(symbol, traversal));
+ }
+
+ public static ObjectAttributes GetObjectAttributes(this ISymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ {
+ return new ObjectAttributes(
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal));
+ }
+
+ public static PropertyAttributes GetPropertyAttributes(this ISymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ {
+ return new PropertyAttributes(
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal),
+ GetAttributeHandler(symbol, traversal));
+ }
+
///
/// Gets the attribute data of the specified type from the symbol.
///
@@ -24,9 +72,11 @@ public static AttributeHandler GetAttributeHandler(this ISymbol symbol, Trave
/// The symbol.
/// Indicates whether to search for attributes on base classes and interfaces.
/// The attribute data if found; otherwise, null.
- public static AttributeData? GetAttributeData(this ISymbol symbol, Traversal traversal = Traversal.SymbolOnly)
+ public static AttributeData? GetAttributeData(this ISymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
where T : Attribute
{
+ AttributeData? mostDerivedAttribute = null;
+
// Search for the attribute on the symbol itself
foreach (AttributeData attribute in symbol.GetAttributes())
{
@@ -36,7 +86,7 @@ public static AttributeHandler GetAttributeHandler(this ISymbol symbol, Trave
if (symbol is INamedTypeSymbol namedTypeSymbol)
{
- if (traversal.CheckFlag(Traversal.Bases))
+ if (traversal.CheckFlag(TraversalMode.Bases))
{
// Search on base classes
INamedTypeSymbol? baseType = namedTypeSymbol.BaseType;
@@ -45,14 +95,17 @@ public static AttributeHandler GetAttributeHandler(this ISymbol symbol, Trave
foreach (AttributeData attribute in baseType.GetAttributes())
{
if (attribute.AttributeClass?.MatchesType() ?? false)
- return attribute;
+ {
+ mostDerivedAttribute = attribute;
+ break;
+ }
}
baseType = baseType.BaseType;
}
}
- if (traversal.CheckFlag(Traversal.Interfaces))
+ if (traversal.CheckFlag(TraversalMode.Interfaces))
{
// Search on interfaces
foreach (INamedTypeSymbol interfaceType in namedTypeSymbol.AllInterfaces)
@@ -60,24 +113,168 @@ public static AttributeHandler GetAttributeHandler(this ISymbol symbol, Trave
foreach (AttributeData attribute in interfaceType.GetAttributes())
{
if (attribute.AttributeClass?.MatchesType() ?? false)
- return attribute;
+ {
+ mostDerivedAttribute = attribute;
+ break;
+ }
}
}
}
}
- return null;
+ return mostDerivedAttribute;
}
- public static TValue? GetAttributeConstructorArgument(this ISymbol symbol, int argumentIndex, Traversal traversal = Traversal.SymbolOnly)
- where TAttribute : Attribute
- where TValue : notnull
+ public static AttributeData? GetAttributeData(this IPropertySymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ where T : Attribute
{
- AttributeData? attributeData = symbol.GetAttributeData(traversal);
- if (attributeData is null)
- return default;
+ AttributeData? mostDerivedAttribute = null;
+
+ // Search for the attribute on the symbol itself
+ foreach (AttributeData attribute in symbol.GetAttributes())
+ {
+ if (attribute.AttributeClass?.MatchesType() ?? false)
+ return attribute;
+ }
- return attributeData.GetConstructorArgument(argumentIndex);
+ if (symbol.ContainingType is INamedTypeSymbol containingType)
+ {
+ if (traversal.CheckFlag(TraversalMode.Bases))
+ {
+ // Search on base classes
+ INamedTypeSymbol? baseType = containingType.BaseType;
+ while (baseType is not null)
+ {
+ var baseProperty = baseType.GetMembers(symbol.Name).OfType().FirstOrDefault();
+ if (baseProperty is not null)
+ {
+ foreach (AttributeData attribute in baseProperty.GetAttributes())
+ {
+ if (attribute.AttributeClass?.MatchesType() ?? false)
+ {
+ mostDerivedAttribute = attribute;
+ break;
+ }
+ }
+ }
+
+ baseType = baseType.BaseType;
+ }
+ }
+
+ if (traversal.CheckFlag(TraversalMode.Interfaces))
+ {
+ // Search on interfaces
+ foreach (INamedTypeSymbol interfaceType in containingType.AllInterfaces)
+ {
+ var interfaceProperty = interfaceType.GetMembers(symbol.Name).OfType().FirstOrDefault();
+ if (interfaceProperty is not null)
+ {
+ foreach (AttributeData attribute in interfaceProperty.GetAttributes())
+ {
+ if (attribute.AttributeClass?.MatchesType() ?? false)
+ {
+ mostDerivedAttribute = attribute;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return mostDerivedAttribute;
+ }
+
+ public static AttributeData? GetAttributeData(this IParameterSymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ where T : Attribute
+ {
+ AttributeData? mostDerivedAttribute = null;
+
+ // Search for the attribute on the symbol itself
+ foreach (AttributeData attribute in symbol.GetAttributes())
+ {
+ if (attribute.AttributeClass?.MatchesType() ?? false)
+ return attribute;
+ }
+
+ if (symbol.ContainingSymbol is IMethodSymbol methodSymbol &&
+ methodSymbol.MethodKind == MethodKind.Constructor &&
+ methodSymbol.ContainingType.IsRecord)
+ {
+ if (methodSymbol.ContainingType is INamedTypeSymbol containingType)
+ {
+ if (traversal.CheckFlag(TraversalMode.Bases))
+ {
+ // Search on base records
+ INamedTypeSymbol? baseType = containingType.BaseType;
+ while (baseType is not null)
+ {
+ var baseConstructor = baseType.InstanceConstructors.FirstOrDefault();
+ if (baseConstructor is not null)
+ {
+ var baseParameter = baseConstructor.Parameters.FirstOrDefault(p => p.Name == symbol.Name);
+ if (baseParameter is not null)
+ {
+ foreach (AttributeData attribute in baseParameter.GetAttributes())
+ {
+ if (attribute.AttributeClass?.MatchesType() ?? false)
+ {
+ mostDerivedAttribute = attribute;
+ break;
+ }
+ }
+ }
+ }
+
+ baseType = baseType.BaseType;
+ }
+ }
+ }
+ }
+
+ return mostDerivedAttribute;
+ }
+
+ public static AttributeData? GetAttributeData(this IFieldSymbol symbol, TraversalMode traversal = TraversalMode.SymbolOnly)
+ where T : Attribute
+ {
+ AttributeData? mostDerivedAttribute = null;
+
+ // Search for the attribute on the symbol itself
+ foreach (AttributeData attribute in symbol.GetAttributes())
+ {
+ if (attribute.AttributeClass?.MatchesType() ?? false)
+ return attribute;
+ }
+
+ if (symbol.ContainingType is INamedTypeSymbol containingType)
+ {
+ if (traversal.CheckFlag(TraversalMode.Bases))
+ {
+ // Search on base classes
+ INamedTypeSymbol? baseType = containingType.BaseType;
+ while (baseType is not null)
+ {
+ var baseField = baseType.GetMembers(symbol.Name).OfType().FirstOrDefault();
+ if (baseField is not null)
+ {
+ foreach (AttributeData attribute in baseField.GetAttributes())
+ {
+ if (attribute.AttributeClass?.MatchesType() ?? false)
+ {
+ mostDerivedAttribute = attribute;
+ break;
+ }
+ }
+ }
+
+ baseType = baseType.BaseType;
+ }
+ }
+ }
+
+ return mostDerivedAttribute;
}
public static bool MatchesType(this INamedTypeSymbol typeSymbol)
@@ -106,6 +303,14 @@ public static bool MatchesType(this INamedTypeSymbol typeSymbol)
return normalizedSymbolName.SequenceEqual(runtimeTypeName.AsSpan());
}
+ public static bool HasUnresolvedTypeArguments(this INamedTypeSymbol namedTypeSymbol)
+ {
+ if (namedTypeSymbol.IsGenericType)
+ return namedTypeSymbol.TypeArguments.Any(arg => arg.TypeKind == TypeKind.TypeParameter);
+
+ return false;
+ }
+
///
/// Determines if the symbol is valid for generation.
///
@@ -114,7 +319,6 @@ public static bool MatchesType(this INamedTypeSymbol typeSymbol)
public static bool IsValidForGeneration(this ISymbol symbol)
{
return !symbol.IsStatic
- && !symbol.IsVirtual
&& !symbol.IsImplicitlyDeclared
&& symbol switch
{
@@ -125,12 +329,11 @@ public static bool IsValidForGeneration(this ISymbol symbol)
static bool IsValidNamedTypeSymbol(INamedTypeSymbol symbol)
{
- return !symbol.IsStatic
+ return !symbol.IsVirtual
&& !symbol.IsAnonymousType
&& !symbol.IsComImport
&& !symbol.IsImplicitClass
- && !symbol.IsExtern
- && !symbol.IsImplicitlyDeclared;
+ && !symbol.IsExtern;
}
static bool IsValidPropertySymbol(IPropertySymbol symbol)
@@ -141,36 +344,31 @@ static bool IsValidPropertySymbol(IPropertySymbol symbol)
}
///
- /// Finds the type declaration syntax for the symbol.
+ /// Finds the declaring syntax node of the specified type for the given symbol.
///
- /// The symbol.
- /// The type declaration syntax if found; otherwise, null.
- public static TypeDeclarationSyntax? FindTypeDeclaration(this INamedTypeSymbol symbol)
+ /// The type of the syntax node to find.
+ /// The symbol whose declaring syntax node is to be found.
+ /// The declaring syntax node of the specified type if found; otherwise, null.
+ public static T? FindDeclaringSyntax(this ISymbol symbol)
+ where T : SyntaxNode
{
foreach (SyntaxReference reference in symbol.DeclaringSyntaxReferences)
{
SyntaxNode syntax = reference.GetSyntax();
- if (syntax is TypeDeclarationSyntax typeDeclarationSyntax)
+ if (syntax is T node)
{
- return typeDeclarationSyntax;
+ return node;
}
}
return null;
}
- public static BaseTypeDeclarationSyntax? FindBaseTypeDeclaration(this ITypeSymbol symbol)
+ public static SyntaxNode? FindDeclaringSyntax(this ISymbol symbol)
{
- foreach (SyntaxReference reference in symbol.DeclaringSyntaxReferences)
- {
- SyntaxNode syntax = reference.GetSyntax();
- if (syntax is BaseTypeDeclarationSyntax baseTypeDeclarationSyntax)
- {
- return baseTypeDeclarationSyntax;
- }
- }
-
- return null;
+ return symbol.DeclaringSyntaxReferences
+ .FirstOrDefault()?
+ .GetSyntax();
}
///
@@ -196,22 +394,38 @@ static bool IsValidPropertySymbol(IPropertySymbol symbol)
public static bool InheritsFrom(this INamedTypeSymbol symbol, INamedTypeSymbol baseType)
{
- INamedTypeSymbol? current = symbol.BaseType;
- while (current is not null)
+ // Traverse base types
+ for (INamedTypeSymbol? current = symbol.BaseType; current is not null; current = current.BaseType)
{
- if (SymbolEqualityComparer.Default.Equals(current, baseType))
+ if (SymbolEqualityComparer.Default.Equals(current.OriginalDefinition, baseType.OriginalDefinition))
+ {
return true;
- current = current.BaseType;
+ }
}
+
+ // Check interfaces as well
+ if (baseType.TypeKind == TypeKind.Interface)
+ {
+ foreach (var iface in symbol.AllInterfaces)
+ {
+ if (SymbolEqualityComparer.Default.Equals(iface.OriginalDefinition, baseType.OriginalDefinition))
+ {
+ return true;
+ }
+ }
+ }
+
return false;
}
public static string GetDefCacheKey(this ITypeSymbol symbol) => symbol.GetDocumentationCommentId() ?? symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
- public static bool IsJsonDefinedType(this ITypeSymbol symbol, [NotNullWhen(true)] out JsonSchemaBuilder? schema)
+ public static bool IsJsonDefinedType(this ITypeSymbol symbol, NumberMode numberMode, [NotNullWhen(true)] out JsonSchemaBuilder? schema)
{
+ using var trace = Tracer.Enter(symbol.Name);
if (symbol.SpecialType == SpecialType.None)
{
+ trace.WriteLine("Symbol is not a special type.");
schema = null;
return false;
}
@@ -219,21 +433,21 @@ public static bool IsJsonDefinedType(this ITypeSymbol symbol, [NotNullWhen(true)
schema = symbol.SpecialType switch
{
SpecialType.System_Boolean => CommonSchemas.Boolean,
- SpecialType.System_Byte => CommonSchemas.System_Byte,
+ SpecialType.System_Byte => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_Byte,
SpecialType.System_Char => CommonSchemas.System_Char,
SpecialType.System_DateTime => CommonSchemas.System_DateTime,
- SpecialType.System_Decimal => CommonSchemas.System_Decimal,
- SpecialType.System_Double => CommonSchemas.System_Double,
- SpecialType.System_Int16 => CommonSchemas.System_Int16,
- SpecialType.System_Int32 => CommonSchemas.System_Int32,
- SpecialType.System_Int64 => CommonSchemas.System_Int64,
+ SpecialType.System_Decimal => numberMode is NumberMode.JsonNative ? CommonSchemas.Number : CommonSchemas.System_Decimal,
+ SpecialType.System_Double => numberMode is NumberMode.JsonNative ? CommonSchemas.Number : CommonSchemas.System_Double,
+ SpecialType.System_Int16 => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_Int16,
+ SpecialType.System_Int32 => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_Int32,
+ SpecialType.System_Int64 => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_Int64,
SpecialType.System_Object => throw new InvalidOperationException("System.Object does not map to a json defined type."),
- SpecialType.System_SByte => CommonSchemas.System_SByte,
- SpecialType.System_Single => CommonSchemas.System_Single,
+ SpecialType.System_SByte => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_SByte,
+ SpecialType.System_Single => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_Single,
SpecialType.System_String => CommonSchemas.String,
- SpecialType.System_UInt16 => CommonSchemas.System_UInt16,
- SpecialType.System_UInt32 => CommonSchemas.System_UInt32,
- SpecialType.System_UInt64 => CommonSchemas.System_UInt64,
+ SpecialType.System_UInt16 => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_UInt16,
+ SpecialType.System_UInt32 => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_UInt32,
+ SpecialType.System_UInt64 => numberMode is NumberMode.JsonNative ? CommonSchemas.Integer : CommonSchemas.System_UInt64,
_ => null
};
diff --git a/src/SharpSchema.Generator/Utilities/SyntaxExtensions.cs b/src/SharpSchema.Generator/Utilities/SyntaxExtensions.cs
index ca6c5bf..e903a21 100644
--- a/src/SharpSchema.Generator/Utilities/SyntaxExtensions.cs
+++ b/src/SharpSchema.Generator/Utilities/SyntaxExtensions.cs
@@ -1,16 +1,11 @@
using System.Runtime.CompilerServices;
-using Humanizer;
-using Json.Schema;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using SharpSchema.Generator.Model;
-using SharpSchema.Annotations;
namespace SharpSchema.Generator.Utilities;
-using Builder = JsonSchemaBuilder;
-
internal static class SyntaxExtensions
{
public static bool IsNestedInSystemNamespace(this TypeDeclarationSyntax node)
@@ -23,7 +18,7 @@ public static bool IsNestedInSystemNamespace(this TypeDeclarationSyntax node)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ISymbol? GetDeclaredSymbol(this SyntaxNode node, SemanticModelCache semanticCache)
{
- return GetDeclaredSymbol(node, semanticCache.GetSemanticModel(node));
+ return node.GetDeclaredSymbol(semanticCache.GetSemanticModel(node));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -32,103 +27,15 @@ public static bool IsNestedInSystemNamespace(this TypeDeclarationSyntax node)
return semanticModel.GetDeclaredSymbol(node);
}
- public static Builder CreateTypeSchema(this TypeDeclarationSyntax node, LeafDeclaredTypeSyntaxVisitor typeVisitor)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static TypeInfo GetTypeInfo(this ExpressionSyntax node, SemanticModelCache semanticCache)
{
- Throw.IfNullArgument(node);
-
- Builder builder = CommonSchemas.Object;
-
- var properties = new Dictionary(StringComparer.OrdinalIgnoreCase);
- var requiredProperties = new HashSet(StringComparer.OrdinalIgnoreCase);
-
- // Collect primary-constructor parameters
- if (node.ParameterList is not null)
- {
- foreach (ParameterSyntax parameter in node.ParameterList.Parameters)
- {
- ProcessParameter(parameter);
- }
- }
-
- foreach (MemberDeclarationSyntax member in node.Members)
- {
- ProcessMember(member);
- }
-
- // Apply collected properties and required properties
- if (properties.Count > 0)
- {
- builder = builder.Properties(properties);
- }
-
- if (requiredProperties.Count > 0)
- {
- builder = builder.Required(requiredProperties);
- }
-
- if (typeVisitor.Options.Traversal.CheckFlag(Traversal.Bases))
- {
- // Apply base types
- if (node.BaseList is not null)
- {
- foreach (BaseTypeSyntax baseType in node.BaseList.Types)
- {
- if (typeVisitor.Visit(baseType) is Builder baseTypeBuilder)
- {
- builder.MergeBaseProperties(baseTypeBuilder);
- }
- }
- }
- }
-
- return builder;
-
- void ProcessMember(MemberDeclarationSyntax member)
- {
- if (member is PropertyDeclarationSyntax property && typeVisitor.Visit(property) is Builder propertyBuilder)
- {
- properties[property.Identifier.Text.Camelize()] = propertyBuilder;
-
- // Check for nullability annotation
- bool isNullable = property.Type is NullableTypeSyntax;
-
- // Check for SchemaRequired attribute
- bool hasSchemaRequiredAttribute = property.AttributeLists
- .SelectMany(attrList => attrList.Attributes)
- .Any(attr => attr.Name.ToString() == nameof(SchemaRequiredAttribute));
-
- // Check for required keyword
- bool hasRequiredKeyword = property.Modifiers.Any(SyntaxKind.RequiredKeyword);
-
- if (!isNullable || hasSchemaRequiredAttribute || hasRequiredKeyword)
- {
- requiredProperties.Add(property.Identifier.Text.Camelize());
- }
- }
- }
-
- void ProcessParameter(ParameterSyntax parameter)
- {
- if (typeVisitor.Visit(parameter) is Builder paramBuilder)
- {
- properties[parameter.Identifier.Text.Camelize()] = paramBuilder;
-
- // Check for default value
- bool hasDefaultValue = parameter.Default is not null;
-
- // Check for nullability annotation
- bool isNullable = parameter.Type is NullableTypeSyntax;
-
- // Check for SchemaRequired attribute
- bool hasSchemaRequiredAttribute = parameter.AttributeLists
- .SelectMany(attrList => attrList.Attributes)
- .Any(attr => attr.Name.ToString() == nameof(SchemaRequiredAttribute));
+ return node.GetTypeInfo(semanticCache.GetSemanticModel(node));
+ }
- if (!hasDefaultValue && !isNullable && !hasSchemaRequiredAttribute)
- {
- requiredProperties.Add(parameter.Identifier.Text.Camelize());
- }
- }
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static TypeInfo GetTypeInfo(this ExpressionSyntax node, SemanticModel semanticModel)
+ {
+ return semanticModel.GetTypeInfo(node);
}
}
diff --git a/src/SharpSchema.Generator/Utilities/Throw.cs b/src/SharpSchema.Generator/Utilities/Throw.cs
index a83facd..cd2565f 100644
--- a/src/SharpSchema.Generator/Utilities/Throw.cs
+++ b/src/SharpSchema.Generator/Utilities/Throw.cs
@@ -15,10 +15,15 @@ public static void IfNullArgument([NotNull] T? value, [CallerArgumentExpressi
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[return: NotNullIfNotNull(nameof(value))]
- public static T ForUnexpectedNull([NotNull] T? value, [CallerArgumentExpression(nameof(value))] string? paramName = null, [CallerMemberName] string? caller = null)
+ public static T IfUnexpectedNull([NotNull] T? value, [CallerArgumentExpression(nameof(value))] string? paramName = null, [CallerMemberName] string? caller = null)
where T : class
{
if (value is null) throw new InvalidOperationException($"Unexpected null value {paramName} in {caller}");
return value;
}
+
+ public static TResult UnknownEnumValue(object value, [CallerArgumentExpression("value")] string? paramName = null)
+ {
+ throw new InvalidOperationException($"Unknown enum value {value} for {paramName}");
+ }
}
diff --git a/src/SharpSchema.Generator/Utilities/Tracer.cs b/src/SharpSchema.Generator/Utilities/Tracer.cs
index 278c28f..2d06eac 100644
--- a/src/SharpSchema.Generator/Utilities/Tracer.cs
+++ b/src/SharpSchema.Generator/Utilities/Tracer.cs
@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
+using System.Diagnostics;
namespace SharpSchema.Generator.Utilities;
@@ -18,6 +19,7 @@ public static class Tracer
private static int s_indentLevel = 0;
private static LineWriter? s_writer;
private static int s_indentWidth = 2;
+ private static bool s_enableTiming = false;
///
/// Sets the writer to use for writing trace messages.
@@ -29,6 +31,15 @@ public static class Tracer
///
public static int IndentWidth { set => s_indentWidth = value; }
+ ///
+ /// Gets or sets whether timing is enabled.
+ ///
+ public static bool EnableTiming
+ {
+ get => s_enableTiming;
+ set => s_enableTiming = value;
+ }
+
///
/// Writes a trace message followed by a newline.
///
@@ -72,6 +83,8 @@ private static string GetIndent()
///
public readonly struct TraceScope() : IDisposable
{
+ private readonly Stopwatch? _stopwatch = Tracer.EnableTiming ? Stopwatch.StartNew() : null;
+
///
/// Writes a trace message followed by a newline.
///
@@ -84,6 +97,16 @@ public void WriteLine(string message, [CallerMemberName] string? caller = null)
///
/// Decreases the indent level when the scope is disposed.
///
- public void Dispose() => Tracer.s_indentLevel--;
+ public void Dispose()
+ {
+ if (Tracer.EnableTiming)
+ {
+ _stopwatch!.Stop();
+ double seconds = _stopwatch.Elapsed.TotalSeconds;
+ WriteLine($"Done [{seconds:0.00}s]", "Scope");
+ }
+
+ Tracer.s_indentLevel--;
+ }
}
}
diff --git a/src/SharpSchema.Generator/_docs/visitor-classes.md b/src/SharpSchema.Generator/_docs/visitor-classes.md
new file mode 100644
index 0000000..638dee1
--- /dev/null
+++ b/src/SharpSchema.Generator/_docs/visitor-classes.md
@@ -0,0 +1,48 @@
+# Visitor Classes in SharpSchema.Generator
+
+## Class Responsibilities and Boundaries
+
+This document outlines the responsibilities of `RootSyntaxVisitor.cs`, `LeafSyntaxVisitor.cs`, and `NamedTypeResolver.cs`, which form the core of SharpSchema's JSON schema generation process.
+
+### 1. RootSyntaxVisitor
+
+- Entry point for schema generation
+- Manages the root schema document structure, setting up the schema version
+- Handles top-level type declarations (classes, structs, records)
+- Coordinates management of declarations for abstract types and their implementations
+- Manages schema references via the `$defs` section
+- Assembles the final complete schema with all required references
+
+### 2. LeafSyntaxVisitor
+
+- Handles the detailed syntax traversal of C# code
+- Processes individual language elements like arrays, enums, nullable types, etc.
+- Manages schema caching for defined types
+- Creates references to abstract types for polymorphic schemas
+- Translates various C# syntax nodes into JSON schema components
+- Connects to NamedTypeResolver when processing types with members
+
+### 3. NamedTypeResolver
+
+- Focuses on symbol-based traversal rather than syntax
+- Handles type member resolution (properties, record parameters)
+- Manages property requirements based on nullability and attributes
+- Implements base type and interface traversal based on TraversalMode
+- Processes property metadata from attributes
+- Manages property naming conventions and schema customization
+
+## Class Collaboration Flow
+
+1. `RootSyntaxVisitor` receives a type declaration and sets up the root schema
+2. It calls through to `LeafSyntaxVisitor` to handle the details of the type
+3. When a type with members is encountered, `LeafSyntaxVisitor` instantiates `NamedTypeResolver`
+4. `NamedTypeResolver` processes the members, referring back to `LeafSyntaxVisitor` to resolve their types
+5. `LeafSyntaxVisitor` caches completed schemas
+6. `RootSyntaxVisitor` assembles everything into a complete schema with references
+
+## Design Principles
+
+- Single Responsibility: Each class has a focused area of concern
+- Separation of Concerns: Syntax traversal vs. symbol traversal vs. high-level document structure
+- Caching: Types are processed once and referenced thereafter
+- Visitor Pattern: Standard Roslyn visitor pattern used throughout
diff --git a/test/Generator/AllFeaturesProject/AllFeaturesProjectTests.cs b/test/Generator/AllFeaturesProject/AllFeaturesProjectTests.cs
index 07485fd..209ec5c 100644
--- a/test/Generator/AllFeaturesProject/AllFeaturesProjectTests.cs
+++ b/test/Generator/AllFeaturesProject/AllFeaturesProjectTests.cs
@@ -7,6 +7,7 @@
using VerifyTests;
using Xunit;
using Xunit.Abstractions;
+using SharpSchema.Annotations;
namespace SharpSchema.Test.Generator.AllFeaturesProject;
@@ -123,12 +124,12 @@ public AllFeaturesProjectTests(ITestOutputHelper outputHelper, AllFeaturesProjec
// return schemaRootInfos;
//}
- public static TheoryData VerifyOptions()
+ public static TheoryData VerifyOptions()
{
return new()
{
- { Accessibilities.Public, Accessibilities.Public},
- { Accessibilities.Any, Accessibilities.Any }
+ { AccessibilityMode.Public, AccessibilityMode.Public},
+ { AccessibilityMode.Any, AccessibilityMode.Any }
};
}
}
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Public.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Public.verified.txt
deleted file mode 100644
index 95c99cb..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Public.verified.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object"
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithInternalProperties.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithInternalProperties.verified.txt
deleted file mode 100644
index 95c99cb..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithInternalProperties.verified.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object"
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithInvalidProperties.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithInvalidProperties.verified.txt
deleted file mode 100644
index 95c99cb..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithInvalidProperties.verified.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object"
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithUnsupportedDictionaryKey.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithUnsupportedDictionaryKey.verified.txt
deleted file mode 100644
index b92a62e..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithUnsupportedDictionaryKey.verified.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "data": {
- "type": "object",
- "$comment": "Ensure key type 'Address' is convertible to string.",
- "additionalProperties": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32"
- },
- "title": "Data"
- }
- },
- "required": [
- "data"
- ]
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithAbstractParameters.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithAbstractParameters.verified.txt
deleted file mode 100644
index 96fc2e8..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithAbstractParameters.verified.txt
+++ /dev/null
@@ -1,114 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "card": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card",
- "title": "Card"
- },
- "deck": {
- "type": "array",
- "items": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
- },
- "title": "Deck"
- }
- },
- "required": [
- "card",
- "deck"
- ],
- "$defs": {
- "T:SharpSchema.Generator.TestData.Card.FaceKind": {
- "type": "string",
- "enum": [
- "NotFaceCard",
- "jack",
- "queen",
- "king",
- "ace"
- ],
- "title": "Face Kind"
- },
- "T:SharpSchema.Generator.TestData.Card.AceOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.KingOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.QueenOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.JackOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.TenOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card": {
- "type": "object",
- "oneOf": [
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.AceOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.KingOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.QueenOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.JackOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.TenOfSpades"
- }
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithParametersAndProperties.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithParametersAndProperties.verified.txt
deleted file mode 100644
index 9b06269..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithParametersAndProperties.verified.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "title": "Name"
- },
- "age": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
- "title": "Age"
- },
- "address": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Address",
- "title": "Address"
- }
- },
- "required": [
- "name",
- "age",
- "address"
- ],
- "$defs": {
- "T:SharpSchema.Generator.TestData.Address": {
- "type": "object",
- "properties": {
- "street": {
- "type": "string",
- "title": "Street"
- },
- "city": {
- "type": "string",
- "title": "City"
- }
- },
- "required": [
- "street",
- "city"
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithReferenceTypeParameters.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithReferenceTypeParameters.verified.txt
deleted file mode 100644
index 284ac24..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithReferenceTypeParameters.verified.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "address": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Address",
- "title": "Address Title",
- "description": "Address Description",
- "$comment": "This is just a test"
- },
- "nullableAddress": {
- "oneOf": [
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Address"
- },
- {
- "type": "null"
- }
- ],
- "title": "Nullable Address",
- "deprecated": true
- },
- "addresses": {
- "oneOf": [
- {
- "type": "array",
- "items": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Address"
- }
- },
- {
- "type": "null"
- }
- ],
- "title": "Addresses Title"
- }
- },
- "required": [
- "address"
- ],
- "$defs": {
- "T:SharpSchema.Generator.TestData.Address": {
- "type": "object",
- "properties": {
- "street": {
- "type": "string",
- "title": "Street"
- },
- "city": {
- "type": "string",
- "title": "City"
- }
- },
- "required": [
- "street",
- "city"
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithReferenceTypeProperties.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithReferenceTypeProperties.verified.txt
deleted file mode 100644
index 29c3c1e..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithReferenceTypeProperties.verified.txt
+++ /dev/null
@@ -1,87 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "title": "Name"
- },
- "age": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
- "title": "Age"
- },
- "person": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Person",
- "title": "Person"
- }
- },
- "required": [
- "name",
- "age",
- "person"
- ],
- "$defs": {
- "T:SharpSchema.Generator.TestData.Address": {
- "type": "object",
- "properties": {
- "street": {
- "type": "string",
- "title": "Street"
- },
- "city": {
- "type": "string",
- "title": "City"
- }
- },
- "required": [
- "street",
- "city"
- ]
- },
- "T:SharpSchema.Generator.TestData.Office": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "title": "Name"
- },
- "address": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Address",
- "title": "Address"
- }
- },
- "required": [
- "name",
- "address"
- ]
- },
- "T:SharpSchema.Generator.TestData.Person": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "title": "Name"
- },
- "age": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
- "title": "Age"
- },
- "office": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Office",
- "title": "Office"
- }
- },
- "required": [
- "name",
- "age",
- "office"
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Struct_WithAbstractProperties.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Struct_WithAbstractProperties.verified.txt
deleted file mode 100644
index 3f36192..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Struct_WithAbstractProperties.verified.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "abstract": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.AbstractClass",
- "title": "Abstract"
- },
- "concrete": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Class_ExtendsAbstractClass",
- "title": "Concrete"
- }
- },
- "required": [
- "abstract",
- "concrete"
- ],
- "$defs": {
- "T:SharpSchema.Generator.TestData.Class_ExtendsAbstractClass": {
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "title": "Name"
- }
- },
- "required": [
- "name"
- ]
- },
- "T:SharpSchema.Generator.TestData.AbstractClass": {
- "type": "object",
- "oneOf": [
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Class_ExtendsAbstractClass"
- }
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Struct_WithNullableValueTypes.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Struct_WithNullableValueTypes.verified.txt
deleted file mode 100644
index 808498b..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Struct_WithNullableValueTypes.verified.txt
+++ /dev/null
@@ -1,185 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "string": {
- "oneOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "title": "String"
- },
- "int": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32"
- },
- {
- "type": "null"
- }
- ],
- "title": "Int"
- },
- "byte": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": 0,
- "maximum": 255,
- "$comment": "System.Byte"
- },
- {
- "type": "null"
- }
- ],
- "title": "Byte"
- },
- "sByte": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": -128,
- "maximum": 127,
- "$comment": "System.SByte"
- },
- {
- "type": "null"
- }
- ],
- "title": "S Byte"
- },
- "short": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": -32768,
- "maximum": 32767,
- "$comment": "System.Int16"
- },
- {
- "type": "null"
- }
- ],
- "title": "Short"
- },
- "uShort": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": 0,
- "maximum": 65535,
- "$comment": "System.UInt16"
- },
- {
- "type": "null"
- }
- ],
- "title": "U Short"
- },
- "uInt": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": 0,
- "maximum": 4294967295,
- "$comment": "System.UInt32"
- },
- {
- "type": "null"
- }
- ],
- "title": "U Int"
- },
- "long": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": -9223372036854775808,
- "maximum": 9223372036854775807,
- "$comment": "System.Int64"
- },
- {
- "type": "null"
- }
- ],
- "title": "Long"
- },
- "uLong": {
- "oneOf": [
- {
- "type": "integer",
- "minimum": 0,
- "maximum": 18446744073709551615,
- "$comment": "System.UInt64"
- },
- {
- "type": "null"
- }
- ],
- "title": "U Long"
- },
- "float": {
- "oneOf": [
- {
- "type": "number",
- "minimum": -79228162514264337593543950335,
- "maximum": 79228162514264337593543950335,
- "$comment": "System.Single"
- },
- {
- "type": "null"
- }
- ],
- "title": "Float"
- },
- "double": {
- "oneOf": [
- {
- "type": "number",
- "minimum": -79228162514264337593543950335,
- "maximum": 79228162514264337593543950335,
- "$comment": "System.Double"
- },
- {
- "type": "null"
- }
- ],
- "title": "Double"
- },
- "decimal": {
- "oneOf": [
- {
- "type": "number",
- "minimum": -79228162514264337593543950335,
- "maximum": 79228162514264337593543950335,
- "$comment": "System.Decimal"
- },
- {
- "type": "null"
- }
- ],
- "title": "Decimal"
- },
- "char": {
- "oneOf": [
- {
- "type": "string",
- "minLength": 1,
- "maxLength": 1,
- "$comment": "System.Char"
- },
- {
- "type": "null"
- }
- ],
- "title": "Char"
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Silent.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Silent.verified.txt
deleted file mode 100644
index 10242cd..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Silent.verified.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "data": {
- "type": "object",
- "additionalProperties": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32"
- },
- "title": "Data"
- }
- },
- "required": [
- "data"
- ]
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Skip.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Skip.verified.txt
deleted file mode 100644
index 10802ee..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Skip.verified.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "data": {
- "title": "Data"
- }
- },
- "required": [
- "data"
- ]
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Strict.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Strict.verified.txt
deleted file mode 100644
index f00504c..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Strict.verified.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "data": {
- "$unsupportedObject": "Key type 'Address' must be string.",
- "title": "Data"
- }
- },
- "required": [
- "data"
- ]
-}
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_EnumHandling_enumHandling=String.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_EnumHandling_enumHandling=String.verified.txt
deleted file mode 100644
index 96fc2e8..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_EnumHandling_enumHandling=String.verified.txt
+++ /dev/null
@@ -1,114 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "card": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card",
- "title": "Card"
- },
- "deck": {
- "type": "array",
- "items": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
- },
- "title": "Deck"
- }
- },
- "required": [
- "card",
- "deck"
- ],
- "$defs": {
- "T:SharpSchema.Generator.TestData.Card.FaceKind": {
- "type": "string",
- "enum": [
- "NotFaceCard",
- "jack",
- "queen",
- "king",
- "ace"
- ],
- "title": "Face Kind"
- },
- "T:SharpSchema.Generator.TestData.Card.AceOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.KingOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.QueenOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.JackOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.TenOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card": {
- "type": "object",
- "oneOf": [
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.AceOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.KingOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.QueenOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.JackOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.TenOfSpades"
- }
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_EnumHandling_enumHandling=UnderlyingType.verified.txt b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_EnumHandling_enumHandling=UnderlyingType.verified.txt
deleted file mode 100644
index 30a03fd..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_EnumHandling_enumHandling=UnderlyingType.verified.txt
+++ /dev/null
@@ -1,110 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "type": "object",
- "properties": {
- "card": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card",
- "title": "Card"
- },
- "deck": {
- "type": "array",
- "items": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
- },
- "title": "Deck"
- }
- },
- "required": [
- "card",
- "deck"
- ],
- "$defs": {
- "T:SharpSchema.Generator.TestData.Card.FaceKind": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
- "title": "Face Kind"
- },
- "T:SharpSchema.Generator.TestData.Card.AceOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.KingOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.QueenOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.JackOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card.TenOfSpades": {
- "type": "object",
- "properties": {
- "face": {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.FaceKind",
- "title": "Face"
- }
- },
- "required": [
- "face"
- ]
- },
- "T:SharpSchema.Generator.TestData.Card": {
- "type": "object",
- "oneOf": [
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.AceOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.KingOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.QueenOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.JackOfSpades"
- },
- {
- "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.TenOfSpades"
- }
- ]
- }
- }
-}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.cs b/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.cs
deleted file mode 100644
index a3a4702..0000000
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using Json.Schema;
-using SharpSchema.Generator;
-using SharpSchema.Generator.TestData;
-using SharpSchema.Generator.Utilities;
-using SharpSchema.Test.Generator.TestUtilities;
-using VerifyXunit;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace SharpSchema.Test.Generator.RootDeclaredTypeSyntaxVisitorTests;
-
-public class VerifyTests : IDisposable, IClassFixture
-{
- private readonly ITestOutputHelper _output;
- private readonly TestDataFixture _fixture;
-
- public VerifyTests(TestDataFixture fixture, ITestOutputHelper outputHelper)
- {
- _fixture = fixture;
- Tracer.Writer = outputHelper.WriteLine;
- _output = outputHelper;
- }
-
- public void Dispose() => Tracer.Writer = null;
-
- [Theory]
- [InlineData(nameof(Struct_WithNullableValueTypes))]
- [InlineData(nameof(Struct_WithAbstractProperties))]
- [InlineData(nameof(Record_WithReferenceTypeProperties))]
- [InlineData(nameof(Record_WithReferenceTypeParameters))]
- [InlineData(nameof(Record_WithValueTypeParameters))]
- [InlineData(nameof(Record_WithSchemaOverride))]
- [InlineData(nameof(Record_WithIgnoredParameter))]
- [InlineData(nameof(Record_WithParametersAndProperties))]
- [InlineData(nameof(Record_WithAbstractParameters))]
- [InlineData(nameof(Class_WithDictionaryProperties))]
- [InlineData(nameof(Class_WithDocComments))]
- [InlineData(nameof(Class_WithValueTypes))]
- [InlineData(nameof(Class_WithSchemaOverride))]
- [InlineData(nameof(Class_WithTypeSchemaOverride))]
- [InlineData(nameof(Class_WithUnsupportedDictionaryKey))]
- [InlineData(nameof(Class_WithIgnoredProperty))]
- [InlineData(nameof(Class_WithInternalProperties))]
- [InlineData(nameof(Class_WithArrayProperties))]
- [InlineData(nameof(Class_WithInvalidProperties))]
- [InlineData(nameof(Class_ExtendsAbstractClass))]
- [InlineData(nameof(Record_WithGenericAbstractProperty), Skip = "Not Yet Implemented")]
- public Task Verify_DefaultOptions(string testName)
- {
- RootDeclaredTypeSyntaxVisitor visitor = _fixture.GetVisitor(GeneratorOptions.Default);
- JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, testName);
- _output.WriteSeparator();
- string schemaString = builder.Build().SerializeToJson();
- _output.WriteLine(schemaString);
- return Verifier.Verify(schemaString).UseParameters(testName);
- }
-
- [InlineData(DictionaryKeyMode.Loose)]
- [InlineData(DictionaryKeyMode.Strict)]
- [InlineData(DictionaryKeyMode.Silent)]
- [InlineData(DictionaryKeyMode.Skip)]
- [Theory]
- public Task Verify_DictionaryKeyMode(DictionaryKeyMode dictionaryKeyMode)
- {
- GeneratorOptions options = new()
- {
- DictionaryKeyMode = dictionaryKeyMode
- };
-
- RootDeclaredTypeSyntaxVisitor visitor = _fixture.GetVisitor(options);
- JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Class_WithUnsupportedDictionaryKey));
- _output.WriteSeparator();
- string schemaString = builder.Build().SerializeToJson();
- _output.WriteLine(schemaString);
- return Verifier.Verify(schemaString).UseParameters(dictionaryKeyMode);
- }
-
- [InlineData(Accessibilities.Public)]
- [InlineData(Accessibilities.Internal)]
- [InlineData(Accessibilities.Private)]
- [InlineData(Accessibilities.PublicInternal)]
- [Theory]
- public Task Verify_Accessibilities(Accessibilities accessibilities)
- {
- GeneratorOptions options = new()
- {
- Accessibilities = accessibilities
- };
-
- RootDeclaredTypeSyntaxVisitor visitor = _fixture.GetVisitor(options);
- JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Class_WithInternalProperties));
- _output.WriteSeparator();
- string schemaString = builder.Build().SerializeToJson();
- _output.WriteLine(schemaString);
- return Verifier.Verify(schemaString).UseParameters(accessibilities);
- }
-
- [InlineData(EnumHandling.String)]
- [InlineData(EnumHandling.UnderlyingType)]
- [Theory]
- public Task Verify_EnumHandling(EnumHandling enumHandling)
- {
- GeneratorOptions options = new()
- {
- EnumHandling = enumHandling
- };
- RootDeclaredTypeSyntaxVisitor visitor = _fixture.GetVisitor(options);
- JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Record_WithAbstractParameters));
- _output.WriteSeparator();
- string schemaString = builder.Build().SerializeToJson();
- _output.WriteLine(schemaString);
- return Verifier.Verify(schemaString).UseParameters(enumHandling);
- }
-
- [InlineData(Traversal.SymbolOnly)]
- [InlineData(Traversal.Bases)]
- [InlineData(Traversal.Interfaces)]
- [InlineData(Traversal.Full)]
- [Theory]
- public Task Verify_Traversal(Traversal traversal)
- {
- GeneratorOptions options = new()
- {
- Traversal = traversal
- };
-
- RootDeclaredTypeSyntaxVisitor visitor = _fixture.GetVisitor(options);
- JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Class_ExtendsAbstractClass));
- _output.WriteSeparator();
- string schemaString = builder.Build().SerializeToJson();
- _output.WriteLine(schemaString);
- return Verifier.Verify(schemaString).UseParameters(traversal);
- }
-}
diff --git a/test/Generator/RootSyntaxVisitorTests/TestData.Attributes.cs b/test/Generator/RootSyntaxVisitorTests/TestData.Attributes.cs
new file mode 100644
index 0000000..16bd577
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/TestData.Attributes.cs
@@ -0,0 +1,78 @@
+#pragma warning disable IDE0130 // Namespace does not match folder structure
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+namespace SharpSchema.Generator.TestData;
+
+using System.Collections.Generic;
+using SharpSchema.Annotations;
+
+public class DictionaryKey_Default
+{
+ public Dictionary StringKey { get; set; }
+
+ public Dictionary IntKey { get; set; }
+
+ public Dictionary ClassKey { get; set; }
+}
+
+public class DictionaryKey_PropertyOverride
+{
+ public Dictionary StringKey { get; set; }
+
+ [SchemaDictionaryKeyMode(DictionaryKeyMode.Silent)]
+ public Dictionary IntKey { get; set; }
+
+ [SchemaDictionaryKeyMode(DictionaryKeyMode.Loose)]
+ public Dictionary BoolKey { get; set; }
+
+ [SchemaDictionaryKeyMode(DictionaryKeyMode.Strict)]
+ public Dictionary ClassKey { get; set; }
+}
+
+public class DictionaryKey_NestedOverride
+{
+ public DictionaryKey_Default Default { get; set; }
+
+ public DictionaryKey_PropertyOverride PropertyOverride { get; set; }
+}
+
+public class Accessibility_Default
+{
+ public string Public { get; set; }
+
+ internal string Internal { get; set; }
+
+ protected string Protected { get; set; }
+
+ protected internal string ProtectedInternal { get; set; }
+
+ private string Private { get; set; }
+}
+
+[SchemaAccessibilityMode(AccessibilityMode.Internal | AccessibilityMode.Private)]
+public class Accessibility_ClassOverride
+{
+ public string Public { get; set; }
+
+ internal string Internal { get; set; }
+
+ protected string Protected { get; set; }
+
+ protected internal string ProtectedInternal { get; set; }
+
+ private string Private { get; set; }
+}
+
+public class Accessibility_NestedDefault
+{
+ public Accessibility_Default Default { get; set; }
+
+ public Accessibility_ClassOverride ClassOverride { get; set; }
+}
+
+[SchemaAccessibilityMode(AccessibilityMode.Any)]
+public class Accessibility_NestedOverride
+{
+ private Accessibility_Default Default { get; set; }
+
+ internal Accessibility_ClassOverride ClassOverride { get; set; }
+}
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/TestData.cs b/test/Generator/RootSyntaxVisitorTests/TestData.cs
similarity index 65%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/TestData.cs
rename to test/Generator/RootSyntaxVisitorTests/TestData.cs
index 8e07764..b24e852 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/TestData.cs
+++ b/test/Generator/RootSyntaxVisitorTests/TestData.cs
@@ -1,13 +1,58 @@
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Linq;
using System.Text.Json.Serialization;
using SharpSchema.Annotations;
#pragma warning disable IDE0130 // Namespace does not match folder structure
namespace SharpSchema.Generator.TestData;
+using Test.Generator.RootSyntaxVisitorTests;
+
+
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+public record Record_WithValueParameters(string Name, int Age);
+
+public record Record_WithDefaultValueParameter(string Name, int Age = 42);
+
+public record Record_WithNullableParameters(string? Name, int? Age);
+
+public record Record_WithValueParametersAndProperty(string Name, int Age)
+{
+ public string Title { get; set; }
+}
+
+public record Record_WithValueParametersAndPropertyInitializer(string Name, int Age)
+{
+ public string Title { get; set; } = "How to make a record";
+}
+
+public record Record_WithDefaultValueParametersAndConstantProperty(string Name, int Age = 42)
+{
+ public string Title => "How to make a record";
+}
+
+///
+/// Demonstrates param-based XML metadata.
+///
+///
+///
+/// NameOfRecord
+/// The record's name.
+/// John Doe
+///
+///
+///
+///
+/// AgeOfRecord
+/// The record's age.
+/// 42
+///
+///
+public record Record_WithDocComments(string Name, int Age = 42);
+
+
public class Class_WithDocComments
{
///
@@ -69,11 +114,13 @@ public class Class_WithArrayProperties
public class Class_WithInvalidProperties
{
+ public int Mutable { get; set; }
+
+ public int Immutable { get; }
+
public string Name { set { } }
public static string Static { get; set; }
-
- public virtual string Virtual { get; set; }
}
public class Class_WithDictionaryProperties
@@ -84,29 +131,14 @@ public class Class_WithDictionaryProperties
}
+///
+///
+///
public class Class_WithUnsupportedDictionaryKey
{
public Dictionary Data { get; set; }
}
-///
-/// Demonstrates param-based XML metadata.
-///
-///
-///
-/// NameOfRecord
-/// The record's name.
-/// John Doe
-///
-///
-///
-///
-/// AgeOfRecord
-/// The record's age.
-/// 42
-///
-///
-public record Record_WithValueTypeParameters(string Name, int Age = 42);
public record Record_WithReferenceTypeParameters(
[SchemaMeta(
@@ -120,10 +152,6 @@ public record Record_WithReferenceTypeParameters(
Title = "Addresses Title")]
List? Addresses);
-public record Record_WithParametersAndProperties(string Name, int Age)
-{
- public required Address Address { get; set; }
-}
public struct Struct_WithNullableValueTypes
{
@@ -155,15 +183,6 @@ public struct Struct_WithNullableValueTypes
}
-public record Record_WithReferenceTypeProperties
-{
- public string Name { get; set; }
-
- public int Age { get; set; }
-
- public Person Person { get; set; }
-}
-
public class Class_WithSchemaOverride
{
[SchemaOverride("{\"type\":\"string\",\"maxLength\":50}")]
@@ -191,7 +210,7 @@ public class Class_WithIgnoredProperty
[SchemaIgnore]
public string Ignored { get; set; }
- [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
+ [SchemaIgnore]
public string AlsoIgnored { get; set; }
public string NotIgnored { get; set; }
@@ -202,8 +221,13 @@ public record Record_WithIgnoredParameter(
string NotIgnored
);
+///
+///
+///
public record Class_WithInternalProperties
{
+ public string Public { get; set; }
+
internal string Internal { get; set; }
protected string Protected { get; set; }
@@ -220,9 +244,14 @@ public class Class_WithRequiredProperties
public string? Optional { get; set; }
[SchemaRequired]
+ public string? DefaultRequired { get; set; } = "default";
+
public string? Default { get; set; } = "default";
}
+// -- Not Tested -- //
+
+
public class Class_ExtendsAbstractClass : AbstractClass
{
public override string Name { get; set; }
@@ -240,10 +269,10 @@ public record Record_WithAbstractParameters(Card Card, ImmutableArray Deck
public record Record_WithGenericAbstractProperty
{
public MagicStack Stack { get; set; }
-
- public CardStack CardStack { get; set; }
}
+public record MagicStack(List Cards);
+
[SchemaOverride("{invalidJson}")]
public record BadOverride();
@@ -289,67 +318,115 @@ public abstract class AbstractClass
public int Age { get; set; }
}
-public class MagicStack : CardStack
+public class GameHall
{
- public List Stack = [];
+ public string Name { get; set; }
+
+ public Dictionary Rooms { get; set; }
+}
+
+public struct GameRoom
+{
+ public string Name { get; set; }
- public override Card.AceOfSpades Peek() => this.Stack[^1];
+ public Table WildCardTable { get; set; }
- public override void Push(Card.AceOfSpades card) => this.Stack.Add(card);
+ public PokerTable PokerTable { get; set; }
+
+ public BlackjackTable BlackjackTable { get; set; }
+
+ public BridgeTable BridgeTable { get; set; }
}
-public abstract class CardStack
- where TCard : Card
+public abstract record Table(int PlayerCount) where T : BaseHand
{
- public abstract TCard Peek();
+ public abstract T? DealerHand { get; }
- public abstract void Push(TCard card);
+ public IReadOnlyCollection Hands { get; }
}
-public abstract record Card(Card.SuitKind Suit, int Value)
+public record PokerTable(int PlayerCount) : Table(PlayerCount)
{
- public enum SuitKind : byte
- {
- Spades,
- Hearts,
- Clubs,
- Diamonds
- }
+ public override BaseHand.Poker DealerHand { get; }
+}
- public enum FaceKind
- {
- [SchemaEnumValue("NotFaceCard")]
- None,
- Jack,
- Queen,
- King,
- Ace
- }
+public record BlackjackTable(int PlayerCount) : Table(PlayerCount)
+{
+ public override BaseHand.Blackjack DealerHand { get; }
+}
+
+public record BridgeTable(int PlayerCount) : Table(PlayerCount)
+{
+ public override BaseHand.Bridge? DealerHand => null;
+}
+
+public record WhistTable(int PlayerCount) : Table(PlayerCount)
+{
+ public override BaseHand.Bridge? DealerHand => null;
+}
- public abstract FaceKind Face { get; }
+public abstract record BaseHand(int Size)
+{
+ public abstract string Game { get; }
+
+ public List Cards { get; set; }
- public record AceOfSpades() : Card(SuitKind.Spades, 1)
+ public record Poker() : BaseHand(5)
{
- public override FaceKind Face => FaceKind.Ace;
+ public override string Game => "Poker";
+
+ public bool IsRoyalFlush => Cards.Count == Size && Cards.All(c => c.IsFaceCard);
}
- public record KingOfSpades() : Card(SuitKind.Spades, 13)
+ public record Blackjack() : BaseHand(2)
{
- public override FaceKind Face => FaceKind.King;
+ public override string Game => "Blackjack";
+
+ public int Value => Cards.Sum(c => c.Rank switch
+ {
+ Card.RankKind.Ace => 11,
+ Card.RankKind.Jack => 10,
+ Card.RankKind.Queen => 10,
+ Card.RankKind.King => 10,
+ _ => (int)c.Rank
+ });
}
- public record QueenOfSpades() : Card(SuitKind.Spades, 12)
+ public record Bridge() : BaseHand(13)
{
- public override FaceKind Face => FaceKind.Queen;
+ public override string Game => "Bridge";
+
+ public bool IsNoTrump => Cards.All(c => c.Suit == Card.SuitKind.Spades);
}
+}
+
+
+public record Card(Card.SuitKind Suit, Card.RankKind Rank)
+{
+ public bool IsFaceCard => Rank >= RankKind.Jack;
- public record JackOfSpades() : Card(SuitKind.Spades, 11)
+ public enum SuitKind
{
- public override FaceKind Face => FaceKind.Jack;
+ Spades,
+ Hearts,
+ Clubs,
+ Diamonds
}
- public record TenOfSpades() : Card(SuitKind.Spades, 10)
+ public enum RankKind
{
- public override FaceKind Face => FaceKind.None;
+ Ace,
+ Two,
+ Three,
+ Four,
+ Five,
+ Six,
+ Seven,
+ Eight,
+ Nine,
+ Ten,
+ Jack,
+ Queen,
+ King
}
}
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/TestDataFixture.cs b/test/Generator/RootSyntaxVisitorTests/TestDataFixture.cs
similarity index 73%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/TestDataFixture.cs
rename to test/Generator/RootSyntaxVisitorTests/TestDataFixture.cs
index 98571b0..09b7918 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/TestDataFixture.cs
+++ b/test/Generator/RootSyntaxVisitorTests/TestDataFixture.cs
@@ -8,13 +8,12 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.IO;
using Xunit;
-using DiffEngine;
using SharpSchema.Generator;
using SharpSchema.Test.Generator.TestUtilities;
using System.Collections.Immutable;
using System.Text.Json.Serialization;
-namespace SharpSchema.Test.Generator.RootDeclaredTypeSyntaxVisitorTests;
+namespace SharpSchema.Test.Generator.RootSyntaxVisitorTests;
public class TestDataFixture
{
@@ -23,20 +22,30 @@ public class TestDataFixture
public TestDataFixture()
{
- DiffRunner.Disabled = true;
string pathToTestData = PathHelper.GetRepoPath(
"test",
"Generator",
- "RootDeclaredTypeSyntaxVisitorTests",
+ "RootSyntaxVisitorTests",
"TestData.cs");
+ string pathToAccessibility = PathHelper.GetRepoPath(
+ "test",
+ "Generator",
+ "RootSyntaxVisitorTests",
+ "TestData.Attributes.cs");
+
// Create an array of syntax tree from all cs files in src/SharpSchema.Annotations/
string[] annotationFiles = Directory.GetFiles(
PathHelper.GetRepoPath("src", "SharpSchema.Annotations"), "*.cs", SearchOption.AllDirectories);
List annotationSyntaxTrees = [.. annotationFiles.Select(file => CSharpSyntaxTree.ParseText(File.ReadAllText(file)))];
- _syntaxTree = CSharpSyntaxTree.ParseText(File.ReadAllText(pathToTestData));
+ _syntaxTree = CSharpSyntaxTree.ParseText(
+ string.Join(
+ Environment.NewLine,
+ File.ReadAllText(pathToTestData),
+ File.ReadAllText(pathToAccessibility)));
+
_compilation = CSharpCompilation.Create("TestDataCompilation")
.AddReferences(
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
@@ -45,9 +54,9 @@ public TestDataFixture()
.AddSyntaxTrees([.. annotationSyntaxTrees, _syntaxTree]);
}
- public RootDeclaredTypeSyntaxVisitor GetVisitor(GeneratorOptions options) => new(_compilation, options);
+ public RootSyntaxVisitor GetVisitor(GeneratorOptions options) => new(_compilation, options);
- public JsonSchemaBuilder GetJsonSchemaBuilder(RootDeclaredTypeSyntaxVisitor visitor, [CallerMemberName] string? testName = null)
+ public JsonSchemaBuilder GetJsonSchemaBuilder(RootSyntaxVisitor visitor, [CallerMemberName] string? testName = null)
{
ArgumentNullException.ThrowIfNull(visitor);
ArgumentNullException.ThrowIfNull(testName);
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Internal.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Internal.verified.txt
similarity index 82%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Internal.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Internal.verified.txt
index 68fb175..a57cef1 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Internal.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Internal.verified.txt
@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with internal properties",
"properties": {
"internal": {
"type": "string",
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Private.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Private.verified.txt
similarity index 82%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Private.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Private.verified.txt
index c84de0f..b65799f 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=Private.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Private.verified.txt
@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with internal properties",
"properties": {
"private": {
"type": "string",
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_ExtendsAbstractClass.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Public.verified.txt
similarity index 61%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_ExtendsAbstractClass.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Public.verified.txt
index 03fd3c2..546e0be 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_ExtendsAbstractClass.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_Public.verified.txt
@@ -1,13 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with internal properties",
"properties": {
- "name": {
+ "public": {
"type": "string",
- "title": "Name"
+ "title": "Public"
}
},
"required": [
- "name"
+ "public"
]
}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_PublicInternal.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_PublicInternal.verified.txt
new file mode 100644
index 0000000..a6e0c5d
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityMode_PublicInternal.verified.txt
@@ -0,0 +1,19 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with internal properties",
+ "properties": {
+ "public": {
+ "type": "string",
+ "title": "Public"
+ },
+ "internal": {
+ "type": "string",
+ "title": "Internal"
+ }
+ },
+ "required": [
+ "public",
+ "internal"
+ ]
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_ClassOverride.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_ClassOverride.verified.txt
new file mode 100644
index 0000000..1b2f82d
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_ClassOverride.verified.txt
@@ -0,0 +1,19 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Accessibility class override",
+ "properties": {
+ "internal": {
+ "type": "string",
+ "title": "Internal"
+ },
+ "private": {
+ "type": "string",
+ "title": "Private"
+ }
+ },
+ "required": [
+ "internal",
+ "private"
+ ]
+}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=PublicInternal.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_Default.verified.txt
similarity index 63%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=PublicInternal.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_Default.verified.txt
index 68fb175..e5b3128 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Accessibilities_accessibilities=PublicInternal.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_Default.verified.txt
@@ -1,13 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Accessibility default",
"properties": {
- "internal": {
+ "public": {
"type": "string",
- "title": "Internal"
+ "title": "Public"
}
},
"required": [
- "internal"
+ "public"
]
}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_NestedDefault.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_NestedDefault.verified.txt
new file mode 100644
index 0000000..f735ff0
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_NestedDefault.verified.txt
@@ -0,0 +1,52 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Accessibility nested default",
+ "properties": {
+ "default": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_Default",
+ "title": "Default"
+ },
+ "classOverride": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_ClassOverride",
+ "title": "Class override"
+ }
+ },
+ "required": [
+ "default",
+ "classOverride"
+ ],
+ "$defs": {
+ "T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_ClassOverride": {
+ "type": "object",
+ "title": "Accessibility class override",
+ "properties": {
+ "internal": {
+ "type": "string",
+ "title": "Internal"
+ },
+ "private": {
+ "type": "string",
+ "title": "Private"
+ }
+ },
+ "required": [
+ "internal",
+ "private"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_Default": {
+ "type": "object",
+ "title": "Accessibility default",
+ "properties": {
+ "public": {
+ "type": "string",
+ "title": "Public"
+ }
+ },
+ "required": [
+ "public"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_NestedOverride.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_NestedOverride.verified.txt
new file mode 100644
index 0000000..31f9692
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/AccessibilityOverride_Accessibility_NestedOverride.verified.txt
@@ -0,0 +1,52 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Accessibility nested override",
+ "properties": {
+ "default": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_Default",
+ "title": "Default"
+ },
+ "classOverride": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_ClassOverride",
+ "title": "Class override"
+ }
+ },
+ "required": [
+ "default",
+ "classOverride"
+ ],
+ "$defs": {
+ "T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_ClassOverride": {
+ "type": "object",
+ "title": "Accessibility class override",
+ "properties": {
+ "internal": {
+ "type": "string",
+ "title": "Internal"
+ },
+ "private": {
+ "type": "string",
+ "title": "Private"
+ }
+ },
+ "required": [
+ "internal",
+ "private"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.Accessibility_Default": {
+ "type": "object",
+ "title": "Accessibility default",
+ "properties": {
+ "public": {
+ "type": "string",
+ "title": "Public"
+ }
+ },
+ "required": [
+ "public"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Bases.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_ExtendsAbstractClass.verified.txt
similarity index 61%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Bases.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_ExtendsAbstractClass.verified.txt
index 8354a29..8a61578 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Bases.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_ExtendsAbstractClass.verified.txt
@@ -1,21 +1,25 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class extends abstract class",
"properties": {
- "age": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
- "title": "Age"
- },
"name": {
"type": "string",
"title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Age"
}
},
"required": [
- "name",
- "age"
- ]
+ "name"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithArrayProperties.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithArrayProperties.verified.txt
similarity index 79%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithArrayProperties.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithArrayProperties.verified.txt
index 663796d..aa1a33a 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithArrayProperties.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithArrayProperties.verified.txt
@@ -1,16 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with array properties",
"properties": {
"numbersArray": {
"type": "array",
"items": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32"
+ "$ref": "#/$defs/T:System.Int32"
},
- "title": "Numbers Array"
+ "title": "Numbers array"
},
"names": {
"type": "array",
@@ -43,12 +41,9 @@
"numbersList": {
"type": "array",
"items": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32"
+ "$ref": "#/$defs/T:System.Int32"
},
- "title": "Numbers List"
+ "title": "Numbers list"
},
"stringsEnumerable": {
"oneOf": [
@@ -62,14 +57,14 @@
"type": "null"
}
],
- "title": "Strings Enumerable"
+ "title": "Strings enumerable"
},
"stringImmutableArray": {
"type": "array",
"items": {
"type": "string"
},
- "title": "String Immutable Array"
+ "title": "String immutable array"
}
},
"required": [
@@ -81,6 +76,7 @@
"$defs": {
"T:SharpSchema.Generator.TestData.Address": {
"type": "object",
+ "title": "Address",
"properties": {
"street": {
"type": "string",
@@ -95,6 +91,11 @@
"street",
"city"
]
+ },
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
}
}
}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithDictionaryProperties.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithDictionaryProperties.verified.txt
similarity index 72%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithDictionaryProperties.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithDictionaryProperties.verified.txt
index 10275ce..e8ff5bd 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithDictionaryProperties.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithDictionaryProperties.verified.txt
@@ -1,23 +1,21 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with dictionary properties",
"properties": {
"valueTypes": {
"type": "object",
"additionalProperties": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32"
+ "$ref": "#/$defs/T:System.Int32"
},
- "title": "Value Types"
+ "title": "Value types"
},
"referenceTypes": {
"type": "object",
"additionalProperties": {
"$ref": "#/$defs/T:SharpSchema.Generator.TestData.Address"
},
- "title": "Reference Types"
+ "title": "Reference types"
}
},
"required": [
@@ -27,6 +25,7 @@
"$defs": {
"T:SharpSchema.Generator.TestData.Address": {
"type": "object",
+ "title": "Address",
"properties": {
"street": {
"type": "string",
@@ -41,6 +40,11 @@
"street",
"city"
]
+ },
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
}
}
}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithDocComments.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithDocComments.verified.txt
similarity index 70%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithDocComments.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithDocComments.verified.txt
index fdb32bb..d498641 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithDocComments.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithDocComments.verified.txt
@@ -1,16 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with doc comments",
"properties": {
"name": {
"type": "string",
"title": "The name of the person."
},
"age": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
+ "$ref": "#/$defs/T:System.Int32",
"title": "Age",
"description": "The age of the person."
}
@@ -18,5 +16,12 @@
"required": [
"name",
"age"
- ]
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithIgnoredProperty.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithIgnoredProperty.verified.txt
similarity index 73%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithIgnoredProperty.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithIgnoredProperty.verified.txt
index 8de934f..2140eac 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithIgnoredProperty.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithIgnoredProperty.verified.txt
@@ -1,10 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with ignored property",
"properties": {
"notIgnored": {
"type": "string",
- "title": "Not Ignored"
+ "title": "Not ignored"
}
},
"required": [
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithInvalidProperties.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithInvalidProperties.verified.txt
new file mode 100644
index 0000000..24d522b
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithInvalidProperties.verified.txt
@@ -0,0 +1,26 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with invalid properties",
+ "properties": {
+ "mutable": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Mutable"
+ },
+ "immutable": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Immutable"
+ }
+ },
+ "required": [
+ "mutable",
+ "immutable"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithRequiredProperties.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithRequiredProperties.verified.txt
new file mode 100644
index 0000000..2d7d24e
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithRequiredProperties.verified.txt
@@ -0,0 +1,69 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with required properties",
+ "properties": {
+ "requiredInt": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Int32"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Required int"
+ },
+ "required": {
+ "type": "string",
+ "title": "Required"
+ },
+ "optional": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Optional"
+ },
+ "defaultRequired": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": "default",
+ "title": "Default required"
+ },
+ "default": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": "default",
+ "title": "Default"
+ }
+ },
+ "required": [
+ "requiredInt",
+ "required",
+ "defaultRequired"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithSchemaOverride.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithSchemaOverride.verified.txt
similarity index 87%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithSchemaOverride.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithSchemaOverride.verified.txt
index 95c6637..7989690 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithSchemaOverride.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithSchemaOverride.verified.txt
@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with schema override",
"properties": {
"name": {
"type": "string",
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithTypeSchemaOverride.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithTypeSchemaOverride.verified.txt
similarity index 82%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithTypeSchemaOverride.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithTypeSchemaOverride.verified.txt
index 505a1e8..5c02023 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithTypeSchemaOverride.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Class_WithTypeSchemaOverride.verified.txt
@@ -1,10 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with type schema override",
"properties": {
"badOverride": {
"$unsupportedObject": "Failed to parse schema override: 'i' is an invalid start of a property name. Expected a '\"'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.",
- "title": "Bad Override"
+ "title": "Bad override"
},
"goodOverride": {
"type": "object",
@@ -13,7 +14,7 @@
"type": "string"
}
},
- "title": "Good Override"
+ "title": "Good override"
}
},
"required": [
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_GameHall.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_GameHall.verified.txt
new file mode 100644
index 0000000..638f365
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_GameHall.verified.txt
@@ -0,0 +1,305 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Game hall",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "rooms": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.GameRoom"
+ },
+ "title": "Rooms"
+ }
+ },
+ "required": [
+ "name",
+ "rooms"
+ ],
+ "$defs": {
+ "T:SharpSchema.Generator.TestData.BaseHand.Blackjack": {
+ "type": "object",
+ "title": "Blackjack",
+ "properties": {
+ "game": {
+ "const": "Blackjack",
+ "title": "Game",
+ "type": "string"
+ },
+ "value": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Value"
+ },
+ "size": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Size"
+ },
+ "cards": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
+ },
+ "title": "Cards"
+ }
+ },
+ "required": [
+ "game",
+ "value"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.BaseHand.Bridge": {
+ "type": "object",
+ "title": "Bridge",
+ "properties": {
+ "game": {
+ "const": "Bridge",
+ "title": "Game",
+ "type": "string"
+ },
+ "isNoTrump": {
+ "type": "boolean",
+ "title": "Is no trump"
+ },
+ "size": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Size"
+ },
+ "cards": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
+ },
+ "title": "Cards"
+ }
+ },
+ "required": [
+ "game",
+ "isNoTrump"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.BaseHand.Poker": {
+ "type": "object",
+ "title": "Poker",
+ "properties": {
+ "game": {
+ "const": "Poker",
+ "title": "Game",
+ "type": "string"
+ },
+ "isRoyalFlush": {
+ "type": "boolean",
+ "title": "Is royal flush"
+ },
+ "size": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Size"
+ },
+ "cards": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
+ },
+ "title": "Cards"
+ }
+ },
+ "required": [
+ "game",
+ "isRoyalFlush"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.BlackjackTable": {
+ "type": "object",
+ "title": "Blackjack table",
+ "properties": {
+ "playerCount": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Player count"
+ },
+ "dealerHand": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BaseHand.Blackjack",
+ "title": "Dealer hand"
+ }
+ },
+ "required": [
+ "playerCount",
+ "dealerHand"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.BridgeTable": {
+ "type": "object",
+ "title": "Bridge table",
+ "properties": {
+ "playerCount": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Player count"
+ },
+ "dealerHand": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BaseHand.Bridge"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Dealer hand"
+ }
+ },
+ "required": [
+ "playerCount"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.Card": {
+ "type": "object",
+ "title": "Card",
+ "properties": {
+ "suit": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.SuitKind",
+ "title": "Suit"
+ },
+ "rank": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.RankKind",
+ "title": "Rank"
+ },
+ "isFaceCard": {
+ "type": "boolean",
+ "title": "Is face card"
+ }
+ },
+ "required": [
+ "suit",
+ "rank",
+ "isFaceCard"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.Card.RankKind": {
+ "type": "string",
+ "enum": [
+ "ace",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "ten",
+ "jack",
+ "queen",
+ "king"
+ ],
+ "title": "Rank kind"
+ },
+ "T:SharpSchema.Generator.TestData.Card.SuitKind": {
+ "type": "string",
+ "enum": [
+ "spades",
+ "hearts",
+ "clubs",
+ "diamonds"
+ ],
+ "title": "Suit kind"
+ },
+ "T:SharpSchema.Generator.TestData.GameRoom": {
+ "type": "object",
+ "title": "Game room",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "wildCardTable": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Table`1",
+ "title": "Wild card table"
+ },
+ "pokerTable": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.PokerTable",
+ "title": "Poker table"
+ },
+ "blackjackTable": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BlackjackTable",
+ "title": "Blackjack table"
+ },
+ "bridgeTable": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BridgeTable",
+ "title": "Bridge table"
+ }
+ },
+ "required": [
+ "name",
+ "wildCardTable",
+ "pokerTable",
+ "blackjackTable",
+ "bridgeTable"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.PokerTable": {
+ "type": "object",
+ "title": "Poker table",
+ "properties": {
+ "playerCount": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Player count"
+ },
+ "dealerHand": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BaseHand.Poker",
+ "title": "Dealer hand"
+ }
+ },
+ "required": [
+ "playerCount",
+ "dealerHand"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.Table`1": {
+ "type": "object",
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.PokerTable"
+ },
+ {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BlackjackTable"
+ },
+ {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BridgeTable"
+ },
+ {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.WhistTable"
+ }
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.WhistTable": {
+ "type": "object",
+ "title": "Whist table",
+ "properties": {
+ "playerCount": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Player count"
+ },
+ "dealerHand": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.BaseHand.Bridge"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Dealer hand"
+ }
+ },
+ "required": [
+ "playerCount"
+ ]
+ },
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDefaultValueParameter.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDefaultValueParameter.verified.txt
new file mode 100644
index 0000000..b77442c
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDefaultValueParameter.verified.txt
@@ -0,0 +1,26 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Record with default value parameter",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "default": 42,
+ "title": "Age"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDefaultValueParametersAndConstantProperty.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDefaultValueParametersAndConstantProperty.verified.txt
new file mode 100644
index 0000000..2173ef1
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDefaultValueParametersAndConstantProperty.verified.txt
@@ -0,0 +1,31 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Record with default value parameters and constant property",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "default": 42,
+ "title": "Age"
+ },
+ "title": {
+ "const": "How to make a record",
+ "title": "Title"
+ }
+ },
+ "required": [
+ "name",
+ "title"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithValueTypeParameters.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDocComments.verified.txt
similarity index 65%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithValueTypeParameters.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDocComments.verified.txt
index f905db0..6f6b566 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithValueTypeParameters.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithDocComments.verified.txt
@@ -1,6 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "NameOfRecord",
+ "description": "The record's name.",
+ "examples": [
+ "John Doe"
+ ],
"properties": {
"name": {
"type": "string",
@@ -11,19 +16,23 @@
]
},
"age": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
+ "$ref": "#/$defs/T:System.Int32",
+ "default": 42,
"title": "NameOfRecord",
"description": "The record's name.",
"examples": [
"42"
- ],
- "default": 42
+ ]
}
},
"required": [
"name"
- ]
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithIgnoredParameter.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithIgnoredParameter.verified.txt
similarity index 72%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithIgnoredParameter.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithIgnoredParameter.verified.txt
index 8de934f..be454b0 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithIgnoredParameter.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithIgnoredParameter.verified.txt
@@ -1,10 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Record with ignored parameter",
"properties": {
"notIgnored": {
"type": "string",
- "title": "Not Ignored"
+ "title": "Not ignored"
}
},
"required": [
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithSchemaOverride.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithSchemaOverride.verified.txt
similarity index 86%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithSchemaOverride.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithSchemaOverride.verified.txt
index 95c6637..25a8fe0 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Record_WithSchemaOverride.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithSchemaOverride.verified.txt
@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Record with schema override",
"properties": {
"name": {
"type": "string",
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Full.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParameters.verified.txt
similarity index 65%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Full.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParameters.verified.txt
index 8354a29..8c81e3a 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Full.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParameters.verified.txt
@@ -1,21 +1,26 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Record with value parameters",
"properties": {
- "age": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32",
- "title": "Age"
- },
"name": {
"type": "string",
"title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Age"
}
},
"required": [
"name",
"age"
- ]
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParametersAndProperty.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParametersAndProperty.verified.txt
new file mode 100644
index 0000000..c26b0d4
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParametersAndProperty.verified.txt
@@ -0,0 +1,31 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Record with value parameters and property",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Age"
+ },
+ "title": {
+ "type": "string",
+ "title": "Title"
+ }
+ },
+ "required": [
+ "name",
+ "age",
+ "title"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParametersAndPropertyInitializer.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParametersAndPropertyInitializer.verified.txt
new file mode 100644
index 0000000..ca00a31
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Record_WithValueParametersAndPropertyInitializer.verified.txt
@@ -0,0 +1,31 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Record with value parameters and property initializer",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Age"
+ },
+ "title": {
+ "type": "string",
+ "default": "How to make a record",
+ "title": "Title"
+ }
+ },
+ "required": [
+ "name",
+ "age"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Struct_WithNullableValueTypes.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Struct_WithNullableValueTypes.verified.txt
new file mode 100644
index 0000000..26c6c93
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DefaultOptions_Struct_WithNullableValueTypes.verified.txt
@@ -0,0 +1,212 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Struct with nullable value types",
+ "properties": {
+ "string": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "String"
+ },
+ "int": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Int32"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Int"
+ },
+ "byte": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Byte"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Byte"
+ },
+ "sByte": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.SByte"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "S byte"
+ },
+ "short": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Int16"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Short"
+ },
+ "uShort": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.UInt16"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "U short"
+ },
+ "uInt": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.UInt32"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "U int"
+ },
+ "long": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Int64"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Long"
+ },
+ "uLong": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.UInt64"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "U long"
+ },
+ "float": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Single"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Float"
+ },
+ "double": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Double"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Double"
+ },
+ "decimal": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Decimal"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Decimal"
+ },
+ "char": {
+ "oneOf": [
+ {
+ "$ref": "#/$defs/T:System.Char"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Char"
+ }
+ },
+ "$defs": {
+ "T:System.Byte": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 255
+ },
+ "T:System.Char": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1
+ },
+ "T:System.Decimal": {
+ "type": "number",
+ "minimum": -79228162514264337593543950335,
+ "maximum": 79228162514264337593543950335
+ },
+ "T:System.Double": {
+ "type": "number",
+ "minimum": -79228162514264337593543950335,
+ "maximum": 79228162514264337593543950335
+ },
+ "T:System.Int16": {
+ "type": "integer",
+ "minimum": -32768,
+ "maximum": 32767
+ },
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ },
+ "T:System.Int64": {
+ "type": "integer",
+ "minimum": -9223372036854775808,
+ "maximum": 9223372036854775807
+ },
+ "T:System.SByte": {
+ "type": "integer",
+ "minimum": -128,
+ "maximum": 127
+ },
+ "T:System.Single": {
+ "type": "number",
+ "minimum": -79228162514264337593543950335,
+ "maximum": 79228162514264337593543950335
+ },
+ "T:System.UInt16": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 65535
+ },
+ "T:System.UInt32": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 4294967295
+ },
+ "T:System.UInt64": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 18446744073709551615
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Loose.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Loose.verified.txt
new file mode 100644
index 0000000..81bc57f
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Loose.verified.txt
@@ -0,0 +1,25 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with unsupported dictionary key",
+ "properties": {
+ "data": {
+ "type": "object",
+ "$comment": "Key type 'Object' must be convertible to string",
+ "additionalProperties": {
+ "$ref": "#/$defs/T:System.Int32"
+ },
+ "title": "Data"
+ }
+ },
+ "required": [
+ "data"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Loose.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Silent.verified.txt
similarity index 51%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Loose.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Silent.verified.txt
index b92a62e..46614c1 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DictionaryKeyMode_dictionaryKeyMode=Loose.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Silent.verified.txt
@@ -1,20 +1,24 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with unsupported dictionary key",
"properties": {
"data": {
"type": "object",
- "$comment": "Ensure key type 'Address' is convertible to string.",
"additionalProperties": {
- "type": "integer",
- "minimum": -2147483648,
- "maximum": 2147483647,
- "$comment": "System.Int32"
+ "$ref": "#/$defs/T:System.Int32"
},
"title": "Data"
}
},
"required": [
"data"
- ]
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Skip.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Skip.verified.txt
new file mode 100644
index 0000000..1973378
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Skip.verified.txt
@@ -0,0 +1,12 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with unsupported dictionary key",
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Strict.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Strict.verified.txt
new file mode 100644
index 0000000..171433a
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyMode_Strict.verified.txt
@@ -0,0 +1,21 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with unsupported dictionary key",
+ "properties": {
+ "data": {
+ "$unsupportedObject": "Key type 'Object' is not supported.",
+ "title": "Data"
+ }
+ },
+ "required": [
+ "data"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_Default.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_Default.verified.txt
new file mode 100644
index 0000000..5264ae2
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_Default.verified.txt
@@ -0,0 +1,35 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Dictionary key default",
+ "properties": {
+ "stringKey": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "String key"
+ },
+ "intKey": {
+ "type": "object",
+ "$comment": "Key type 'Integer' must be convertible to string",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Int key"
+ },
+ "classKey": {
+ "type": "object",
+ "$comment": "Key type 'Object' must be convertible to string",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Class key"
+ }
+ },
+ "required": [
+ "stringKey",
+ "intKey",
+ "classKey"
+ ]
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_NestedOverride.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_NestedOverride.verified.txt
new file mode 100644
index 0000000..3c17673
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_NestedOverride.verified.txt
@@ -0,0 +1,93 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Dictionary key nested override",
+ "properties": {
+ "default": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.DictionaryKey_Default",
+ "title": "Default"
+ },
+ "propertyOverride": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.DictionaryKey_PropertyOverride",
+ "title": "Property override"
+ }
+ },
+ "required": [
+ "default",
+ "propertyOverride"
+ ],
+ "$defs": {
+ "T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.DictionaryKey_Default": {
+ "type": "object",
+ "title": "Dictionary key default",
+ "properties": {
+ "stringKey": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "String key"
+ },
+ "intKey": {
+ "type": "object",
+ "$comment": "Key type 'Integer' must be convertible to string",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Int key"
+ },
+ "classKey": {
+ "type": "object",
+ "$comment": "Key type 'Object' must be convertible to string",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Class key"
+ }
+ },
+ "required": [
+ "stringKey",
+ "intKey",
+ "classKey"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.SharpSchema.Generator.TestData.DictionaryKey_PropertyOverride": {
+ "type": "object",
+ "title": "Dictionary key property override",
+ "properties": {
+ "stringKey": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "String key"
+ },
+ "intKey": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Int key"
+ },
+ "boolKey": {
+ "type": "object",
+ "$comment": "Key type 'Boolean' must be convertible to string",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Bool key"
+ },
+ "classKey": {
+ "$unsupportedObject": "Key type 'Object' is not supported.",
+ "title": "Class key"
+ }
+ },
+ "required": [
+ "stringKey",
+ "intKey",
+ "boolKey",
+ "classKey"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_PropertyOverride.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_PropertyOverride.verified.txt
new file mode 100644
index 0000000..2429a45
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/DictionaryKeyOverride_DictionaryKey_PropertyOverride.verified.txt
@@ -0,0 +1,39 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Dictionary key property override",
+ "properties": {
+ "stringKey": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "String key"
+ },
+ "intKey": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Int key"
+ },
+ "boolKey": {
+ "type": "object",
+ "$comment": "Key type 'Boolean' must be convertible to string",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "title": "Bool key"
+ },
+ "classKey": {
+ "$unsupportedObject": "Key type 'Object' is not supported.",
+ "title": "Class key"
+ }
+ },
+ "required": [
+ "stringKey",
+ "intKey",
+ "boolKey",
+ "classKey"
+ ]
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/EnumMode_String.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/EnumMode_String.verified.txt
new file mode 100644
index 0000000..85d7d7f
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/EnumMode_String.verified.txt
@@ -0,0 +1,76 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Record with abstract parameters",
+ "properties": {
+ "card": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card",
+ "title": "Card"
+ },
+ "deck": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
+ },
+ "title": "Deck"
+ }
+ },
+ "required": [
+ "card",
+ "deck"
+ ],
+ "$defs": {
+ "T:SharpSchema.Generator.TestData.Card": {
+ "type": "object",
+ "title": "Card",
+ "properties": {
+ "suit": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.SuitKind",
+ "title": "Suit"
+ },
+ "rank": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.RankKind",
+ "title": "Rank"
+ },
+ "isFaceCard": {
+ "type": "boolean",
+ "title": "Is face card"
+ }
+ },
+ "required": [
+ "suit",
+ "rank",
+ "isFaceCard"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.Card.RankKind": {
+ "type": "string",
+ "enum": [
+ "ace",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "ten",
+ "jack",
+ "queen",
+ "king"
+ ],
+ "title": "Rank kind"
+ },
+ "T:SharpSchema.Generator.TestData.Card.SuitKind": {
+ "type": "string",
+ "enum": [
+ "spades",
+ "hearts",
+ "clubs",
+ "diamonds"
+ ],
+ "title": "Suit kind"
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/EnumMode_UnderlyingType.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/EnumMode_UnderlyingType.verified.txt
new file mode 100644
index 0000000..6543c17
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/EnumMode_UnderlyingType.verified.txt
@@ -0,0 +1,55 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Record with abstract parameters",
+ "properties": {
+ "card": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card",
+ "title": "Card"
+ },
+ "deck": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card"
+ },
+ "title": "Deck"
+ }
+ },
+ "required": [
+ "card",
+ "deck"
+ ],
+ "$defs": {
+ "T:SharpSchema.Generator.TestData.Card": {
+ "type": "object",
+ "title": "Card",
+ "properties": {
+ "suit": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.SuitKind",
+ "title": "Suit"
+ },
+ "rank": {
+ "$ref": "#/$defs/T:SharpSchema.Generator.TestData.Card.RankKind",
+ "title": "Rank"
+ },
+ "isFaceCard": {
+ "type": "boolean",
+ "title": "Is face card"
+ }
+ },
+ "required": [
+ "suit",
+ "rank",
+ "isFaceCard"
+ ]
+ },
+ "T:SharpSchema.Generator.TestData.Card.RankKind": {
+ "type": "integer",
+ "title": "Rank kind"
+ },
+ "T:SharpSchema.Generator.TestData.Card.SuitKind": {
+ "type": "integer",
+ "title": "Suit kind"
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_JsonNative.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_JsonNative.verified.txt
new file mode 100644
index 0000000..6eb0385
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_JsonNative.verified.txt
@@ -0,0 +1,81 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with value types",
+ "properties": {
+ "string": {
+ "type": "string",
+ "title": "String"
+ },
+ "int": {
+ "type": "integer",
+ "title": "Int"
+ },
+ "bool": {
+ "type": "boolean",
+ "title": "Bool"
+ },
+ "byte": {
+ "type": "integer",
+ "title": "Byte"
+ },
+ "sByte": {
+ "type": "integer",
+ "title": "S byte"
+ },
+ "short": {
+ "type": "integer",
+ "title": "Short"
+ },
+ "uShort": {
+ "type": "integer",
+ "title": "U short"
+ },
+ "uInt": {
+ "type": "integer",
+ "title": "U int"
+ },
+ "long": {
+ "type": "integer",
+ "title": "Long"
+ },
+ "uLong": {
+ "type": "integer",
+ "title": "U long"
+ },
+ "float": {
+ "type": "integer",
+ "title": "Float"
+ },
+ "double": {
+ "type": "number",
+ "title": "Double"
+ },
+ "decimal": {
+ "type": "number",
+ "title": "Decimal"
+ },
+ "char": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1,
+ "title": "Char"
+ }
+ },
+ "required": [
+ "string",
+ "int",
+ "bool",
+ "byte",
+ "sByte",
+ "short",
+ "uShort",
+ "uInt",
+ "long",
+ "uLong",
+ "float",
+ "double",
+ "decimal",
+ "char"
+ ]
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_StrictDefs.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_StrictDefs.verified.txt
new file mode 100644
index 0000000..5383374
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_StrictDefs.verified.txt
@@ -0,0 +1,141 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class with value types",
+ "properties": {
+ "string": {
+ "type": "string",
+ "title": "String"
+ },
+ "int": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Int"
+ },
+ "bool": {
+ "type": "boolean",
+ "title": "Bool"
+ },
+ "byte": {
+ "$ref": "#/$defs/T:System.Byte",
+ "title": "Byte"
+ },
+ "sByte": {
+ "$ref": "#/$defs/T:System.SByte",
+ "title": "S byte"
+ },
+ "short": {
+ "$ref": "#/$defs/T:System.Int16",
+ "title": "Short"
+ },
+ "uShort": {
+ "$ref": "#/$defs/T:System.UInt16",
+ "title": "U short"
+ },
+ "uInt": {
+ "$ref": "#/$defs/T:System.UInt32",
+ "title": "U int"
+ },
+ "long": {
+ "$ref": "#/$defs/T:System.Int64",
+ "title": "Long"
+ },
+ "uLong": {
+ "$ref": "#/$defs/T:System.UInt64",
+ "title": "U long"
+ },
+ "float": {
+ "$ref": "#/$defs/T:System.Single",
+ "title": "Float"
+ },
+ "double": {
+ "$ref": "#/$defs/T:System.Double",
+ "title": "Double"
+ },
+ "decimal": {
+ "$ref": "#/$defs/T:System.Decimal",
+ "title": "Decimal"
+ },
+ "char": {
+ "$ref": "#/$defs/T:System.Char",
+ "title": "Char"
+ }
+ },
+ "required": [
+ "string",
+ "int",
+ "bool",
+ "byte",
+ "sByte",
+ "short",
+ "uShort",
+ "uInt",
+ "long",
+ "uLong",
+ "float",
+ "double",
+ "decimal",
+ "char"
+ ],
+ "$defs": {
+ "T:System.Byte": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 255
+ },
+ "T:System.Char": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1
+ },
+ "T:System.Decimal": {
+ "type": "number",
+ "minimum": -79228162514264337593543950335,
+ "maximum": 79228162514264337593543950335
+ },
+ "T:System.Double": {
+ "type": "number",
+ "minimum": -79228162514264337593543950335,
+ "maximum": 79228162514264337593543950335
+ },
+ "T:System.Int16": {
+ "type": "integer",
+ "minimum": -32768,
+ "maximum": 32767
+ },
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ },
+ "T:System.Int64": {
+ "type": "integer",
+ "minimum": -9223372036854775808,
+ "maximum": 9223372036854775807
+ },
+ "T:System.SByte": {
+ "type": "integer",
+ "minimum": -128,
+ "maximum": 127
+ },
+ "T:System.Single": {
+ "type": "number",
+ "minimum": -79228162514264337593543950335,
+ "maximum": 79228162514264337593543950335
+ },
+ "T:System.UInt16": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 65535
+ },
+ "T:System.UInt32": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 4294967295
+ },
+ "T:System.UInt64": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 18446744073709551615
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithValueTypes.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_StrictInline.verified.txt
similarity index 79%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithValueTypes.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_StrictInline.verified.txt
index 02535bb..bdafc3e 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_DefaultOptions_testName=Class_WithValueTypes.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/NumberMode_StrictInline.verified.txt
@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class with value types",
"properties": {
"string": {
"type": "string",
@@ -10,7 +11,6 @@
"type": "integer",
"minimum": -2147483648,
"maximum": 2147483647,
- "$comment": "System.Int32",
"title": "Int"
},
"bool": {
@@ -21,77 +21,66 @@
"type": "integer",
"minimum": 0,
"maximum": 255,
- "$comment": "System.Byte",
"title": "Byte"
},
"sByte": {
"type": "integer",
"minimum": -128,
"maximum": 127,
- "$comment": "System.SByte",
- "title": "S Byte"
+ "title": "S byte"
},
"short": {
"type": "integer",
"minimum": -32768,
"maximum": 32767,
- "$comment": "System.Int16",
"title": "Short"
},
"uShort": {
"type": "integer",
"minimum": 0,
"maximum": 65535,
- "$comment": "System.UInt16",
- "title": "U Short"
+ "title": "U short"
},
"uInt": {
"type": "integer",
"minimum": 0,
"maximum": 4294967295,
- "$comment": "System.UInt32",
- "title": "U Int"
+ "title": "U int"
},
"long": {
"type": "integer",
"minimum": -9223372036854775808,
"maximum": 9223372036854775807,
- "$comment": "System.Int64",
"title": "Long"
},
"uLong": {
"type": "integer",
"minimum": 0,
"maximum": 18446744073709551615,
- "$comment": "System.UInt64",
- "title": "U Long"
+ "title": "U long"
},
"float": {
"type": "number",
"minimum": -79228162514264337593543950335,
"maximum": 79228162514264337593543950335,
- "$comment": "System.Single",
"title": "Float"
},
"double": {
"type": "number",
"minimum": -79228162514264337593543950335,
"maximum": 79228162514264337593543950335,
- "$comment": "System.Double",
"title": "Double"
},
"decimal": {
"type": "number",
"minimum": -79228162514264337593543950335,
"maximum": 79228162514264337593543950335,
- "$comment": "System.Decimal",
"title": "Decimal"
},
"char": {
"type": "string",
"minLength": 1,
"maxLength": 1,
- "$comment": "System.Char",
"title": "Char"
}
},
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Bases.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Bases.verified.txt
new file mode 100644
index 0000000..8a61578
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Bases.verified.txt
@@ -0,0 +1,25 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class extends abstract class",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Age"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Full.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Full.verified.txt
new file mode 100644
index 0000000..8a61578
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Full.verified.txt
@@ -0,0 +1,25 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "title": "Class extends abstract class",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name"
+ },
+ "age": {
+ "$ref": "#/$defs/T:System.Int32",
+ "title": "Age"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "$defs": {
+ "T:System.Int32": {
+ "type": "integer",
+ "minimum": -2147483648,
+ "maximum": 2147483647
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Interfaces.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Interfaces.verified.txt
similarity index 82%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Interfaces.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Interfaces.verified.txt
index 03fd3c2..4149796 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=Interfaces.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_Interfaces.verified.txt
@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class extends abstract class",
"properties": {
"name": {
"type": "string",
diff --git a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=SymbolOnly.verified.txt b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_SymbolOnly.verified.txt
similarity index 82%
rename from test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=SymbolOnly.verified.txt
rename to test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_SymbolOnly.verified.txt
index 03fd3c2..4149796 100644
--- a/test/Generator/RootDeclaredTypeSyntaxVisitorTests/VerifyTests.Verify_Traversal_traversal=SymbolOnly.verified.txt
+++ b/test/Generator/RootSyntaxVisitorTests/Verifications/Traversal_SymbolOnly.verified.txt
@@ -1,6 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
+ "title": "Class extends abstract class",
"properties": {
"name": {
"type": "string",
diff --git a/test/Generator/RootSyntaxVisitorTests/VerifyTests.cs b/test/Generator/RootSyntaxVisitorTests/VerifyTests.cs
new file mode 100644
index 0000000..259c1d7
--- /dev/null
+++ b/test/Generator/RootSyntaxVisitorTests/VerifyTests.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Threading.Tasks;
+using Json.Schema;
+using SharpSchema.Annotations;
+using SharpSchema.Generator;
+using SharpSchema.Generator.TestData;
+using SharpSchema.Generator.Utilities;
+using SharpSchema.Test.Generator.TestUtilities;
+using VerifyXunit;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace SharpSchema.Test.Generator.RootSyntaxVisitorTests;
+
+
+public class VerifyTests : IDisposable, IClassFixture
+{
+ private readonly ITestOutputHelper _output;
+ private readonly TestDataFixture _fixture;
+
+ public VerifyTests(TestDataFixture fixture, ITestOutputHelper outputHelper)
+ {
+ ArgumentNullException.ThrowIfNull(outputHelper);
+
+ _fixture = fixture;
+ Tracer.Writer = outputHelper.WriteLine;
+ _output = outputHelper;
+ }
+
+ public void Dispose() => Tracer.Writer = null;
+
+ internal static Task Verify(string schemaString, string testName, string parameter)
+ {
+ return Verifier.Verify(schemaString)
+ .UseDirectory("Verifications")
+ .UseFileName($"{testName}_{parameter}");
+ }
+
+ [Theory]
+ [InlineData(nameof(Class_WithArrayProperties))]
+ [InlineData(nameof(Class_WithDictionaryProperties))]
+ [InlineData(nameof(Class_WithDocComments))]
+ [InlineData(nameof(Class_WithIgnoredProperty))]
+ [InlineData(nameof(Class_WithInvalidProperties))]
+ [InlineData(nameof(Class_WithRequiredProperties))]
+ [InlineData(nameof(Class_WithSchemaOverride))]
+ [InlineData(nameof(Class_WithTypeSchemaOverride))]
+ [InlineData(nameof(Class_ExtendsAbstractClass))]
+ [InlineData(nameof(Record_WithDefaultValueParameter))]
+ [InlineData(nameof(Record_WithDefaultValueParametersAndConstantProperty))]
+ [InlineData(nameof(Record_WithDocComments))]
+ [InlineData(nameof(Record_WithIgnoredParameter))]
+ [InlineData(nameof(Record_WithSchemaOverride))]
+ [InlineData(nameof(Record_WithValueParameters))]
+ [InlineData(nameof(Record_WithValueParametersAndProperty))]
+ [InlineData(nameof(Record_WithValueParametersAndPropertyInitializer))]
+ [InlineData(nameof(Struct_WithNullableValueTypes))]
+ [InlineData(nameof(GameHall))]
+ public Task Verify_DefaultOptions(string testName)
+ {
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(GeneratorOptions.Default);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, testName);
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+ _output.WriteSeparator();
+
+ return Verify(schemaString, "DefaultOptions", testName);
+ }
+
+ [Theory]
+ [InlineData(nameof(Accessibility_Default))]
+ [InlineData(nameof(Accessibility_ClassOverride))]
+ [InlineData(nameof(Accessibility_NestedDefault))]
+ [InlineData(nameof(Accessibility_NestedOverride))]
+ public Task Verify_AccessibilityOverride(string testName)
+ {
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(GeneratorOptions.Default);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, testName);
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+ _output.WriteSeparator();
+
+ return Verify(schemaString, "AccessibilityOverride", testName);
+
+ }
+
+ [Theory]
+ [InlineData(nameof(DictionaryKey_Default))]
+ [InlineData(nameof(DictionaryKey_PropertyOverride))]
+ [InlineData(nameof(DictionaryKey_NestedOverride))]
+ public Task Verify_DictionaryKeyOverride(string testName)
+ {
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(GeneratorOptions.Default);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, testName);
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+ _output.WriteSeparator();
+
+ return Verify(schemaString, "DictionaryKeyOverride", testName);
+ }
+
+ [InlineData(DictionaryKeyMode.Loose)]
+ [InlineData(DictionaryKeyMode.Strict)]
+ [InlineData(DictionaryKeyMode.Silent)]
+ [InlineData(DictionaryKeyMode.Skip)]
+ [Theory]
+ public Task Verify_DictionaryKeyMode(DictionaryKeyMode dictionaryKeyMode)
+ {
+ GeneratorOptions options = new()
+ {
+ DictionaryKeyMode = dictionaryKeyMode
+ };
+
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(options);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Class_WithUnsupportedDictionaryKey));
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+
+ return Verify(schemaString, "DictionaryKeyMode", dictionaryKeyMode.ToString());
+ }
+
+ [InlineData(AccessibilityMode.Public)]
+ [InlineData(AccessibilityMode.Internal)]
+ [InlineData(AccessibilityMode.Private)]
+ [InlineData(AccessibilityMode.PublicInternal)]
+ [Theory]
+ public Task Verify_AccessibilityMode(AccessibilityMode accessibilities)
+ {
+ GeneratorOptions options = new()
+ {
+ AccessibilityMode = accessibilities
+ };
+
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(options);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Class_WithInternalProperties));
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+
+ return Verify(schemaString, "AccessibilityMode", accessibilities.ToString());
+ }
+
+ [InlineData(EnumMode.String)]
+ [InlineData(EnumMode.UnderlyingType)]
+ [Theory]
+ public Task Verify_EnumMode(EnumMode enumHandling)
+ {
+ GeneratorOptions options = new()
+ {
+ EnumMode = enumHandling
+ };
+
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(options);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Record_WithAbstractParameters));
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+
+ return Verify(schemaString, "EnumMode", enumHandling.ToString());
+ }
+
+ [InlineData(TraversalMode.SymbolOnly)]
+ [InlineData(TraversalMode.Bases)]
+ [InlineData(TraversalMode.Interfaces)]
+ [InlineData(TraversalMode.Full)]
+ [Theory]
+ public Task Verify_Traversal(TraversalMode traversal)
+ {
+ GeneratorOptions options = new()
+ {
+ TraversalMode = traversal
+ };
+
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(options);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Class_ExtendsAbstractClass));
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+
+ return Verify(schemaString, "Traversal", traversal.ToString());
+ }
+
+ [InlineData(NumberMode.StrictDefs)]
+ [InlineData(NumberMode.StrictInline)]
+ [InlineData(NumberMode.JsonNative)]
+ [Theory]
+ public Task Verify_NumberMode(NumberMode numberMode)
+ {
+ GeneratorOptions options = new()
+ {
+ NumberMode = numberMode
+ };
+
+ RootSyntaxVisitor visitor = _fixture.GetVisitor(options);
+ JsonSchemaBuilder builder = _fixture.GetJsonSchemaBuilder(visitor, nameof(Class_WithValueTypes));
+ _output.WriteSeparator();
+
+ string schemaString = builder.Build().SerializeToJson();
+ _output.WriteLine(schemaString);
+
+ return Verify(schemaString, "NumberMode", numberMode.ToString());
+ }
+}
diff --git a/test/Generator/SharpSchema.Test.Generator.csproj b/test/Generator/SharpSchema.Test.Generator.csproj
index 93fb879..d5de853 100644
--- a/test/Generator/SharpSchema.Test.Generator.csproj
+++ b/test/Generator/SharpSchema.Test.Generator.csproj
@@ -26,14 +26,10 @@
-
+
-
-
-
-
diff --git a/vscode-diff.runsettings b/vscode-diff.runsettings
new file mode 100644
index 0000000..311021e
--- /dev/null
+++ b/vscode-diff.runsettings
@@ -0,0 +1,11 @@
+
+
+
+
+ VisualStudioCode
+ false
+ true
+ 5
+
+
+