Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a feature to support additional class properties in TypeGen #181

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion nuget-dotnetcli/dotnet-typegen.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>dotnet-typegen</id>
<version>5.0.0</version>
<version>5.0.1</version>
<authors>Jacek Burzynski</authors>
<owners>Jacek Burzynski</owners>
<license type="file">LICENSE</license>
Expand Down
2 changes: 1 addition & 1 deletion nuget/TypeGen.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>TypeGen</id>
<version>5.0.0</version>
<version>5.0.1</version>
<authors>Jacek Burzynski</authors>
<owners>Jacek Burzynski</owners>
<license type="file">LICENSE</license>
Expand Down
2 changes: 1 addition & 1 deletion src/TypeGen/TypeGen.Cli/ApplicationConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ namespace TypeGen.Cli;

internal class ApplicationConfig
{
public const string Version = "5.0.0";
public const string Version = "5.0.1";
}
6 changes: 3 additions & 3 deletions src/TypeGen/TypeGen.Cli/TypeGen.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<FileVersion>5.0.0.0</FileVersion>
<Version>5.0.0</Version>
<AssemblyVersion>5.0.0.1</AssemblyVersion>
<FileVersion>5.0.0.1</FileVersion>
<Version>5.0.1</Version>
<PackageId>TypeGen</PackageId>
<Authors />
</PropertyGroup>
Expand Down
79 changes: 54 additions & 25 deletions src/TypeGen/TypeGen.Core/Generator/Generator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand All @@ -12,6 +11,7 @@
using TypeGen.Core.Logging;
using TypeGen.Core.Metadata;
using TypeGen.Core.SpecGeneration;
using TypeGen.Core.SpecGeneration.Builders.Traits;
using TypeGen.Core.Storage;
using TypeGen.Core.TypeAnnotations;
using TypeGen.Core.Validation;
Expand Down Expand Up @@ -65,8 +65,8 @@ public Generator(GeneratorOptions options, ILogger logger = null)
_typeService = new TypeService(_metadataReaderFactory, generatorOptionsProvider);
_typeDependencyService = new TypeDependencyService(_typeService, _metadataReaderFactory, generatorOptionsProvider);
_templateService = new TemplateService(internalStorage, generatorOptionsProvider);

_tsContentGenerator = new TsContentGenerator(_typeDependencyService,

_typeService,
_templateService,
new TsContentParser(_fileSystem),
Expand Down Expand Up @@ -140,6 +140,7 @@ public IEnumerable<string> Generate(IEnumerable<GenerationSpec> generationSpecs)
Requires.NotNullOrEmpty(generationSpecs, nameof(generationSpecs));

generationSpecs = generationSpecs.ToList();

var files = new List<string>();
_generationContext = new GenerationContext(_fileSystem);

Expand All @@ -153,7 +154,7 @@ public IEnumerable<string> Generate(IEnumerable<GenerationSpec> generationSpecs)
_metadataReaderFactory.GenerationSpec = generationSpec;

foreach (KeyValuePair<Type, TypeSpec> kvp in generationSpec.TypeSpecs)
files.AddRange(GenerateMarkedType(kvp.Key));
files.AddRange(GenerateMarkedType(kvp.Key, kvp.Value));
}

files = files.Distinct().ToList();
Expand Down Expand Up @@ -326,15 +327,15 @@ private IEnumerable<string> GenerateIndexFile(IEnumerable<string> generatedFiles
return new[] { filename };
}

private IEnumerable<string> GenerateMarkedType(Type type)
private IEnumerable<string> GenerateMarkedType(Type type, TypeSpec typeSpec)
{
if (Options.IsTypeBlacklisted(type)) return Enumerable.Empty<string>();

IEnumerable<string> files = Enumerable.Empty<string>();

_generationContext.BeginTypeGeneration(type);
_generationContext.AddGeneratedType(type);
ExecuteWithTypeContextLogging(() => { files = GenerateType(type); });
ExecuteWithTypeContextLogging(() => { files = GenerateType(type, typeSpec); });
_generationContext.EndTypeGeneration();

return files.Distinct();
Expand All @@ -346,50 +347,51 @@ private IEnumerable<string> GenerateMarkedType(Type type)
/// </summary>
/// <param name="type"></param>
/// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
private IEnumerable<string> GenerateType(Type type)
private IEnumerable<string> GenerateType(Type type, TypeSpec typeSpec)
{
var classAttribute = _metadataReaderFactory.GetInstance().GetAttribute<ExportTsClassAttribute>(type);
var interfaceAttribute = _metadataReaderFactory.GetInstance().GetAttribute<ExportTsInterfaceAttribute>(type);
var enumAttribute = _metadataReaderFactory.GetInstance().GetAttribute<ExportTsEnumAttribute>(type);

if (classAttribute != null)
{
return GenerateClass(type, classAttribute);
return GenerateClass(type, classAttribute, typeSpec);
}

if (interfaceAttribute != null)
{
return GenerateInterface(type, interfaceAttribute);
return GenerateInterface(type, interfaceAttribute, typeSpec);
}

if (enumAttribute != null)
{
return GenerateEnum(type, enumAttribute);
}

return GenerateNotMarkedType(type, Options.BaseOutputDirectory);
return GenerateNotMarkedType(type, Options.BaseOutputDirectory, typeSpec);
}

/// <summary>
/// Generates TypeScript files for types that are not marked with an ExportTs... attribute
/// </summary>
/// <param name="type"></param>
/// <param name="outputDirectory"></param>
/// <param name="typeSpec"></param>
/// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
private IEnumerable<string> GenerateNotMarkedType(Type type, string outputDirectory)
private IEnumerable<string> GenerateNotMarkedType(Type type, string outputDirectory, TypeSpec typeSpec)
{
if (Options.IsTypeBlacklisted(type)) return Enumerable.Empty<string>();

var typeInfo = type.GetTypeInfo();
if (typeInfo.IsClass || typeInfo.IsStruct())
{
return Options.ExportTypesAsInterfacesByDefault
? GenerateInterface(type, new ExportTsInterfaceAttribute { OutputDir = outputDirectory })
: GenerateClass(type, new ExportTsClassAttribute { OutputDir = outputDirectory });
? GenerateInterface(type, new ExportTsInterfaceAttribute { OutputDir = outputDirectory }, typeSpec)
: GenerateClass(type, new ExportTsClassAttribute { OutputDir = outputDirectory }, typeSpec);
}

if (typeInfo.IsInterface)
return GenerateInterface(type, new ExportTsInterfaceAttribute { OutputDir = outputDirectory });
return GenerateInterface(type, new ExportTsInterfaceAttribute { OutputDir = outputDirectory }, typeSpec);

if (typeInfo.IsEnum)
return GenerateEnum(type, new ExportTsEnumAttribute { OutputDir = outputDirectory });
Expand All @@ -402,11 +404,12 @@ private IEnumerable<string> GenerateNotMarkedType(Type type, string outputDirect
/// </summary>
/// <param name="type"></param>
/// <param name="classAttribute"></param>
/// <param name="typeSpec"></param>
/// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute classAttribute)
private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute classAttribute, TypeSpec typeSpec)
{
string outputDir = classAttribute.OutputDir;
IEnumerable<string> dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir);
IEnumerable<string> dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir, typeSpec);

// get text for sections

Expand All @@ -428,7 +431,7 @@ private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute clas
}

string importsText = _tsContentGenerator.GetImportsText(type, outputDir);
string propertiesText = GetClassPropertiesText(type);
string propertiesText = GetClassPropertiesText(type, typeSpec.AdditionalClassProperties);

// generate the file content

Expand Down Expand Up @@ -458,11 +461,12 @@ private IEnumerable<string> GenerateClass(Type type, ExportTsClassAttribute clas
/// </summary>
/// <param name="type"></param>
/// <param name="interfaceAttribute"></param>
/// <param name="typeSpec"></param>
/// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
private IEnumerable<string> GenerateInterface(Type type, ExportTsInterfaceAttribute interfaceAttribute)
private IEnumerable<string> GenerateInterface(Type type, ExportTsInterfaceAttribute interfaceAttribute, TypeSpec typeSpec)
{
string outputDir = interfaceAttribute.OutputDir;
IEnumerable<string> dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir);
IEnumerable<string> dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir, typeSpec);

// get text for sections

Expand Down Expand Up @@ -648,20 +652,44 @@ private void LogClassPropertyWarnings(MemberInfo memberInfo)
/// Gets TypeScript class properties definition source code
/// </summary>
/// <param name="type"></param>
/// <param name="additionalProperties"></param>
/// <returns></returns>
private string GetClassPropertiesText(Type type)
private string GetClassPropertiesText(Type type, IEnumerable<AdditionalClassProperty> additionalProperties)
{
var propertiesText = "";
IEnumerable<MemberInfo> memberInfos = type.GetTsExportableMembers(_metadataReaderFactory.GetInstance());

// create TypeScript source code for properties' definition

// Generate TypeScript properties from C# members
propertiesText += memberInfos
.Aggregate(propertiesText, (current, memberInfo) => current + GetClassPropertyText(type, memberInfo));
.Aggregate("", (current, memberInfo) => current + GetClassPropertyText(type, memberInfo));

propertiesText += GetAdditionalPropertiesText(additionalProperties);

return RemoveLastLineEnding(propertiesText);
}

/// <summary>
/// Gets TypeScript class additional properties if defined
/// </summary>
/// <param name="additionalProperties"></param>
/// <returns></returns>
private string GetAdditionalPropertiesText(IEnumerable<AdditionalClassProperty> additionalProperties)
{
if (!additionalProperties.Any())
{
return "";
}

var additionalPropertiesText = _templateService.FillWithSingleLineComment("Additional properties");

foreach (var property in additionalProperties)
{
additionalPropertiesText += _templateService.FillClassPropertyTemplate(property.Name, property.Type, property.DefaultValue);
}

return additionalPropertiesText;
}

/// <summary>
/// Gets TypeScript interface property definition source code
/// </summary>
Expand Down Expand Up @@ -772,8 +800,9 @@ private string GetEnumMembersText(Type type, bool asUnionType)
/// </summary>
/// <param name="type"></param>
/// <param name="outputDir"></param>
/// <param name="typeSpec"></param>
/// <returns>Generated TypeScript file paths (relative to the Options.BaseOutputDirectory)</returns>
private IEnumerable<string> GenerateTypeDependencies(Type type, string outputDir)
private IEnumerable<string> GenerateTypeDependencies(Type type, string outputDir, TypeSpec typeSpec)
{
var generatedFiles = new List<string>();
var typeDependencies = _typeDependencyService.GetTypeDependencies(type);
Expand All @@ -793,7 +822,7 @@ private IEnumerable<string> GenerateTypeDependencies(Type type, string outputDir

try
{
generatedFiles.AddRange(GenerateNotMarkedType(typeDependency, defaultOutputDir));
generatedFiles.AddRange(GenerateNotMarkedType(typeDependency, defaultOutputDir, typeSpec));
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ internal interface ITemplateService
string FillClassTemplate(string imports, string name, string extends, string implements, string properties, string tsDoc, string customHead, string customBody, string fileHeading = null);
string FillClassDefaultExportTemplate(string imports, string name, string exportName, string extends, string implements, string properties, string tsDoc, string customHead, string customBody, string fileHeading = null);
string FillClassPropertyTemplate(string modifiers, string name, string type, IEnumerable<string> typeUnions, bool isOptional, string tsDoc, string defaultValue = null);
string FillClassPropertyTemplate(string name, string type, string defaultValue = null);
string FillInterfaceTemplate(string imports, string name, string extends, string properties, string tsDoc, string customHead, string customBody, string fileHeading = null);
string FillInterfaceDefaultExportTemplate(string imports, string name, string exportName, string extends, string properties, string tsDoc, string customHead, string customBody, string fileHeading = null);
string FillInterfacePropertyTemplate(string modifiers, string name, string type, IEnumerable<string> typeUnions, bool isOptional, string tsDoc);
Expand All @@ -17,6 +18,7 @@ internal interface ITemplateService
string FillImportTemplate(string name, string typeAlias, string path, bool useImportType);
string FillImportDefaultExportTemplate(string name, string path, bool useImportType);
string FillIndexTemplate(string exports);
string FillWithSingleLineComment(string comment);
string FillIndexExportTemplate(string filename);
string GetExtendsText(string name);
string GetExtendsText(IEnumerable<string> names);
Expand Down
28 changes: 28 additions & 0 deletions src/TypeGen/TypeGen.Core/Generator/Services/TemplateService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using TypeGen.Core.Storage;
using TypeGen.Core.Utils;

Expand Down Expand Up @@ -33,6 +35,8 @@ internal class TemplateService : ITemplateService
private readonly string _indexTemplate;
private readonly string _indexExportTemplate;
private readonly string _headingTemplate;
private readonly string _singleLineCommentTemplate;
private readonly string _lineBreakTemplate;

private GeneratorOptions GeneratorOptions => _generatorOptionsProvider.GeneratorOptions;

Expand All @@ -58,6 +62,8 @@ public TemplateService(IInternalStorage internalStorage, IGeneratorOptionsProvid
_indexTemplate = _internalStorage.GetEmbeddedResource("TypeGen.Core.Templates.Index.tpl");
_indexExportTemplate = _internalStorage.GetEmbeddedResource("TypeGen.Core.Templates.IndexExport.tpl");
_headingTemplate = _internalStorage.GetEmbeddedResource("TypeGen.Core.Templates.Heading.tpl");
_singleLineCommentTemplate = _internalStorage.GetEmbeddedResource("TypeGen.Core.Templates.SingleLineComment.tpl");
_lineBreakTemplate = _internalStorage.GetEmbeddedResource("TypeGen.Core.Templates.LineBreak.tpl");
}

public string FillClassTemplate(string imports, string name, string extends, string implements, string properties,
Expand Down Expand Up @@ -111,6 +117,20 @@ public string FillClassPropertyTemplate(string modifiers, string name, string ty
.Replace(GetTag("defaultValue"), defaultValue);
}

public string FillClassPropertyTemplate(string name, string type, string defaultValue = null)
{
type = $": {type}";

defaultValue = string.IsNullOrWhiteSpace(defaultValue) ? "" : $" = {defaultValue}";

return ReplaceSpecialChars(_classPropertyTemplate)
.Replace(GetTag("modifiers"), "")
.Replace(GetTag("name"), name)
.Replace(GetTag("type"), type)
.Replace(GetTag("tsDoc"), "")
.Replace(GetTag("defaultValue"), defaultValue);
}

public string FillInterfaceTemplate(string imports, string name, string extends, string properties, string tsDoc,
string customHead,string customBody, string fileHeading = null)
{
Expand Down Expand Up @@ -242,6 +262,14 @@ public string FillIndexExportTemplate(string filename)

public string GetImplementsText(IEnumerable<string> names) => $" implements {string.Join(", ", names)}";

public string FillWithSingleLineComment(string comment)
{
return
ReplaceSpecialChars(_lineBreakTemplate) +
ReplaceSpecialChars(_singleLineCommentTemplate)
.Replace(GetTag("comment"), comment);
}

private static string GetTag(string tagName) => $"$tg{{{tagName}}}";

private string ReplaceSpecialChars(string template)
Expand Down
Loading