Skip to content

Commit

Permalink
Added Addtional properties feature.
Browse files Browse the repository at this point in the history
u
  • Loading branch information
mohammed belhaj committed Nov 18, 2023
1 parent 7f353d5 commit 9d81273
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 84 deletions.
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

0 comments on commit 9d81273

Please sign in to comment.