diff --git a/nuget-dotnetcli/dotnet-typegen.nuspec b/nuget-dotnetcli/dotnet-typegen.nuspec index 27d58977..cb1feb7e 100644 --- a/nuget-dotnetcli/dotnet-typegen.nuspec +++ b/nuget-dotnetcli/dotnet-typegen.nuspec @@ -2,7 +2,7 @@ dotnet-typegen - 5.0.0 + 5.0.1 Jacek Burzynski Jacek Burzynski LICENSE diff --git a/nuget/TypeGen.nuspec b/nuget/TypeGen.nuspec index 235048a9..d6fe7c08 100644 --- a/nuget/TypeGen.nuspec +++ b/nuget/TypeGen.nuspec @@ -2,7 +2,7 @@ TypeGen - 5.0.0 + 5.0.1 Jacek Burzynski Jacek Burzynski LICENSE diff --git a/src/TypeGen/TypeGen.Cli/ApplicationConfig.cs b/src/TypeGen/TypeGen.Cli/ApplicationConfig.cs index 3f411074..3399433e 100644 --- a/src/TypeGen/TypeGen.Cli/ApplicationConfig.cs +++ b/src/TypeGen/TypeGen.Cli/ApplicationConfig.cs @@ -2,5 +2,5 @@ namespace TypeGen.Cli; internal class ApplicationConfig { - public const string Version = "5.0.0"; + public const string Version = "5.0.1"; } diff --git a/src/TypeGen/TypeGen.Cli/TypeGen.Cli.csproj b/src/TypeGen/TypeGen.Cli/TypeGen.Cli.csproj index 85b97bff..39013f9c 100644 --- a/src/TypeGen/TypeGen.Cli/TypeGen.Cli.csproj +++ b/src/TypeGen/TypeGen.Cli/TypeGen.Cli.csproj @@ -2,9 +2,9 @@ Exe net8.0 - 5.0.0.0 - 5.0.0.0 - 5.0.0 + 5.0.0.1 + 5.0.0.1 + 5.0.1 TypeGen diff --git a/src/TypeGen/TypeGen.Core/Generator/Generator.cs b/src/TypeGen/TypeGen.Core/Generator/Generator.cs index 35b56a69..9504f445 100644 --- a/src/TypeGen/TypeGen.Core/Generator/Generator.cs +++ b/src/TypeGen/TypeGen.Core/Generator/Generator.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -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; @@ -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), @@ -140,6 +140,7 @@ public IEnumerable Generate(IEnumerable generationSpecs) Requires.NotNullOrEmpty(generationSpecs, nameof(generationSpecs)); generationSpecs = generationSpecs.ToList(); + var files = new List(); _generationContext = new GenerationContext(_fileSystem); @@ -153,7 +154,7 @@ public IEnumerable Generate(IEnumerable generationSpecs) _metadataReaderFactory.GenerationSpec = generationSpec; foreach (KeyValuePair kvp in generationSpec.TypeSpecs) - files.AddRange(GenerateMarkedType(kvp.Key)); + files.AddRange(GenerateMarkedType(kvp.Key, kvp.Value)); } files = files.Distinct().ToList(); @@ -326,7 +327,7 @@ private IEnumerable GenerateIndexFile(IEnumerable generatedFiles return new[] { filename }; } - private IEnumerable GenerateMarkedType(Type type) + private IEnumerable GenerateMarkedType(Type type, TypeSpec typeSpec) { if (Options.IsTypeBlacklisted(type)) return Enumerable.Empty(); @@ -334,7 +335,7 @@ private IEnumerable GenerateMarkedType(Type type) _generationContext.BeginTypeGeneration(type); _generationContext.AddGeneratedType(type); - ExecuteWithTypeContextLogging(() => { files = GenerateType(type); }); + ExecuteWithTypeContextLogging(() => { files = GenerateType(type, typeSpec); }); _generationContext.EndTypeGeneration(); return files.Distinct(); @@ -346,7 +347,7 @@ private IEnumerable GenerateMarkedType(Type type) /// /// /// Generated TypeScript file paths (relative to the Options.BaseOutputDirectory) - private IEnumerable GenerateType(Type type) + private IEnumerable GenerateType(Type type, TypeSpec typeSpec) { var classAttribute = _metadataReaderFactory.GetInstance().GetAttribute(type); var interfaceAttribute = _metadataReaderFactory.GetInstance().GetAttribute(type); @@ -354,12 +355,12 @@ private IEnumerable GenerateType(Type 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) @@ -367,16 +368,17 @@ private IEnumerable GenerateType(Type type) return GenerateEnum(type, enumAttribute); } - return GenerateNotMarkedType(type, Options.BaseOutputDirectory); + return GenerateNotMarkedType(type, Options.BaseOutputDirectory, typeSpec); } - + /// /// Generates TypeScript files for types that are not marked with an ExportTs... attribute /// /// /// + /// /// Generated TypeScript file paths (relative to the Options.BaseOutputDirectory) - private IEnumerable GenerateNotMarkedType(Type type, string outputDirectory) + private IEnumerable GenerateNotMarkedType(Type type, string outputDirectory, TypeSpec typeSpec) { if (Options.IsTypeBlacklisted(type)) return Enumerable.Empty(); @@ -384,12 +386,12 @@ private IEnumerable GenerateNotMarkedType(Type type, string outputDirect 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 }); @@ -402,11 +404,12 @@ private IEnumerable GenerateNotMarkedType(Type type, string outputDirect /// /// /// + /// /// Generated TypeScript file paths (relative to the Options.BaseOutputDirectory) - private IEnumerable GenerateClass(Type type, ExportTsClassAttribute classAttribute) + private IEnumerable GenerateClass(Type type, ExportTsClassAttribute classAttribute, TypeSpec typeSpec) { string outputDir = classAttribute.OutputDir; - IEnumerable dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir); + IEnumerable dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir, typeSpec); // get text for sections @@ -428,7 +431,7 @@ private IEnumerable 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 @@ -458,11 +461,12 @@ private IEnumerable GenerateClass(Type type, ExportTsClassAttribute clas /// /// /// + /// /// Generated TypeScript file paths (relative to the Options.BaseOutputDirectory) - private IEnumerable GenerateInterface(Type type, ExportTsInterfaceAttribute interfaceAttribute) + private IEnumerable GenerateInterface(Type type, ExportTsInterfaceAttribute interfaceAttribute, TypeSpec typeSpec) { string outputDir = interfaceAttribute.OutputDir; - IEnumerable dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir); + IEnumerable dependenciesGenerationResult = GenerateTypeDependencies(type, outputDir, typeSpec); // get text for sections @@ -648,20 +652,44 @@ private void LogClassPropertyWarnings(MemberInfo memberInfo) /// Gets TypeScript class properties definition source code /// /// + /// /// - private string GetClassPropertiesText(Type type) + private string GetClassPropertiesText(Type type, IEnumerable additionalProperties) { var propertiesText = ""; IEnumerable 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); } + /// + /// Gets TypeScript class additional properties if defined + /// + /// + /// + private string GetAdditionalPropertiesText(IEnumerable 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; + } + /// /// Gets TypeScript interface property definition source code /// @@ -772,8 +800,9 @@ private string GetEnumMembersText(Type type, bool asUnionType) /// /// /// + /// /// Generated TypeScript file paths (relative to the Options.BaseOutputDirectory) - private IEnumerable GenerateTypeDependencies(Type type, string outputDir) + private IEnumerable GenerateTypeDependencies(Type type, string outputDir, TypeSpec typeSpec) { var generatedFiles = new List(); var typeDependencies = _typeDependencyService.GetTypeDependencies(type); @@ -793,7 +822,7 @@ private IEnumerable GenerateTypeDependencies(Type type, string outputDir try { - generatedFiles.AddRange(GenerateNotMarkedType(typeDependency, defaultOutputDir)); + generatedFiles.AddRange(GenerateNotMarkedType(typeDependency, defaultOutputDir, typeSpec)); } catch (Exception ex) { diff --git a/src/TypeGen/TypeGen.Core/Generator/Services/ITemplateService.cs b/src/TypeGen/TypeGen.Core/Generator/Services/ITemplateService.cs index d196ffd1..fd35f38e 100644 --- a/src/TypeGen/TypeGen.Core/Generator/Services/ITemplateService.cs +++ b/src/TypeGen/TypeGen.Core/Generator/Services/ITemplateService.cs @@ -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 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 typeUnions, bool isOptional, string tsDoc); @@ -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 names); diff --git a/src/TypeGen/TypeGen.Core/Generator/Services/TemplateService.cs b/src/TypeGen/TypeGen.Core/Generator/Services/TemplateService.cs index 3ca1759e..568c86e9 100644 --- a/src/TypeGen/TypeGen.Core/Generator/Services/TemplateService.cs +++ b/src/TypeGen/TypeGen.Core/Generator/Services/TemplateService.cs @@ -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; @@ -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; @@ -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, @@ -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) { @@ -242,6 +262,14 @@ public string FillIndexExportTemplate(string filename) public string GetImplementsText(IEnumerable 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) diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs index 15d9866d..d02a51fb 100644 --- a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs @@ -4,6 +4,7 @@ namespace TypeGen.Core.SpecGeneration.Builders { + /// public abstract class ClassSpecBuilderBase : SpecBuilderBase, ICustomBaseTrait, ICustomHeaderTrait, @@ -24,7 +25,8 @@ public abstract class ClassSpecBuilderBase : SpecBuilderBase, IStaticTrait, ITypeTrait, ITypeUnionsTrait, - IUndefinedTrait + IUndefinedTrait, + IAdditionalPropertiesTrait where TSelf : SpecBuilderBase { private readonly CustomBaseTrait _customBaseTrait; @@ -47,7 +49,8 @@ public abstract class ClassSpecBuilderBase : SpecBuilderBase, private readonly TypeTrait _typeTrait; private readonly TypeUnionsTrait _typeUnionsTrait; private readonly UndefinedTrait _undefinedTrait; - + private readonly AdditionalPropertiesTrait _additionalPropertiesTrait; + internal ClassSpecBuilderBase(TypeSpec typeSpec) : base(typeSpec) { MemberTrait = new MemberTrait(this as TSelf, typeSpec); @@ -70,13 +73,14 @@ internal ClassSpecBuilderBase(TypeSpec typeSpec) : base(typeSpec) _typeTrait = new TypeTrait(this as TSelf, typeSpec, MemberTrait); _typeUnionsTrait = new TypeUnionsTrait(this as TSelf, typeSpec, MemberTrait); _undefinedTrait = new UndefinedTrait(this as TSelf, typeSpec, MemberTrait); + _additionalPropertiesTrait = new AdditionalPropertiesTrait(this as TSelf, typeSpec); } /// public TSelf CustomBase(string @base = null, string importPath = null, string originalTypeName = null, bool isDefaultExport = false, IEnumerable implementedInterfaces = null) => _customBaseTrait.CustomBase(@base, importPath, originalTypeName, isDefaultExport, implementedInterfaces); - + /// public TSelf CustomBase(string @base = null, string importPath = null, string originalTypeName = null, bool isDefaultExport = false, params ImplementedInterface[] implementedInterfaces) @@ -92,43 +96,43 @@ public TSelf CustomHeader(string header) /// public TSelf DefaultExport(bool enabled = true) => _defaultExportTrait.DefaultExport(enabled); - + /// public TSelf DefaultTypeOutput(string outputDir) => _defaultTypeOutputTrait.DefaultTypeOutput(outputDir); - + /// public TSelf DefaultValue(string defaultValue) => _defaultValueTrait.DefaultValue(defaultValue); - + /// public TSelf IgnoreBase() => _ignoreBaseTrait.IgnoreBase(); - + /// public TSelf Ignore() => _ignoreTrait.Ignore(); - + /// public TSelf MemberName(string name) => _memberNameTrait.MemberName(name); - + /// public TSelf Member(string memberName) => MemberTrait.Member(memberName); /// public TSelf NotNull() => _notNullTrait.NotNull(); - + /// public TSelf NotReadonly() => _notReadonlyTrait.NotReadonly(); - + /// public TSelf NotStatic() => _notStaticTrait.NotStatic(); /// public TSelf NotUndefined() => _notUndefinedTrait.NotUndefined(); - + /// public TSelf Null() => _nullTrait.Null(); - + /// public TSelf Readonly() => _readonlyTrait.Readonly(); - + /// public TSelf Static() => _staticTrait.Static(); @@ -138,7 +142,7 @@ public TSelf Type(string typeName, string importPath = null, string originalType /// public TSelf Type(TsType tsType) => _typeTrait.Type(tsType); - + /// public TSelf TypeUnions(IEnumerable typeUnions) => _typeUnionsTrait.TypeUnions(typeUnions); @@ -147,5 +151,18 @@ public TSelf Type(string typeName, string importPath = null, string originalType /// public TSelf Undefined() => _undefinedTrait.Undefined(); + + /// + /// Adds an additional property to the TypeScript class being generated. + /// The 'name' parameter can include access modifiers and the 'readonly' keyword, + /// allowing for flexible property definitions. For instance, you can define the + /// property as 'public name', 'private name', 'readonly name', etc. + /// + /// The name of the property, which can include access modifiers and keywords. + /// The TypeScript type of the property. + /// An optional default value for the property. If provided, it initializes the property with this value. + /// The instance of the spec builder for method chaining. + public TSelf WithAdditionalProperty(string name, string type, string defaultValue = null) => + _additionalPropertiesTrait.WithAdditionalProperty(name, type, defaultValue); } } \ No newline at end of file diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/AdditionalClassProperty.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/AdditionalClassProperty.cs new file mode 100644 index 00000000..ceddb4a3 --- /dev/null +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/AdditionalClassProperty.cs @@ -0,0 +1,8 @@ +namespace TypeGen.Core.SpecGeneration.Builders.Traits; + +public class AdditionalClassProperty +{ + public string Name { get; set; } + public string Type { get; set; } + public string? DefaultValue { get; set; } +} diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/AdditionalPropertiesTrait.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/AdditionalPropertiesTrait.cs new file mode 100644 index 00000000..b78906a1 --- /dev/null +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/AdditionalPropertiesTrait.cs @@ -0,0 +1,19 @@ +namespace TypeGen.Core.SpecGeneration.Builders.Traits; + +internal class AdditionalPropertiesTrait : IAdditionalPropertiesTrait +{ + private readonly TSpecBuilder _this; + private readonly TypeSpec _typeSpec; + + public AdditionalPropertiesTrait(TSpecBuilder @this, TypeSpec typeSpec) + { + _this = @this; + _typeSpec = typeSpec; + } + + public TSpecBuilder WithAdditionalProperty(string name, string type, string? defaultValue = null) + { + _typeSpec.AddAdditionalClassProperty(name, type, defaultValue); + return _this; + } +} \ No newline at end of file diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/IAdditionalPropertiesTrait.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/IAdditionalPropertiesTrait.cs new file mode 100644 index 00000000..b4c29ded --- /dev/null +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/IAdditionalPropertiesTrait.cs @@ -0,0 +1,13 @@ +namespace TypeGen.Core.SpecGeneration.Builders.Traits; + +internal interface IAdditionalPropertiesTrait +{ + /// + /// Adds an additional property to the TypeScript class. + /// + /// The name of the property. + /// The TypeScript type of the property. + /// The TypeScript default value of the property. + /// The current instance of . + TSpecBuilder WithAdditionalProperty(string name, string type, string? defaultValue = null); +} diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs index 89d131c6..692f611b 100644 --- a/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs @@ -1,57 +1,72 @@ using System; using System.Collections.Generic; +using TypeGen.Core.SpecGeneration.Builders.Traits; using TypeGen.Core.TypeAnnotations; -namespace TypeGen.Core.SpecGeneration +namespace TypeGen.Core.SpecGeneration; + +internal class TypeSpec { - internal class TypeSpec + private readonly List _additionalAttributes; + private readonly Dictionary> _memberAttributes; + private readonly List _additionalClassProperties = new List(); + + public ExportAttribute ExportAttribute { get; } + + public IList AdditionalAttributes => _additionalAttributes; + + public IDictionary> MemberAttributes => _memberAttributes; + + public IEnumerable AdditionalClassProperties => _additionalClassProperties; + + public TypeSpec(ExportAttribute exportAttribute) { - private readonly List _additionalAttributes; - private readonly Dictionary> _memberAttributes; + ExportAttribute = exportAttribute; + _memberAttributes = new Dictionary>(); + _additionalAttributes = new List(); + } - public ExportAttribute ExportAttribute { get; } + public void AddMember(string memberName) => _memberAttributes[memberName] = new List(); - public IList AdditionalAttributes => _additionalAttributes; + public void AddCustomBaseAttribute(string @base = null, string importPath = null, string originalTypeName = null, bool isDefaultExport = false, + params object[] implementedInterfaces) + => AddAdditionalAttribute(new TsCustomBaseAttribute(@base, importPath, originalTypeName, isDefaultExport, implementedInterfaces)); + public void AddDefaultExportAttribute(bool enabled = true) => AddAdditionalAttribute(new TsDefaultExportAttribute(enabled)); + public void AddDefaultTypeOutputAttribute(string memberName, string outputDir) => AddMemberAttribute(memberName, new TsDefaultTypeOutputAttribute(outputDir)); + public void AddDefaultValueAttribute(string memberName, string defaultValue) => AddMemberAttribute(memberName, new TsDefaultValueAttribute(defaultValue)); + public void AddIgnoreAttribute(string memberName) => AddMemberAttribute(memberName, new TsIgnoreAttribute()); + public void AddIgnoreBaseAttribute() => AddAdditionalAttribute(new TsIgnoreBaseAttribute()); + public void SetCustomHeader(string header) { ExportAttribute.CustomHeader = header; } + public void SetCustomBody(string body) { ExportAttribute.CustomBody = body; } + public void AddMemberNameAttribute(string memberName, string name) => AddMemberAttribute(memberName, new TsMemberNameAttribute(name)); + public void AddNotNullAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotNullAttribute()); + public void AddNotReadonlyAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotReadonlyAttribute()); + public void AddNotStaticAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotStaticAttribute()); + public void AddNotUndefinedAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotUndefinedAttribute()); + public void AddNullAttribute(string memberName) => AddMemberAttribute(memberName, new TsNullAttribute()); + public void AddOptionalAttribute(string memberName) => AddMemberAttribute(memberName, new TsOptionalAttribute()); + public void AddReadonlyAttribute(string memberName) => AddMemberAttribute(memberName, new TsReadonlyAttribute()); + public void AddStaticAttribute(string memberName) => AddMemberAttribute(memberName, new TsStaticAttribute()); + public void AddStringInitializersAttribute(bool enabled = true) => AddAdditionalAttribute(new TsStringInitializersAttribute(enabled)); + public void AddTypeAttribute(string memberName, TsType tsType) => AddMemberAttribute(memberName, new TsTypeAttribute(tsType)); + public void AddTypeAttribute(string memberName, string typeName, string importPath = null, string originalTypeName = null, bool isDefaultExport = false) + => AddMemberAttribute(memberName, new TsTypeAttribute(typeName, importPath, originalTypeName, isDefaultExport)); + public void AddTypeUnionsAttribute(string memberName, IEnumerable typeUnions) => AddMemberAttribute(memberName, new TsTypeUnionsAttribute(typeUnions)); + public void AddTypeUnionsAttribute(string memberName, params string[] typeUnions) => AddMemberAttribute(memberName, new TsTypeUnionsAttribute(typeUnions)); + public void AddUndefinedAttribute(string memberName) => AddMemberAttribute(memberName, new TsUndefinedAttribute()); - public IDictionary> MemberAttributes => _memberAttributes; + private void AddMemberAttribute(string memberName, Attribute attribute) => MemberAttributes[memberName].Add(attribute); + private void AddAdditionalAttribute(Attribute attribute) => _additionalAttributes.Add(attribute); - public TypeSpec(ExportAttribute exportAttribute) + public void AddAdditionalClassProperty(string name, string type, string? defaultValue) + { + _additionalClassProperties.Add(new AdditionalClassProperty { - ExportAttribute = exportAttribute; - _memberAttributes = new Dictionary>(); - _additionalAttributes = new List(); - } - - public void AddMember(string memberName) => _memberAttributes[memberName] = new List(); - - public void AddCustomBaseAttribute(string @base = null, string importPath = null, string originalTypeName = null, bool isDefaultExport = false, - params object[] implementedInterfaces) - => AddAdditionalAttribute(new TsCustomBaseAttribute(@base, importPath, originalTypeName, isDefaultExport, implementedInterfaces)); - public void AddDefaultExportAttribute(bool enabled = true) => AddAdditionalAttribute(new TsDefaultExportAttribute(enabled)); - public void AddDefaultTypeOutputAttribute(string memberName, string outputDir) => AddMemberAttribute(memberName, new TsDefaultTypeOutputAttribute(outputDir)); - public void AddDefaultValueAttribute(string memberName, string defaultValue) => AddMemberAttribute(memberName, new TsDefaultValueAttribute(defaultValue)); - public void AddIgnoreAttribute(string memberName) => AddMemberAttribute(memberName, new TsIgnoreAttribute()); - public void AddIgnoreBaseAttribute() => AddAdditionalAttribute(new TsIgnoreBaseAttribute()); - public void SetCustomHeader(string header) { ExportAttribute.CustomHeader = header; } - public void SetCustomBody(string body) { ExportAttribute.CustomBody = body; } - public void AddMemberNameAttribute(string memberName, string name) => AddMemberAttribute(memberName, new TsMemberNameAttribute(name)); - public void AddNotNullAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotNullAttribute()); - public void AddNotReadonlyAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotReadonlyAttribute()); - public void AddNotStaticAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotStaticAttribute()); - public void AddNotUndefinedAttribute(string memberName) => AddMemberAttribute(memberName, new TsNotUndefinedAttribute()); - public void AddNullAttribute(string memberName) => AddMemberAttribute(memberName, new TsNullAttribute()); - public void AddOptionalAttribute(string memberName) => AddMemberAttribute(memberName, new TsOptionalAttribute()); - public void AddReadonlyAttribute(string memberName) => AddMemberAttribute(memberName, new TsReadonlyAttribute()); - public void AddStaticAttribute(string memberName) => AddMemberAttribute(memberName, new TsStaticAttribute()); - public void AddStringInitializersAttribute(bool enabled = true) => AddAdditionalAttribute(new TsStringInitializersAttribute(enabled)); - public void AddTypeAttribute(string memberName, TsType tsType) => AddMemberAttribute(memberName, new TsTypeAttribute(tsType)); - public void AddTypeAttribute(string memberName, string typeName, string importPath = null, string originalTypeName = null, bool isDefaultExport = false) - => AddMemberAttribute(memberName, new TsTypeAttribute(typeName, importPath, originalTypeName, isDefaultExport)); - public void AddTypeUnionsAttribute(string memberName, IEnumerable typeUnions) => AddMemberAttribute(memberName, new TsTypeUnionsAttribute(typeUnions)); - public void AddTypeUnionsAttribute(string memberName, params string[] typeUnions) => AddMemberAttribute(memberName, new TsTypeUnionsAttribute(typeUnions)); - public void AddUndefinedAttribute(string memberName) => AddMemberAttribute(memberName, new TsUndefinedAttribute()); - - private void AddMemberAttribute(string memberName, Attribute attribute) => MemberAttributes[memberName].Add(attribute); - private void AddAdditionalAttribute(Attribute attribute) => _additionalAttributes.Add(attribute); + Name = name, + Type = type, + DefaultValue = defaultValue, + }); } + + } diff --git a/src/TypeGen/TypeGen.Core/Templates/LineBreak.tpl b/src/TypeGen/TypeGen.Core/Templates/LineBreak.tpl new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/TypeGen/TypeGen.Core/Templates/LineBreak.tpl @@ -0,0 +1 @@ + diff --git a/src/TypeGen/TypeGen.Core/Templates/SingleLineComment.tpl b/src/TypeGen/TypeGen.Core/Templates/SingleLineComment.tpl new file mode 100644 index 00000000..76b6214a --- /dev/null +++ b/src/TypeGen/TypeGen.Core/Templates/SingleLineComment.tpl @@ -0,0 +1 @@ +$tg{tab}// $tg{comment} diff --git a/src/TypeGen/TypeGen.Core/TypeGen.Core.csproj b/src/TypeGen/TypeGen.Core/TypeGen.Core.csproj index ea861bd7..cc79f81c 100644 --- a/src/TypeGen/TypeGen.Core/TypeGen.Core.csproj +++ b/src/TypeGen/TypeGen.Core/TypeGen.Core.csproj @@ -3,8 +3,7 @@ netstandard2.0;net8.0 TypeGen.Core.xml latest - 5.0.0.0 - 5.0.0.0 + 5.0.0.1 @@ -21,11 +20,15 @@ + + + + diff --git a/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/AdditionalClassPropertiesTest.cs b/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/AdditionalClassPropertiesTest.cs new file mode 100644 index 00000000..3a43f8b3 --- /dev/null +++ b/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/AdditionalClassPropertiesTest.cs @@ -0,0 +1,38 @@ +using System.Threading.Tasks; +using TypeGen.Core.Generator; +using TypeGen.Core.SpecGeneration; +using TypeGen.FileContentTest.AdditionalClassProperties.Entities; +using TypeGen.FileContentTest.TestingUtils; +using Xunit; + +namespace TypeGen.FileContentTest.AdditionalClassProperties +{ + public class AdditionalClassPropertiesTest : GenerationTestBase + { + [Fact] + public async Task ClassWithAdditionalClassProperties_Test() + { + var type = typeof(ClassWithAdditionalClassProperties); + const string expectedLocation = "TypeGen.FileContentTest.AdditionalProperties.Expected.class-with-additional-class-properties.ts"; + var generationSpec = new ClassWithAdditionalPropertiesGenerationSpec(); + var generatorOptions = new GeneratorOptions { }; + + await TestGenerationSpec(type, expectedLocation, generationSpec, generatorOptions); + } + + private class ClassWithAdditionalPropertiesGenerationSpec : GenerationSpec + { + public ClassWithAdditionalPropertiesGenerationSpec() + { + AddClass() + .WithAdditionalProperty("public email", "string") + .WithAdditionalProperty("greetingMessage", "string", "'Hello, World!'") + .WithAdditionalProperty("emptyString", "string", "''") + .WithAdditionalProperty("creationDate", "Date") + .WithAdditionalProperty("username", "string") + .WithAdditionalProperty("age", "number") + .WithAdditionalProperty("status", "'active' | 'inactive' | 'pending'"); + } + } + } +} diff --git a/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/Entities/ClassWithAdditionalClassProperties.cs b/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/Entities/ClassWithAdditionalClassProperties.cs new file mode 100644 index 00000000..f548d754 --- /dev/null +++ b/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/Entities/ClassWithAdditionalClassProperties.cs @@ -0,0 +1,8 @@ +using System; + +namespace TypeGen.FileContentTest.AdditionalClassProperties.Entities; + +public class ClassWithAdditionalClassProperties +{ + public string name; +} \ No newline at end of file diff --git a/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/Expected/class-with-additional-class-properties.ts b/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/Expected/class-with-additional-class-properties.ts new file mode 100644 index 00000000..7909b555 --- /dev/null +++ b/src/TypeGen/TypeGen.FileContentTest/AdditionalProperties/Expected/class-with-additional-class-properties.ts @@ -0,0 +1,17 @@ +/** + * This is a TypeGen auto-generated file. + * Any changes made to this file can be lost when this file is regenerated. + */ + +export class ClassWithAdditionalClassProperties { + name: string; + + // Additional properties + public email: string; + greetingMessage: string = 'Hello, World!'; + emptyString: string = ''; + creationDate: Date; + username: string; + age: number; + status: 'active' | 'inactive' | 'pending'; +} diff --git a/src/TypeGen/TypeGen.FileContentTest/TypeGen.FileContentTest.csproj b/src/TypeGen/TypeGen.FileContentTest/TypeGen.FileContentTest.csproj index 1e4409ea..dba7ec9b 100644 --- a/src/TypeGen/TypeGen.FileContentTest/TypeGen.FileContentTest.csproj +++ b/src/TypeGen/TypeGen.FileContentTest/TypeGen.FileContentTest.csproj @@ -17,6 +17,7 @@ + @@ -32,6 +33,7 @@ +