Skip to content

Commit ad2a599

Browse files
committed
Added support for nullable reference types
1 parent 6d2a695 commit ad2a599

7 files changed

Lines changed: 132 additions & 14 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace TestNet6.Models;
2+
3+
public class FakeWithNullable
4+
{
5+
public string? Name { get; set; }
6+
}

TestNet6/Program.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using TestNet6.Models;
2+
using TypeScriptBuilder;
3+
4+
var builder = new TypeScriptGenerator(new TypeScriptGeneratorOptions
5+
{
6+
EmitDocumentation = false,
7+
EmitComments = true
8+
});
9+
10+
builder
11+
.ExcludeType(typeof(Program))
12+
//.AddCSType(typeof(Poco))
13+
.AddCSType(typeof(FakeWithNullable));
14+
15+
var res = builder.ToString();
16+
17+
Console.WriteLine(res);
18+
19+
//builder.Store("Test.ts");
20+

TestNet6/TestNet6.csproj

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="..\src\TypeScriptBuilder\TypeScriptBuilder.csproj" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<Folder Include="Models\" />
16+
</ItemGroup>
17+
18+
</Project>

TypeScriptBuilder.sln

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.30804.86
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.3.32819.101
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "src\Test\Test.csproj", "{2E383C04-12C6-4E36-A901-723DA97E7CBE}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "src\Test\Test.csproj", "{2E383C04-12C6-4E36-A901-723DA97E7CBE}"
77
EndProject
8-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TypeScriptBuilder", "src\TypeScriptBuilder\TypeScriptBuilder.csproj", "{B5BCA49F-589E-4745-AD91-E152E859BD88}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TypeScriptBuilder", "src\TypeScriptBuilder\TypeScriptBuilder.csproj", "{B5BCA49F-589E-4745-AD91-E152E859BD88}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestNet6", "TestNet6\TestNet6.csproj", "{A5B82787-BEAA-487C-A8AB-9C6B47A815C0}"
911
EndProject
1012
Global
1113
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -21,6 +23,10 @@ Global
2123
{B5BCA49F-589E-4745-AD91-E152E859BD88}.Debug|Any CPU.Build.0 = Debug|Any CPU
2224
{B5BCA49F-589E-4745-AD91-E152E859BD88}.Release|Any CPU.ActiveCfg = Release|Any CPU
2325
{B5BCA49F-589E-4745-AD91-E152E859BD88}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{A5B82787-BEAA-487C-A8AB-9C6B47A815C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{A5B82787-BEAA-487C-A8AB-9C6B47A815C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{A5B82787-BEAA-487C-A8AB-9C6B47A815C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{A5B82787-BEAA-487C-A8AB-9C6B47A815C0}.Release|Any CPU.Build.0 = Release|Any CPU
2430
EndGlobalSection
2531
GlobalSection(SolutionProperties) = preSolution
2632
HideSolutionNode = FALSE
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Collections.Generic;
2+
using System.Collections.ObjectModel;
3+
using System.Reflection;
4+
using System;
5+
using System.Linq;
6+
7+
namespace TypeScriptBuilder.Helper
8+
{
9+
public class NullableHelper
10+
{
11+
public static bool IsNullable(PropertyInfo property) =>
12+
IsNullableHelper(property.PropertyType, property.DeclaringType, property.CustomAttributes);
13+
14+
public static bool IsNullable(FieldInfo field) =>
15+
IsNullableHelper(field.FieldType, field.DeclaringType, field.CustomAttributes);
16+
17+
public static bool IsNullable(ParameterInfo parameter) =>
18+
IsNullableHelper(parameter.ParameterType, parameter.Member, parameter.CustomAttributes);
19+
20+
private static bool IsNullableHelper(Type memberType, MemberInfo declaringType, IEnumerable<CustomAttributeData> customAttributes)
21+
{
22+
if (memberType.IsValueType)
23+
return Nullable.GetUnderlyingType(memberType) != null;
24+
25+
var nullable = customAttributes
26+
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
27+
if (nullable != null && nullable.ConstructorArguments.Count == 1)
28+
{
29+
var attributeArgument = nullable.ConstructorArguments[0];
30+
if (attributeArgument.ArgumentType == typeof(byte[]))
31+
{
32+
var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)attributeArgument.Value;
33+
if (args.Count > 0 && args[0].ArgumentType == typeof(byte))
34+
{
35+
return (byte)args[0].Value == 2;
36+
}
37+
}
38+
else if (attributeArgument.ArgumentType == typeof(byte))
39+
{
40+
return (byte)attributeArgument.Value == 2;
41+
}
42+
}
43+
44+
for (var type = declaringType; type != null; type = type.DeclaringType)
45+
{
46+
var context = type.CustomAttributes
47+
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
48+
if (context != null &&
49+
context.ConstructorArguments.Count == 1 &&
50+
context.ConstructorArguments[0].ArgumentType == typeof(byte))
51+
{
52+
return (byte)context.ConstructorArguments[0].Value! == 2;
53+
}
54+
}
55+
56+
// Couldn't find a suitable attribute
57+
return false;
58+
}
59+
}
60+
}

src/TypeScriptBuilder/TypeScriptBuilder.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<PropertyGroup>
44
<LangVersion>latest</LangVersion>
5+
<Nullable>enable</Nullable>
56
<TargetFramework>netstandard2.0</TargetFramework>
67
<PackageId>TypeScriptBuilder</PackageId>
78
<Company>TypeScriptBuilder</Company>
@@ -18,4 +19,8 @@
1819
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
1920
</ItemGroup>
2021

22+
<ItemGroup>
23+
<Folder Include="Helper\" />
24+
</ItemGroup>
25+
2126
</Project>

src/TypeScriptBuilder/TypeScriptGenerator.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Reflection;
77
using System.Runtime.Serialization;
88
using Newtonsoft.Json;
9+
using TypeScriptBuilder.Helper;
910

1011
namespace TypeScriptBuilder
1112
{
@@ -262,23 +263,25 @@ void GenerateFields<T>(Type type, T[] fields, Func<T, Type> getType, Func<T, boo
262263
{
263264
// Needs to fetch the Type from the PropertyInfo or FieldInfo-objects, for some resone
264265
// the fieldType-variable does not contain this info.
265-
Type realType = null;
266+
//Type realType = null;
266267
if (f is PropertyInfo pInfo)
267268
{
268-
realType = pInfo.PropertyType;
269+
//realType = pInfo.PropertyType;
270+
optional = NullableHelper.IsNullable(pInfo);
269271
}
270272
else if (f is FieldInfo fInfo)
271273
{
272-
realType = fInfo.FieldType;
274+
//realType = fInfo.FieldType;
275+
optional = NullableHelper.IsNullable(fInfo);
273276
}
274277

275-
if (realType != null)
276-
{
277-
if (realType.IsGenericType && realType.GetGenericTypeDefinition() == typeof(Nullable<>))
278-
{
279-
optional = true;
280-
}
281-
}
278+
//if (realType != null)
279+
//{
280+
// if (realType.IsGenericType && realType.GetGenericTypeDefinition() == typeof(Nullable<>))
281+
// {
282+
// optional = true;
283+
// }
284+
//}
282285

283286
}
284287

0 commit comments

Comments
 (0)