Skip to content

Commit

Permalink
Merge branch 'explicit-nullable-arrays-fix'
Browse files Browse the repository at this point in the history
  • Loading branch information
fakefeik committed Feb 20, 2019
2 parents 3f6ea1d + de8e043 commit 8aac6a3
Show file tree
Hide file tree
Showing 19 changed files with 117 additions and 77 deletions.
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@

export type ArrayRootType = {
ints?: null | number[];
nullableInts?: null | Nullable<number>[];
nullableInts?: null | Array<null | number>;
byteArray?: null | string;
nullableByteArray?: null | Nullable<Byte>[];
nullableByteArray?: null | Array<null | Byte>;
enums?: null | AnotherEnum[];
nullableEnums?: null | Nullable<AnotherEnum>[];
nullableEnums?: null | Array<null | AnotherEnum>;
strings?: null | string[];
customTypes?: null | AnotherCustomType[];
stringsList?: null | string[];
customTypesDict?: null | {
[key: string]: AnotherCustomType;
};
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
};
export type Byte = {
};
export type AnotherEnum = 'B' | 'C';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@

export type ArrayRootType = {
ints?: null | number[];
nullableInts?: null | Nullable<number>[];
nullableInts?: null | Array<null | number>;
byteArray?: null | string;
nullableByteArray?: null | Nullable<Byte>[];
nullableByteArray?: null | Array<null | Byte>;
enums?: null | AnotherEnum[];
nullableEnums?: null | Nullable<AnotherEnum>[];
nullableEnums?: null | Array<null | AnotherEnum>;
strings?: null | string[];
customTypes?: null | AnotherCustomType[];
stringsList?: null | string[];
customTypesDict?: null | {
[key in string]?: AnotherCustomType;
};
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
};
export type Byte = {
};
export type AnotherEnum = 'B' | 'C';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@

export type NotNullRootType = {
export type ExplicitNullabilityRootType = {
someNotNullClass: SomeClass;
someNullableClass?: SomeClass;
notNullString: string;
nullableString?: string;
notNullInt: number;
nullableInt?: number;
notNullArray: number[];
nullableArray?: number[];
notNullNullablesArray: number[];
nullableNullablesArray?: number[];
};
export type SomeClass = {
a: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@

export type NotNullRootType = {
export type ExplicitNullabilityRootType = {
someNotNullClass: SomeClass;
someNullableClass?: SomeClass;
notNullString: string;
nullableString?: string;
notNullInt: number;
nullableInt?: number;
notNullArray: number[];
nullableArray?: number[];
notNullNullablesArray: number[];
nullableNullablesArray?: number[];
};
export type SomeClass = {
a: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@

export type NotNullRootType = {
export type ExplicitNullabilityRootType = {
someNotNullClass: SomeClass;
someNullableClass?: null | SomeClass;
notNullString: string;
nullableString?: null | string;
notNullInt: number;
nullableInt?: null | number;
notNullArray: number[];
nullableArray?: null | number[];
notNullNullablesArray: Array<null | number>;
nullableNullablesArray?: null | Array<null | number>;
};
export type SomeClass = {
a: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@

export type NotNullRootType = {
export type ExplicitNullabilityRootType = {
someNotNullClass: SomeClass;
someNullableClass?: null | SomeClass;
notNullString: string;
nullableString?: null | string;
notNullInt: number;
nullableInt?: null | number;
notNullArray: number[];
nullableArray?: null | number[];
notNullNullablesArray: Array<null | number>;
nullableNullablesArray?: null | Array<null | number>;
};
export type SomeClass = {
a: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
export type GlobalNullableRootType = {
int: number;
nullableInt?: null | number;
nullableInts?: null | Nullable<number>[];
nullableInts?: null | Array<null | number>;
intGeneric?: null | GenericClass<number>;
nullableIntGeneric?: null | GenericClass<Nullable<number>>;
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
nullableIntGeneric?: null | GenericClass<null | number>;
};
export type GenericClass<T> = {
genericType?: T;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
export type GlobalNullableRootType = {
int: number;
nullableInt?: null | number;
nullableInts?: null | Nullable<number>[];
nullableInts?: null | Array<null | number>;
intGeneric?: null | GenericClass<number>;
nullableIntGeneric?: null | GenericClass<Nullable<number>>;
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
nullableIntGeneric?: null | GenericClass<null | number>;
};
export type GenericClass<T> = {
genericType?: T;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@

export type ArrayRootType = {
ints?: null | number[];
nullableInts?: null | Nullable<number>[];
nullableInts?: null | Array<null | number>;
byteArray?: null | string;
nullableByteArray?: null | Nullable<Byte>[];
nullableByteArray?: null | Array<null | Byte>;
enums?: null | AnotherEnum[];
nullableEnums?: null | Nullable<AnotherEnum>[];
nullableEnums?: null | Array<null | AnotherEnum>;
strings?: null | string[];
customTypes?: null | AnotherCustomType[];
stringsList?: null | List<string>;
customTypesDict?: null | Dictionary<string, AnotherCustomType>;
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
};
export type Byte = {
};
export type AnotherEnum = 'B' | 'C';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@

export type ArrayRootType = {
ints?: null | number[];
nullableInts?: null | Nullable<number>[];
nullableInts?: null | Array<null | number>;
byteArray?: null | string;
nullableByteArray?: null | Nullable<Byte>[];
nullableByteArray?: null | Array<null | Byte>;
enums?: null | AnotherEnum[];
nullableEnums?: null | Nullable<AnotherEnum>[];
nullableEnums?: null | Array<null | AnotherEnum>;
strings?: null | string[];
customTypes?: null | AnotherCustomType[];
stringsList?: null | List<string>;
customTypesDict?: null | Dictionary<string, AnotherCustomType>;
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
};
export type Byte = {
};
export type AnotherEnum = 'B' | 'C';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

export type GenericContainingRootType = {
genericIntChild?: null | GenericChildType<number>;
genericNullableIntChild?: null | GenericChildType<Nullable<number>>;
arrayGenericNullableIntChild?: null | GenericChildType<Nullable<number>>[];
genericNullableIntChild?: null | GenericChildType<null | number>;
arrayGenericNullableIntChild?: null | GenericChildType<null | number>[];
severalGenericParameters?: null | ChildWithSeveralGenericParameters<string, number>;
genericChildType?: null | GenericChildType<ChildWithConstraint<string>>;
genericHell?: null | GenericChildType<ChildWithConstraint<GenericChildType<string>>>;
Expand All @@ -11,10 +11,6 @@ export type GenericChildType<T> = {
childType?: T;
childTypes?: null | T[];
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
};
export type ChildWithSeveralGenericParameters<T1, T2> = {
item1?: T1;
item2?: T2;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

export type GenericContainingRootType = {
genericIntChild?: null | GenericChildType<number>;
genericNullableIntChild?: null | GenericChildType<Nullable<number>>;
arrayGenericNullableIntChild?: null | GenericChildType<Nullable<number>>[];
genericNullableIntChild?: null | GenericChildType<null | number>;
arrayGenericNullableIntChild?: null | GenericChildType<null | number>[];
severalGenericParameters?: null | ChildWithSeveralGenericParameters<string, number>;
genericChildType?: null | GenericChildType<ChildWithConstraint<string>>;
genericHell?: null | GenericChildType<ChildWithConstraint<GenericChildType<string>>>;
Expand All @@ -11,10 +11,6 @@ export type GenericChildType<T> = {
childType?: T;
childTypes?: null | T[];
};
export type Nullable<T> = {
hasValue: boolean;
value: T;
};
export type ChildWithSeveralGenericParameters<T1, T2> = {
item1?: T1;
item2?: T2;
Expand Down
3 changes: 1 addition & 2 deletions TypeScript.ContractGenerator.Tests/OptionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Linq;

using FluentAssertions;
Expand Down Expand Up @@ -39,7 +38,7 @@ public void OptionalPropertiesTest(bool optionalPropertiesEnabled, string expect
[TestCase(false, "explicit-nullability-disabled")]
public void ExplicitNullabilityTest(bool explicitNullabilityEnabled, string expectedFileName)
{
var generatedCode = GenerateCode(new FlowTypeGenerationOptions {EnableExplicitNullability = explicitNullabilityEnabled}, CustomTypeGenerator.Null, typeof(NotNullRootType)).Single().Replace("\r\n", "\n");
var generatedCode = GenerateCode(new FlowTypeGenerationOptions {EnableExplicitNullability = explicitNullabilityEnabled}, CustomTypeGenerator.Null, typeof(ExplicitNullabilityRootType)).Single().Replace("\r\n", "\n");
var expectedCode = GetExpectedCode($"Options.Expected/{expectedFileName}");
generatedCode.Should().Be(expectedCode);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace SkbKontur.TypeScript.ContractGenerator.Tests.Types
{
public class ExplicitNullabilityRootType
{
[NotNull]
public SomeClass SomeNotNullClass { get; set; }

public SomeClass SomeNullableClass { get; set; }

[NotNull]
public string NotNullString { get; set; }

public string NullableString { get; set; }

public int NotNullInt { get; set; }

public int? NullableInt { get; set; }

[NotNull]
public int[] NotNullArray { get; set; }

public int[] NullableArray { get; set; }

[NotNull]
public int?[] NotNullNullablesArray { get; set; }

public int?[] NullableNullablesArray { get; set; }
}
}
8 changes: 6 additions & 2 deletions TypeScript.ContractGenerator/CodeDom/FlowTypeArrayType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ public FlowTypeArrayType(FlowTypeType itemType)
ItemType = itemType;
}

public FlowTypeType ItemType { get; private set; }
private FlowTypeType ItemType { get; }

public override string GenerateCode(ICodeGenerationContext context)
{
return ItemType.GenerateCode(context) + "[]";
var innerTypeCode = ItemType.GenerateCode(context);
if (!(ItemType is FlowTypeUnionType))
return innerTypeCode + "[]";

return $"Array<{innerTypeCode}>";
}
}
}
14 changes: 14 additions & 0 deletions TypeScript.ContractGenerator/CodeDom/FlowTypeOrNullType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace SkbKontur.TypeScript.ContractGenerator.CodeDom
{
public class FlowTypeOrNullType : FlowTypeUnionType
{
public FlowTypeOrNullType(FlowTypeType innerType)
: base(new[]
{
new FlowTypeBuildInType("null"),
innerType
})
{
}
}
}
9 changes: 7 additions & 2 deletions TypeScript.ContractGenerator/FlowTypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,13 @@ private ITypeBuildingContext GetTypeBuildingContext(string typeLocation, Type ty
: new TypeScriptEnumTypeBuildingContext(targetUnit, type);
}

if (options.UseGlobalNullable && type.IsGenericType && !type.IsGenericTypeDefinition && type.GetGenericTypeDefinition() == typeof(Nullable<>))
return new NullableTypeBuildingContext(type);
if (type.IsGenericType && !type.IsGenericTypeDefinition && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
var underlyingType = type.GenericTypeArguments.Single();
if (options.EnableExplicitNullability)
return new NullableTypeBuildingContext(underlyingType, options.UseGlobalNullable);
return GetTypeBuildingContext(typeLocation, underlyingType);
}

if (type.IsGenericType && !type.IsGenericTypeDefinition)
return new GenericTypeTypeBuildingContext(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,14 @@ private FlowTypeType GetMaybeNullableComplexType(ITypeGenerator typeGenerator, T
return new FlowTypeTypeReference(property.PropertyType.Name);

if (isNullable && options.EnableExplicitNullability && !options.UseGlobalNullable)
return OrNull(propertyType);
return new FlowTypeOrNullType(propertyType);

if (isNullable && options.EnableExplicitNullability && options.UseGlobalNullable)
return new FlowTypeNullableType(propertyType);

return propertyType;
}

private static FlowTypeUnionType OrNull(FlowTypeType buildAndImportType)
{
return new FlowTypeUnionType(
new[]
{
new FlowTypeBuildInType("null"),
buildAndImportType
}
);
}

private static string BuildPropertyName(string propertyName)
{
return propertyName.ToLowerCamelCase();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ namespace SkbKontur.TypeScript.ContractGenerator.TypeBuilders
{
public class NullableTypeBuildingContext : ITypeBuildingContext
{
public NullableTypeBuildingContext(Type nullableType)
public NullableTypeBuildingContext(Type nullableUnderlyingType, bool useGlobalNullable)
{
itemType = nullableType.GetGenericArguments()[0];
itemType = nullableUnderlyingType;
this.useGlobalNullable = useGlobalNullable;
}

public bool IsDefinitionBuilt => true;
Expand All @@ -24,9 +25,12 @@ public void BuildDefinition(ITypeGenerator typeGenerator)
public FlowTypeType ReferenceFrom(FlowTypeUnit targetUnit, ITypeGenerator typeGenerator)
{
var itemFlowType = typeGenerator.ResolveType(itemType).ReferenceFrom(targetUnit, typeGenerator);
return new FlowTypeNullableType(itemFlowType);
return useGlobalNullable
? (FlowTypeType)new FlowTypeNullableType(itemFlowType)
: new FlowTypeOrNullType(itemFlowType);
}

private readonly Type itemType;
private readonly bool useGlobalNullable;
}
}

0 comments on commit 8aac6a3

Please sign in to comment.