Skip to content

Commit

Permalink
Merge pull request #917 from RSuter/master
Browse files Browse the repository at this point in the history
Release v9.13.20
  • Loading branch information
RicoSuter committed Mar 1, 2019
2 parents 28b87b3 + d2a35cb commit 0661237
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 20 deletions.
26 changes: 25 additions & 1 deletion src/NJsonSchema.CodeGeneration.CSharp.Tests/ArrayTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using NJsonSchema.Annotations;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -32,5 +33,28 @@ public async Task When_array_property_is_required_then_array_instance_can_be_cha
//// Assert
Assert.Contains("public Foo<string> ArrayProperty { get; set; } = new Bar<string>();", code);
}

public class ClassWithNullableArrayItems
{
[NotNull]
[ItemsCanBeNull]
public List<int?> Items { get; set; }
}

[Fact]
public async Task When_array_item_is_nullable_then_generated_CSharp_is_correct()
{
// Arrange
var schema = await JsonSchema4.FromTypeAsync<ClassWithNullableArrayItems>();
var json = schema.ToJson();
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings());

// Act
var output = generator.GenerateFile("MyClass");

// Assert
Assert.True(schema.Properties["Items"].Item.IsNullable(SchemaType.JsonSchema));
Assert.Contains("System.Collections.ObjectModel.ObservableCollection<int?> Items", output);
}
}
}
6 changes: 4 additions & 2 deletions src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,14 @@ private static string ResolveNumber(JsonSchema4 schema, bool isNullable)
private string ResolveArrayOrTuple(JsonSchema4 schema)
{
if (schema.Item != null)
return string.Format(Settings.ArrayType + "<{0}>", Resolve(schema.Item, false, null));
{
return string.Format(Settings.ArrayType + "<{0}>", Resolve(schema.Item, schema.Item.IsNullable(Settings.SchemaType), null));
}

if (schema.Items != null && schema.Items.Count > 0)
{
var tupleTypes = schema.Items
.Select(i => Resolve(i, false, null))
.Select(i => Resolve(i, i.IsNullable(Settings.SchemaType), null))
.ToArray();

return string.Format("System.Tuple<" + string.Join(", ", tupleTypes) + ">");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0;net451</TargetFrameworks>
<Description>JSON Schema reader, generator and validator for .NET</Description>
<Version>9.13.19</Version>
<Version>9.13.20</Version>
<PackageTags>json schema validation generator .net</PackageTags>
<Copyright>Copyright © Rico Suter, 2018</Copyright>
<PackageLicenseUrl>https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md</PackageLicenseUrl>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using NJsonSchema.CodeGeneration.TypeScript.Tests.Models;
using NJsonSchema.Annotations;
using NJsonSchema.CodeGeneration.TypeScript.Tests.Models;
using NJsonSchema.Generation;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;

Expand Down Expand Up @@ -159,5 +161,32 @@ public async Task When_a_complex_property_is_nullable_then_default_is_null()
// Assert
Assert.DoesNotContain(": new ChildDto();", output);
}

public class ClassWithNullableArrayItems
{
[NotNull]
[ItemsCanBeNull]
public List<string> Items { get; set; }
}

[Fact]
public async Task When_array_item_is_nullable_then_generated_TypeScript_is_correct()
{
// Arrange
var schema = await JsonSchema4.FromTypeAsync<ClassWithNullableArrayItems>();
var json = schema.ToJson();
var generator = new TypeScriptGenerator(schema, new TypeScriptGeneratorSettings
{
TypeScriptVersion = 2.7m,
NullValue = TypeScriptNullValue.Null
});

// Act
var output = generator.GenerateFile("MyClass");

// Assert
Assert.True(schema.Properties["Items"].Item.IsNullable(SchemaType.JsonSchema));
Assert.Contains(": (string | null)[]", output);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0;net451</TargetFrameworks>
<Description>JSON Schema reader, generator and validator for .NET</Description>
<Version>9.13.19</Version>
<Version>9.13.20</Version>
<PackageTags>json schema validation generator .net</PackageTags>
<Copyright>Copyright © Rico Suter, 2018</Copyright>
<PackageLicenseUrl>https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md</PackageLicenseUrl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,20 +183,33 @@ private string ResolveArrayOrTuple(JsonSchema4 schema, string typeNameHint, bool
{
var isObject = schema.Item?.ActualSchema.Type.HasFlag(JsonObjectType.Object) == true;
var isDictionary = schema.Item?.ActualSchema.IsDictionary == true;

var prefix = addInterfacePrefix && SupportsConstructorConversion(schema.Item) && isObject && !isDictionary ? "I" : "";
return string.Format("{0}[]", prefix + Resolve(schema.Item, true, typeNameHint)); // TODO: Make typeNameHint singular if possible
var itemType = prefix + Resolve(schema.Item, true, typeNameHint);

return string.Format("{0}[]", GetNullableItemType(schema, itemType)); // TODO: Make typeNameHint singular if possible
}

if (schema.Items != null && schema.Items.Count > 0)
{
var tupleTypes = schema.Items
.Select(i => Resolve(i.ActualSchema, false, null))
.Select(s => GetNullableItemType(s, Resolve(s, false, null)))
.ToArray();

return string.Format("[" + string.Join(", ", tupleTypes) + "]");
}

return "any[]";
}

private string GetNullableItemType(JsonSchema4 schema, string itemType)
{
if (Settings.SupportsStrictNullChecks && schema.Item.IsNullable(Settings.SchemaType))
{
return string.Format("({0} | {1})", itemType, Settings.NullValue.ToString().ToLowerInvariant());
}

return itemType;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@
// <author>Rico Suter, mail@rsuter.com</author>
//-----------------------------------------------------------------------

using System.Collections.Generic;

namespace NJsonSchema.CodeGeneration.TypeScript
{
/// <summary>Converts the default value to a TypeScript identifier.</summary>
public class TypeScriptValueGenerator : ValueGeneratorBase
{
private readonly List<string> _formatCompatibleWithString = new List<string>()
{
JsonFormatStrings.Uri,
JsonFormatStrings.Guid,
#pragma warning disable CS0618 // Type or member is obsolete
JsonFormatStrings.Uuid
#pragma warning restore CS0618 // Type or member is obsolete
};

/// <summary>Initializes a new instance of the <see cref="TypeScriptValueGenerator"/> class.</summary>
/// <param name="settings">The settings.</param>
public TypeScriptValueGenerator(TypeScriptGeneratorSettings settings)
Expand All @@ -31,6 +42,11 @@ public override string GetDefaultValue(JsonSchema4 schema, bool allowsNull, stri
var value = base.GetDefaultValue(schema, allowsNull, targetType, typeNameHint, useSchemaDefault, typeResolver);
if (value == null)
{
if (schema.Type.HasFlag(JsonObjectType.String) && _formatCompatibleWithString.Contains(schema.Format))
{
return "\"" + ConversionUtilities.ConvertToStringLiteral(value.ToString()) + "\"";
}

var isOptional = (schema as JsonProperty)?.IsRequired == false;
if (schema != null && allowsNull == false && isOptional == false)
{
Expand Down Expand Up @@ -66,4 +82,4 @@ public override string GetNumericValue(JsonObjectType type, object value, string
return ConvertNumberToString(value);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0;net451</TargetFrameworks>
<Description>JSON Schema reader, generator and validator for .NET</Description>
<Version>9.13.19</Version>
<Version>9.13.20</Version>
<PackageTags>json schema validation generator .net</PackageTags>
<Copyright>Copyright © Rico Suter, 2018</Copyright>
<PackageLicenseUrl>https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md</PackageLicenseUrl>
Expand Down
31 changes: 28 additions & 3 deletions src/NJsonSchema.CodeGeneration/ValueGeneratorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// <author>Rico Suter, mail@rsuter.com</author>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

Expand All @@ -15,7 +17,21 @@ namespace NJsonSchema.CodeGeneration
public abstract class ValueGeneratorBase
{
private readonly CodeGeneratorSettingsBase _settings;

private readonly List<string> _formatNotCompatibleWithString = new List<string>()
{
JsonFormatStrings.Date,
JsonFormatStrings.DateTime,
JsonFormatStrings.Time,
JsonFormatStrings.TimeSpan,
JsonFormatStrings.Uri,
JsonFormatStrings.Guid,
JsonFormatStrings.Byte,
#pragma warning disable CS0618 // Type or member is obsolete
JsonFormatStrings.Uuid,
JsonFormatStrings.Base64,
#pragma warning restore CS0618 // Type or member is obsolete
};

/// <summary>Initializes a new instance of the <see cref="ValueGeneratorBase" /> class.</summary>
/// <param name="settings">The settings.</param>
protected ValueGeneratorBase(CodeGeneratorSettingsBase settings)
Expand All @@ -41,7 +57,8 @@ public virtual string GetDefaultValue(JsonSchema4 schema, bool allowsNull, strin
return GetEnumDefaultValue(schema, actualSchema, typeNameHint, typeResolver);

if (schema.Type.HasFlag(JsonObjectType.String))
return "\"" + ConversionUtilities.ConvertToStringLiteral(schema.Default.ToString()) + "\"";
return GetStringValue(schema.Type, schema.Default, schema.Format);

if (schema.Type.HasFlag(JsonObjectType.Boolean))
return schema.Default.ToString().ToLowerInvariant();
if (schema.Type.HasFlag(JsonObjectType.Integer) ||
Expand All @@ -51,6 +68,14 @@ public virtual string GetDefaultValue(JsonSchema4 schema, bool allowsNull, strin
return null;
}

private string GetStringValue(JsonObjectType type, object value, string format)
{
if(!_formatNotCompatibleWithString.Contains(format))
return "\"" + ConversionUtilities.ConvertToStringLiteral(value.ToString()) + "\"";
else
return null;
}

/// <summary>Converts the default value to a number literal. </summary>
/// <param name="type">The JSON type.</param>
/// <param name="value">The value to convert.</param>
Expand Down Expand Up @@ -117,4 +142,4 @@ protected string ConvertNumberToString(object value)
return null;
}
}
}
}
2 changes: 1 addition & 1 deletion src/NJsonSchema.Yaml/NJsonSchema.Yaml.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0;net45</TargetFrameworks>
<Description>JSON Schema reader, generator and validator for .NET</Description>
<Version>9.13.19</Version>
<Version>9.13.20</Version>
<PackageTags>json schema validation generator .net</PackageTags>
<Copyright>Copyright © Rico Suter, 2018</Copyright>
<PackageLicenseUrl>https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md</PackageLicenseUrl>
Expand Down
18 changes: 18 additions & 0 deletions src/NJsonSchema/Annotations/ItemsCanBeNullAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//-----------------------------------------------------------------------
// <copyright file="ItemsCanBeNullAttribute.cs" company="NJsonSchema">
// Copyright (c) Rico Suter. All rights reserved.
// </copyright>
// <license>https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md</license>
// <author>Rico Suter, mail@rsuter.com</author>
//-----------------------------------------------------------------------

using System;

namespace NJsonSchema.Annotations
{
/// <summary>Annotation to specify that array items are nullable.</summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.Field)]
public class ItemsCanBeNullAttribute : Attribute
{
}
}
18 changes: 13 additions & 5 deletions src/NJsonSchema/Generation/JsonSchemaGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public virtual async Task GenerateAsync<TSchemaType>(Type type, IEnumerable<Attr
else if (typeDescription.IsEnum)
await GenerateEnum(schema, type, parentAttributes, typeDescription, schemaResolver).ConfigureAwait(false);
else if (typeDescription.Type.HasFlag(JsonObjectType.Array)) // TODO: Add support for tuples?
await GenerateArray(schema, type, typeDescription, schemaResolver).ConfigureAwait(false);
await GenerateArray(schema, type, parentAttributes, typeDescription, schemaResolver).ConfigureAwait(false);
else
typeDescription.ApplyType(schema);

Expand Down Expand Up @@ -442,28 +442,36 @@ private async Task<bool> TryHandleSpecialTypesAsync<TSchemaType>(Type type, TSch
}

private async Task GenerateArray<TSchemaType>(
TSchemaType schema, Type type, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
TSchemaType schema, Type type, IEnumerable<Attribute> parentAttributes, JsonTypeDescription typeDescription, JsonSchemaResolver schemaResolver)
where TSchemaType : JsonSchema4, new()
{
#pragma warning disable 1998

typeDescription.ApplyType(schema);

var itemType = type.GetEnumerableItemType();
if (itemType != null)
{
schema.Item = await GenerateWithReferenceAndNullabilityAsync<JsonSchema4>(
#pragma warning disable 1998
itemType, null, false, schemaResolver, async (s, r) =>
#pragma warning restore 1998
itemType, null, parentAttributes?.OfType<ItemsCanBeNullAttribute>().Any() == true, schemaResolver, async (s, r) =>
{
if (Settings.GenerateXmlObjects)
{
s.GenerateXmlObjectForItemType(itemType);
}
}).ConfigureAwait(false);

if (Settings.GenerateXmlObjects)
{
schema.GenerateXmlObjectForArrayType(type);
}
}
else
{
schema.Item = JsonSchema4.CreateAnySchema();
}

#pragma warning restore 1998
}

private async Task GenerateEnum<TSchemaType>(
Expand Down
2 changes: 1 addition & 1 deletion src/NJsonSchema/NJsonSchema.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard1.0;netstandard2.0;net40;net45</TargetFrameworks>
<Description>JSON Schema reader, generator and validator for .NET</Description>
<Version>9.13.19</Version>
<Version>9.13.20</Version>
<PackageTags>json schema validation generator .net</PackageTags>
<Copyright>Copyright © Rico Suter, 2018</Copyright>
<PackageLicenseUrl>https://github.com/rsuter/NJsonSchema/blob/master/LICENSE.md</PackageLicenseUrl>
Expand Down

0 comments on commit 0661237

Please sign in to comment.