Skip to content

Commit

Permalink
Add support for TypeScript 4.3 override keyword (#1489)
Browse files Browse the repository at this point in the history
* Add support for TypeScript 4.3 override keyword

* Create verify tests for different output styles and TS versions
  • Loading branch information
lahma committed Feb 21, 2022
1 parent e082783 commit d3f648e
Show file tree
Hide file tree
Showing 19 changed files with 1,968 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using VerifyXunit;
using Xunit;

using static NJsonSchema.CodeGeneration.TypeScript.Tests.VerifyHelper;

namespace NJsonSchema.CodeGeneration.TypeScript.Tests
{
[UsesVerify]
public class ClassGenerationTests
{
public class MyClassTest
Expand Down Expand Up @@ -47,36 +51,29 @@ public class Person
public string LastName { get; set; }
}

[Fact]
public async Task When_generating_TypeScript_classes_then_output_is_correct()
{
var code = await PrepareAsync(new TypeScriptGeneratorSettings { TypeStyle = TypeScriptTypeStyle.Class });

//// Assert
Assert.Contains("init(_data?: any) {", code);
}

[Fact]
public async Task When_default_value_is_available_then_variable_is_initialized()
[Theory]
[InlineData(TypeScriptTypeStyle.Class, 1.8)]
[InlineData(TypeScriptTypeStyle.Class, 2.1)]
[InlineData(TypeScriptTypeStyle.Class, 2.7)]
[InlineData(TypeScriptTypeStyle.Class, 4.3)]
[InlineData(TypeScriptTypeStyle.KnockoutClass, 1.8)]
[InlineData(TypeScriptTypeStyle.KnockoutClass, 2.1)]
[InlineData(TypeScriptTypeStyle.KnockoutClass, 2.7)]
[InlineData(TypeScriptTypeStyle.KnockoutClass, 4.3)]
[InlineData(TypeScriptTypeStyle.Interface, 1.8)]
[InlineData(TypeScriptTypeStyle.Interface, 2.1)]
[InlineData(TypeScriptTypeStyle.Interface, 2.7)]
[InlineData(TypeScriptTypeStyle.Interface, 4.3)]
public async Task Verify_output(TypeScriptTypeStyle style, decimal version)
{
var code = await PrepareAsync(new TypeScriptGeneratorSettings
var settings = new TypeScriptGeneratorSettings
{
TypeStyle = TypeScriptTypeStyle.Class,
TypeScriptVersion = 1.8m
});

//// Assert
Assert.Contains("name: string;", code);
Assert.Contains("this.name = \"foo\";", code);
}

[Fact]
public async Task When_generating_TypeScript_knockout_classes_then_output_is_correct()
{
var code = await PrepareAsync(new TypeScriptGeneratorSettings { TypeStyle = TypeScriptTypeStyle.KnockoutClass });
TypeStyle = style,
TypeScriptVersion = version
};
var output = await PrepareAsync(settings);

//// Assert
Assert.Contains("dateOfBirth = ko.observable<Date>();", code);
await Verify(output).UseParameters(style, version);
}

private static async Task<string> PrepareAsync(TypeScriptGeneratorSettings settings)
Expand Down Expand Up @@ -239,17 +236,6 @@ public void When_object_property_is_required_or_not_then_the_code_has_correct_in
Assert.Contains("this.b = _data[\"B\"] ? B.fromJS(_data[\"B\"]) : <any>undefined;", code);
}

[Fact]
public async Task When_export_types_is_true_add_export_before_class_and_interface()
{
var code = await PrepareAsync(new TypeScriptGeneratorSettings { TypeStyle = TypeScriptTypeStyle.Class, ExportTypes = true });

//// Assert
Assert.Contains("export class Student extends Person implements IStudent {", code);
Assert.Contains("export interface IStudent extends IPerson {", code);
Assert.Contains("export interface IPerson {", code);
}

[Fact]
public async Task When_export_types_is_false_dont_add_export_before_class_and_interface()
{
Expand All @@ -261,15 +247,6 @@ public async Task When_export_types_is_false_dont_add_export_before_class_and_in
Assert.DoesNotContain("export interface IPerson {", code);
}

[Fact]
public async Task When_add_export_keyword_is_true_with_knockout_class_add_export_before_class()
{
var code = await PrepareAsync(new TypeScriptGeneratorSettings { TypeStyle = TypeScriptTypeStyle.KnockoutClass, ExportTypes = true });

//// Assert
Assert.Contains("export class Student extends Person {", code);
}

[Fact]
public async Task When_add_export_keyword_is_false_with_knockout_class_dont_add_export_before_class()
{
Expand All @@ -279,17 +256,6 @@ public async Task When_add_export_keyword_is_false_with_knockout_class_dont_add_
Assert.DoesNotContain("export class Student extends Person {", code);
}

[Fact]
public async Task When_class_is_generated_then_constructor_interfaces_are_correctly_generated()
{
var code = await PrepareAsync(new TypeScriptGeneratorSettings { TypeStyle = TypeScriptTypeStyle.Class });

//// Assert
Assert.Contains("class Student extends Person implements IStudent {", code);
Assert.Contains("interface IStudent extends IPerson {", code);
Assert.Contains("interface IPerson {", code);
}

[Fact]
public async Task When_GenerateConstructorInterface_then_no_interfaces_are_generated()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<NoWarn>$(NoWarn),1587,1998,1591,618</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Verify.XUnit" Version="14.7.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<Reference Condition="'$(TargetFramework)' == 'net461'" Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
//----------------------
// <auto-generated>
// </auto-generated>
//----------------------







export class Person implements IPerson {
firstName: string;
lastName: string;

constructor(data?: IPerson) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
}

init(_data?: any) {
if (_data) {
this.firstName = _data["FirstName"];
this.lastName = _data["LastName"];
}
}

static fromJS(data: any): Person {
data = typeof data === 'object' ? data : {};
let result = new Person();
result.init(data);
return result;
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["FirstName"] = this.firstName;
data["LastName"] = this.lastName;
return data;
}
}

export interface IPerson {
firstName: string;
lastName: string;
}

export class Student extends Person implements IStudent {
study: string;

constructor(data?: IStudent) {
super(data);
}

init(_data?: any) {
super.init(_data);
if (_data) {
this.study = _data["Study"];
}
}

static fromJS(data: any): Student {
data = typeof data === 'object' ? data : {};
let result = new Student();
result.init(data);
return result;
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["Study"] = this.study;
super.toJSON(data);
return data;
}
}

export interface IStudent extends IPerson {
study: string;
}

export class MyClass implements IMyClass {
name: string;
dateOfBirth: Date;
primitiveArray: number[];
primitiveDictionary: { [key: string]: number; };
dateArray: Date[];
dateDictionary: { [key: string]: Date; };
reference: Student;
array: Student[];
dictionary: { [key: string]: Student; };

constructor(data?: IMyClass) {
if (data) {
for (var property in data) {
if (data.hasOwnProperty(property))
(<any>this)[property] = (<any>data)[property];
}
}
if (!data) {
this.name = "foo";
}
}

init(_data?: any) {
if (_data) {
this.name = _data["Name"] !== undefined ? _data["Name"] : "foo";
this.dateOfBirth = _data["DateOfBirth"] ? new Date(_data["DateOfBirth"].toString()) : <any>undefined;
if (Array.isArray(_data["PrimitiveArray"])) {
this.primitiveArray = [] as any;
for (let item of _data["PrimitiveArray"])
this.primitiveArray.push(item);
}
if (_data["PrimitiveDictionary"]) {
this.primitiveDictionary = {} as any;
for (let key in _data["PrimitiveDictionary"]) {
if (_data["PrimitiveDictionary"].hasOwnProperty(key))
(<any>this.primitiveDictionary)[key] = _data["PrimitiveDictionary"][key];
}
}
if (Array.isArray(_data["DateArray"])) {
this.dateArray = [] as any;
for (let item of _data["DateArray"])
this.dateArray.push(new Date(item));
}
if (_data["DateDictionary"]) {
this.dateDictionary = {} as any;
for (let key in _data["DateDictionary"]) {
if (_data["DateDictionary"].hasOwnProperty(key))
(<any>this.dateDictionary)[key] = _data["DateDictionary"][key] ? new Date(_data["DateDictionary"][key].toString()) : <any>undefined;
}
}
this.reference = _data["Reference"] ? Student.fromJS(_data["Reference"]) : <any>undefined;
if (Array.isArray(_data["Array"])) {
this.array = [] as any;
for (let item of _data["Array"])
this.array.push(Student.fromJS(item));
}
if (_data["Dictionary"]) {
this.dictionary = {} as any;
for (let key in _data["Dictionary"]) {
if (_data["Dictionary"].hasOwnProperty(key))
(<any>this.dictionary)[key] = _data["Dictionary"][key] ? Student.fromJS(_data["Dictionary"][key]) : new Student();
}
}
}
}

static fromJS(data: any): MyClass {
data = typeof data === 'object' ? data : {};
let result = new MyClass();
result.init(data);
return result;
}

toJSON(data?: any) {
data = typeof data === 'object' ? data : {};
data["Name"] = this.name;
data["DateOfBirth"] = this.dateOfBirth ? this.dateOfBirth.toISOString() : <any>undefined;
if (Array.isArray(this.primitiveArray)) {
data["PrimitiveArray"] = [];
for (let item of this.primitiveArray)
data["PrimitiveArray"].push(item);
}
if (this.primitiveDictionary) {
data["PrimitiveDictionary"] = {};
for (let key in this.primitiveDictionary) {
if (this.primitiveDictionary.hasOwnProperty(key))
(<any>data["PrimitiveDictionary"])[key] = this.primitiveDictionary[key];
}
}
if (Array.isArray(this.dateArray)) {
data["DateArray"] = [];
for (let item of this.dateArray)
data["DateArray"].push(item.toISOString());
}
if (this.dateDictionary) {
data["DateDictionary"] = {};
for (let key in this.dateDictionary) {
if (this.dateDictionary.hasOwnProperty(key))
(<any>data["DateDictionary"])[key] = this.dateDictionary[key] ? this.dateDictionary[key].toISOString() : <any>undefined;
}
}
data["Reference"] = this.reference ? this.reference.toJSON() : <any>undefined;
if (Array.isArray(this.array)) {
data["Array"] = [];
for (let item of this.array)
data["Array"].push(item.toJSON());
}
if (this.dictionary) {
data["Dictionary"] = {};
for (let key in this.dictionary) {
if (this.dictionary.hasOwnProperty(key))
(<any>data["Dictionary"])[key] = this.dictionary[key] ? this.dictionary[key].toJSON() : <any>undefined;
}
}
return data;
}
}

export interface IMyClass {
name: string;
dateOfBirth: Date;
primitiveArray: number[];
primitiveDictionary: { [key: string]: number; };
dateArray: Date[];
dateDictionary: { [key: string]: Date; };
reference: Student;
array: Student[];
dictionary: { [key: string]: Student; };
}
Loading

0 comments on commit d3f648e

Please sign in to comment.