Skip to content

Commit

Permalink
Merge branch 'vNext'
Browse files Browse the repository at this point in the history
  • Loading branch information
iperevoschikov committed Feb 18, 2019
2 parents 2cd9cef + 3dc9134 commit 89ee356
Show file tree
Hide file tree
Showing 68 changed files with 853 additions and 172 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v1.1 - 2019.02.18
- TypeScript files generated with '.ts' extension
- Generation options: EnumGenerationMode: FixedStringsAndDictionary | TypeScriptEnum, EnableOptionalProperties, EnableExplicitNullability
- IRootTypes provider interface (preparation to build in executable generator)
- Add internal JetBrains.Annotations
- Typos fixes at ITypeBuildingContext: IDefinitionBuilded -> IsDefinitionBuilt, BuildDefiniion -> BuildDefinition

## v1.0 - 2019.01.30
- Support .NET Standard 2.0.
- Switch to SDK-style project format and dotnet core build tooling.
Expand Down
1 change: 1 addition & 0 deletions Common.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
Expand Down
65 changes: 62 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public class SecondType
Then generate TypeScript files with:

```csharp
var generator = new FlowTypeGenerator(customTypeGenerator : null, rootTypes : new[] {typeof(SecondType)});
generator.GenerateTypeScriptFiles("./output");
var generator = new FlowTypeGenerator(FlowTypeGenerationOptions.Default, CustomTypeGenerator.Null, new RootTypesProvider(typeof(SecondType)));
generator.GenerateFiles("./output", JavaScriptTypeChecker.TypeScript);
```

By default, this will generate file with name `.tsx` with following content:
By default, this will generate file with name `.ts` with following content:

```ts
// TypeScriptContractGenerator's generated content
Expand All @@ -52,6 +52,65 @@ export type FirstType = {

If you want generated files to have different name or to generate some typings differently, you should pass your own implementation of `ICustomTypeGenerator` to `FlowTypeGenerator`.

## Generation options

### EnumGenerationMode

This options is set to `FixedStringsAndDictionary` by default.

```csharp
public enum EnumGenerationMode
{
FixedStringsAndDictionary = 0,
TypeScriptEnum = 1,
}
```

Setting option value equal to `FixedStringsAndDictionary` produces following output:

```ts
export type SomeEnum = 'A' | 'B';
export const SomeEnums = {
['A']: ('A') as SomeEnum,
['B']: ('B') as SomeEnum,
};
```

Option value `TypeScriptEnum` produces following:

```ts
export enum SomeEnum {
A = 'A',
B = 'B',
}
```

### EnableOptionalProperties

This option is **enabled** by default. When **enabled** produces optional properties for members which may contain nulls.

```ts
export type SomeType = {
somePropertyWithNullableValue?: typeDefinition;
somePropertyWithNonNullableValue: typeDefinition;
};

```
When **disabled**, all properties produced as required.

### EnableExplicitNullability

This option is **enabled** by default. When **enabled** produces nullable types for members which may contain nulls.

```ts
export type SomeType = {
nullablePropertyDefinition: null | string;
nonNullablePropertyDefinition: string;
};
```

When **disabled** produces all types as-is.

## Known bugs

See [this issue](https://github.com/skbkontur/TypeScript.ContractGenerator/issues/1)
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ public DictionaryTypeBuildingContext(Type dictionaryType)
valueType = dictionaryType.GetGenericArguments()[1];
}

public bool IsDefinitionBuilded => true;
public bool IsDefinitionBuilt => true;

public void Initialize(ITypeGenerator typeGenerator)
{
}

public void BuildDefiniion(ITypeGenerator typeGenerator)
public void BuildDefinition(ITypeGenerator typeGenerator)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ public ListTypeBuildingContext(Type listType)
itemType = listType.GetGenericArguments()[0];
}

public bool IsDefinitionBuilded => true;
public bool IsDefinitionBuilt => true;

public void Initialize(ITypeGenerator typeGenerator)
{
}

public void BuildDefiniion(ITypeGenerator typeGenerator)
public void BuildDefinition(ITypeGenerator typeGenerator)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ namespace SkbKontur.TypeScript.ContractGenerator.Tests.CustomTypeGenerators
{
public class StringBuildingContext : ITypeBuildingContext
{
public bool IsDefinitionBuilded => true;
public bool IsDefinitionBuilt => true;

public void Initialize(ITypeGenerator typeGenerator)
{
}

public void BuildDefiniion(ITypeGenerator typeGenerator)
public void BuildDefinition(ITypeGenerator typeGenerator)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace SkbKontur.TypeScript.ContractGenerator.Tests.CustomTypeGenerators
{
public class CustomTypeGenerator : ICustomTypeGenerator
public class TestCustomTypeGenerator : ICustomTypeGenerator
{
public string GetTypeLocation(Type type)
{
Expand Down
7 changes: 3 additions & 4 deletions TypeScript.ContractGenerator.Tests/EndToEndTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.IO;
using System.Linq;

using FluentAssertions;
Expand Down Expand Up @@ -31,7 +30,7 @@ public EndToEndTests(JavaScriptTypeChecker javaScriptTypeChecker)
public void GenerateCodeTest(Type rootType, string expectedFileName)
{
var generatedCode = GenerateCode(rootType).Single().Replace("\r\n", "\n");
var expectedCode = File.ReadAllText(GetFilePath($"SimpleGenerator/{expectedFileName}")).Replace("\r\n", "\n");
var expectedCode = GetExpectedCode($"SimpleGenerator/{expectedFileName}");
generatedCode.Should().Be(expectedCode);
}

Expand All @@ -49,8 +48,8 @@ public void GenerateFilesTest(Type type)
[TestCase(typeof(ArrayRootType), "array-types.expected")]
public void CustomGeneratorTest(Type rootType, string expectedFileName)
{
var generatedCode = GenerateCode(new CustomTypeGenerator(), rootType).Single().Replace("\r\n", "\n");
var expectedCode = File.ReadAllText(GetFilePath($"CustomGenerator/{expectedFileName}")).Replace("\r\n", "\n");
var generatedCode = GenerateCode(new TestCustomTypeGenerator(), rootType).Single().Replace("\r\n", "\n");
var expectedCode = GetExpectedCode($"CustomGenerator/{expectedFileName}");
generatedCode.Should().Be(expectedCode);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

export type DefaultEnum = 'A' | 'B';
export const DefaultEnums = {
['A']: (('A'): DefaultEnum),
['B']: (('B'): DefaultEnum),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

export type DefaultEnum = 'A' | 'B';
export const DefaultEnums = {
['A']: ('A') as DefaultEnum,
['B']: ('B') as DefaultEnum,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export enum DefaultEnum {
A = 'A',
B = 'B',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

export enum DefaultEnum {
A = 'A',
B = 'B',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

export type NotNullRootType = {
someNotNullClass: SomeClass;
someNullableClass?: SomeClass;
notNullString: string;
};
export type SomeClass = {
a: number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

export type NotNullRootType = {
someNotNullClass: SomeClass;
someNullableClass?: SomeClass;
notNullString: string;
};
export type SomeClass = {
a: number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

export type NotNullRootType = {
someNotNullClass: SomeClass;
someNullableClass?: null | SomeClass;
notNullString: string;
};
export type SomeClass = {
a: number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

export type NotNullRootType = {
someNotNullClass: SomeClass;
someNullableClass?: null | SomeClass;
notNullString: string;
};
export type SomeClass = {
a: number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export type SingleNullablePropertyType = {
a: null | number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export type SingleNullablePropertyType = {
a: null | number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export type SingleNullablePropertyType = {
a?: null | number;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export type SingleNullablePropertyType = {
a?: null | number;
};
40 changes: 23 additions & 17 deletions TypeScript.ContractGenerator.Tests/FlowTypeTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,40 @@ public abstract class FlowTypeTestBase
{
protected FlowTypeTestBase(JavaScriptTypeChecker javaScriptTypeChecker)
{
this.javaScriptTypeChecker = javaScriptTypeChecker;
fileExtension = javaScriptTypeChecker == JavaScriptTypeChecker.TypeScript ? "ts" : "js";
filesGenerationContext = FilesGenerationContext.Create(javaScriptTypeChecker);
}

protected string[] GenerateCode(Type rootType)
{
return GenerateCode(null, rootType);
return GenerateCode(CustomTypeGenerator.Null, rootType);
}

protected string[] GenerateCode(ICustomTypeGenerator customTypeGenerator, Type rootType)
{
var generator = new FlowTypeGenerator(customTypeGenerator, new[] {rootType});
return generator.Generate().Select(x => x.GenerateCode(new DefaultCodeGenerationContext(javaScriptTypeChecker))).ToArray();
return GenerateCode(FlowTypeGenerationOptions.Default, customTypeGenerator, rootType);
}

protected string[] GenerateCode(FlowTypeGenerationOptions options, ICustomTypeGenerator customTypeGenerator, Type rootType)
{
var generator = new FlowTypeGenerator(options, customTypeGenerator, new RootTypesProvider(rootType));
return generator.Generate().Select(x => x.GenerateCode(new DefaultCodeGenerationContext(JavaScriptTypeChecker))).ToArray();
}

protected void GenerateFiles(ICustomTypeGenerator customTypeGenerator, string folderName, params Type[] rootTypes)
{
var path = $"{TestContext.CurrentContext.TestDirectory}/{folderName}/{javaScriptTypeChecker}";
var path = $"{TestContext.CurrentContext.TestDirectory}/{folderName}/{JavaScriptTypeChecker}";
if (Directory.Exists(path))
Directory.Delete(path, recursive : true);
Directory.CreateDirectory(path);

var generator = new FlowTypeGenerator(customTypeGenerator, rootTypes);
if (javaScriptTypeChecker == JavaScriptTypeChecker.Flow)
generator.GenerateFiles(path);
else
generator.GenerateTypeScriptFiles(path);
var generator = new FlowTypeGenerator(FlowTypeGenerationOptions.Default, customTypeGenerator, new RootTypesProvider(rootTypes));
generator.GenerateFiles(path, JavaScriptTypeChecker);
}

protected void CheckDirectoriesEquivalence(string expectedDirectory, string actualDirectory)
{
expectedDirectory = $"{TestContext.CurrentContext.TestDirectory}/{expectedDirectory}/{javaScriptTypeChecker}";
actualDirectory = $"{TestContext.CurrentContext.TestDirectory}/{actualDirectory}/{javaScriptTypeChecker}";
expectedDirectory = $"{TestContext.CurrentContext.TestDirectory}/{expectedDirectory}/{JavaScriptTypeChecker}";
actualDirectory = $"{TestContext.CurrentContext.TestDirectory}/{actualDirectory}/{JavaScriptTypeChecker}";

CheckDirectoriesEquivalenceInner(expectedDirectory, actualDirectory);
}
Expand Down Expand Up @@ -80,12 +81,17 @@ private static void CheckDirectoriesEquivalenceInner(string expectedDirectory, s
CheckDirectoriesEquivalenceInner($"{expectedDirectory}/{directory}", $"{actualDirectory}/{directory}");
}

protected string GetFilePath(string filename)
protected string GetExpectedCode(string expectedCodeFilePath)
{
return File.ReadAllText(GetFilePath(expectedCodeFilePath)).Replace("\r\n", "\n");
}

private string GetFilePath(string filename)
{
return $"{TestContext.CurrentContext.TestDirectory}/Files/{filename}.{fileExtension}";
return $"{TestContext.CurrentContext.TestDirectory}/Files/{filename}.{filesGenerationContext.FileExtension}";
}

private readonly JavaScriptTypeChecker javaScriptTypeChecker;
private readonly string fileExtension;
private readonly FilesGenerationContext filesGenerationContext;
private JavaScriptTypeChecker JavaScriptTypeChecker => filesGenerationContext.JavaScriptTypeChecker;
}
}
3 changes: 2 additions & 1 deletion TypeScript.ContractGenerator.Tests/GenericTypesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public class GenericTypesTest
[Test]
public void RootCantBeGenericType()
{
new FlowTypeGenerator(null, new[] {typeof(GenericRootType<CustomType>)}).Generate().Should().BeEmpty();
new FlowTypeGenerator(FlowTypeGenerationOptions.Default, CustomTypeGenerator.Null, new RootTypesProvider(typeof(GenericRootType<CustomType>)))
.Generate().Should().BeEmpty();
}
}
}
Loading

0 comments on commit 89ee356

Please sign in to comment.