Skip to content

Commit

Permalink
Merge pull request #10 from mr146/master
Browse files Browse the repository at this point in the history
Substitute value in enums where getter returns constant value
  • Loading branch information
fakefeik authored Mar 8, 2019
2 parents 3c96774 + 8f4cfed commit 99ce2b3
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 13 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## v1.4 - 2019.03.08
- `//tslint:disable` is placed before codegen marker
- Global rename: `FlowType => TypeScript`
- Add support for enum properties with user-defined getter (see `GenerateEnumWithConstGetterTest` for details)

## v1.3 - 2019.02.22
- Correctly generate built-in types
- Add support for `List<T>` and `Dictionary<TKey, TValue>`
Expand Down
9 changes: 9 additions & 0 deletions TypeScript.ContractGenerator.Tests/EndToEndTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ public void GenerateCodeTest(Type rootType, string expectedFileName)
generatedCode.Should().Be(expectedCode);
}

[TestCase(EnumGenerationMode.FixedStringsAndDictionary, "enum-types-with-const-getter-fixed-strings.expected")]
[TestCase(EnumGenerationMode.TypeScriptEnum, "enum-types-with-const-getter-typescript-enum.expected")]
public void GenerateEnumWithConstGetterTest(EnumGenerationMode enumGenerationMode, string expectedFileName)
{
var generatedCode = GenerateCode(new TypeScriptGenerationOptions {EnumGenerationMode = enumGenerationMode}, CustomTypeGenerator.Null, typeof(EnumWithConstGetterContainingRootType)).Single().Replace("\r\n", "\n");
var expectedCode = GetExpectedCode($"SimpleGenerator/{expectedFileName}");
generatedCode.Should().Be(expectedCode);
}

[TestCase(typeof(FlatTypeLocator))]
[TestCase(typeof(SimpleStructureTypeLocator))]
public void GenerateFilesTest(Type type)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export type EnumWithConstGetterContainingRootType = {
defaultEnum: 'A';
explicitEnum: 'C';
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export type EnumWithConstGetterContainingRootType = {
defaultEnum: 'A';
explicitEnum: 'C';
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

export type EnumWithConstGetterContainingRootType = {
defaultEnum: DefaultEnum.A;
explicitEnum: ExplicitEnum.C;
};
export enum DefaultEnum {
A = 'A',
B = 'B',
}
export enum ExplicitEnum {
C = 'C',
D = 'D',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

export type EnumWithConstGetterContainingRootType = {
defaultEnum: DefaultEnum.A;
explicitEnum: ExplicitEnum.C;
};
export enum DefaultEnum {
A = 'A',
B = 'B',
}
export enum ExplicitEnum {
C = 'C',
D = 'D',
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<IsPackable>false</IsPackable>
Expand Down Expand Up @@ -55,6 +55,10 @@
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\complex-types.expected.ts" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\enum-types.expected.js" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\enum-types.expected.ts" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\enum-types-with-const-getter-fixed-strings.expected.ts" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\enum-types-with-const-getter-fixed-strings.expected.js" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\enum-types-with-const-getter-typescript-enum.expected.ts" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\enum-types-with-const-getter-typescript-enum.expected.js" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\generic-root.expected.js" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\generic-root.expected.ts" />
<None CopyToOutputDirectory="Always" Update="Files\SimpleGenerator\generic-types.expected.js" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ public class EnumContainingRootType
public ExplicitEnum ExplicitEnum { get; set; }
}

public class EnumWithConstGetterContainingRootType
{
public DefaultEnum DefaultEnum => DefaultEnum.A;
public ExplicitEnum ExplicitEnum => ExplicitEnum.C;
}

public enum DefaultEnum
{
A,
Expand Down
19 changes: 19 additions & 0 deletions TypeScript.ContractGenerator/CodeDom/TypeScriptEnumValueType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace SkbKontur.TypeScript.ContractGenerator.CodeDom
{
public class TypeScriptEnumValueType : TypeScriptType
{
public TypeScriptEnumValueType(TypeScriptType enumType, string value)
{
this.enumType = enumType;
this.value = value;
}

public override string GenerateCode(ICodeGenerationContext context)
{
return $"{enumType.GenerateCode(context)}.{value}";
}

private readonly TypeScriptType enumType;
private readonly string value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private TypeScriptTypeDeclaration CreateComplexTypeScriptDeclarationWithoutDefin

public override void Initialize(ITypeGenerator typeGenerator)
{
if (Type.BaseType != typeof(object) && Type.BaseType != typeof(ValueType) && Type.BaseType != typeof(MarshalByRefObject) && Type.BaseType != null)
if(Type.BaseType != typeof(object) && Type.BaseType != typeof(ValueType) && Type.BaseType != typeof(MarshalByRefObject) && Type.BaseType != null)
{
typeGenerator.ResolveType(Type.BaseType);
}
Expand All @@ -51,31 +51,67 @@ protected virtual TypeScriptTypeDefintion CreateComplexTypeScriptDefinition(ITyp
{
var result = new TypeScriptTypeDefintion();
var properties = CreateTypeProperties(Type);
foreach (var property in properties)
foreach(var property in properties)
{
var (isNullable, type) = TypeScriptGeneratorHelpers.ProcessNullable(property, property.PropertyType);

result.Members.Add(new TypeScriptTypeMemberDeclaration
{
Name = BuildPropertyName(property.Name),
Optional = isNullable && options.EnableOptionalProperties,
Type = GetMaybeNullableComplexType(typeGenerator, type, property, isNullable),
});
if(TryGetGetOnlyEnumPropertyValue(property, out var value))
{
result.Members.Add(new TypeScriptTypeMemberDeclaration
{
Name = BuildPropertyName(property.Name),
Optional = isNullable && options.EnableOptionalProperties,
Type = GetConstEnumType(typeGenerator, property, value),
});
}
else
{
result.Members.Add(new TypeScriptTypeMemberDeclaration
{
Name = BuildPropertyName(property.Name),
Optional = isNullable && options.EnableOptionalProperties,
Type = GetMaybeNullableComplexType(typeGenerator, type, property, isNullable),
});
}
}
return result;
}

private TypeScriptType GetConstEnumType(ITypeGenerator typeGenerator, PropertyInfo property, string value)
{
switch(options.EnumGenerationMode)
{
case EnumGenerationMode.FixedStringsAndDictionary:
return new TypeScriptStringLiteralType(value);
case EnumGenerationMode.TypeScriptEnum:
return new TypeScriptEnumValueType(typeGenerator.BuildAndImportType(Unit, property, property.PropertyType), value);
default:
throw new ArgumentOutOfRangeException();
}
}

private bool TryGetGetOnlyEnumPropertyValue(PropertyInfo property, out string value)
{
if(!property.PropertyType.IsEnum || property.CanWrite || Type.GetConstructors().All(x => x.GetParameters().Length > 0))
{
value = null;
return false;
}
value = property.GetMethod.Invoke(Activator.CreateInstance(Type), null).ToString();
return true;
}

private TypeScriptType GetMaybeNullableComplexType(ITypeGenerator typeGenerator, Type type, PropertyInfo property, bool isNullable)
{
var propertyType = typeGenerator.BuildAndImportType(Unit, null, type);

if (property.PropertyType.IsGenericParameter)
if(property.PropertyType.IsGenericParameter)
return new TypeScriptTypeReference(property.PropertyType.Name);

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

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

return propertyType;
Expand Down
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "1.3",
"version": "1.4",
"assemblyVersion": {
"precision": "build"
},
Expand Down

0 comments on commit 99ce2b3

Please sign in to comment.