From dbd41722587a8678f5a10e71f9a235b011654b35 Mon Sep 17 00:00:00 2001 From: "Spencer G. Jones" Date: Fri, 18 Aug 2023 09:15:45 -0600 Subject: [PATCH] Allow specifying custom header and body as an attribute or spec --- .../SpecGeneration/ClassSpecBuilderTest.cs | 28 ++++++++++++++++++- .../Generic/InterfaceSpecBuilderTest.cs | 28 ++++++++++++++++++- .../TypeGen.Core/Generator/Generator.cs | 16 ++++++++--- .../Builders/ClassSpecBuilderBase.cs | 16 ++++++++++- .../Builders/InterfaceSpecBuilderBase.cs | 16 ++++++++++- .../Builders/Traits/CustomBodyTrait.cs | 21 ++++++++++++++ .../Builders/Traits/CustomHeaderTrait.cs | 21 ++++++++++++++ .../Builders/Traits/ICustomBodyTrait.cs | 10 +++++++ .../Builders/Traits/ICustomHeaderTrait.cs | 10 +++++++ .../TypeGen.Core/SpecGeneration/TypeSpec.cs | 8 ++++-- .../TypeAnnotations/ExportAttribute.cs | 22 ++++++++++++++- 11 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomBodyTrait.cs create mode 100644 src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomHeaderTrait.cs create mode 100644 src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomBodyTrait.cs create mode 100644 src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomHeaderTrait.cs diff --git a/src/TypeGen/TypeGen.Core.Test/SpecGeneration/ClassSpecBuilderTest.cs b/src/TypeGen/TypeGen.Core.Test/SpecGeneration/ClassSpecBuilderTest.cs index 9b4ce06d..367d9ba1 100644 --- a/src/TypeGen/TypeGen.Core.Test/SpecGeneration/ClassSpecBuilderTest.cs +++ b/src/TypeGen/TypeGen.Core.Test/SpecGeneration/ClassSpecBuilderTest.cs @@ -57,6 +57,32 @@ public void CustomBase_Invoked_SpecUpdated() Assert.Equal(isDefaultExport, ((TsCustomBaseAttribute)attribute).IsDefaultExport); } + [Fact] + public void CustomHeader_Invoked_SpecUpdated() + { + const string header = "header"; + var spec = new TypeSpec(new ExportTsInterfaceAttribute()); + var builder = new ClassSpecBuilder(spec); + + builder.CustomHeader(header); + + var attribute = spec.ExportAttribute; + Assert.Equal(header, attribute.CustomHeader); + } + + [Fact] + public void CustomBody_Invoked_SpecUpdated() + { + const string body = "body"; + var spec = new TypeSpec(new ExportTsInterfaceAttribute()); + var builder = new ClassSpecBuilder(spec); + + builder.CustomBody(body); + + var attribute = spec.ExportAttribute; + Assert.Equal(body, attribute.CustomBody); + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -256,4 +282,4 @@ public void Undefined_Invoked_SpecUpdated() Assert.IsType(attribute); } } -} \ No newline at end of file +} diff --git a/src/TypeGen/TypeGen.Core.Test/SpecGeneration/Generic/InterfaceSpecBuilderTest.cs b/src/TypeGen/TypeGen.Core.Test/SpecGeneration/Generic/InterfaceSpecBuilderTest.cs index 9f53e440..b7bd798a 100644 --- a/src/TypeGen/TypeGen.Core.Test/SpecGeneration/Generic/InterfaceSpecBuilderTest.cs +++ b/src/TypeGen/TypeGen.Core.Test/SpecGeneration/Generic/InterfaceSpecBuilderTest.cs @@ -85,6 +85,32 @@ public void CustomBase_Invoked_SpecUpdated() Assert.Equal(isDefaultExport, ((TsCustomBaseAttribute)attribute).IsDefaultExport); } + [Fact] + public void CustomHeader_Invoked_SpecUpdated() + { + const string header = "header"; + var spec = new TypeSpec(new ExportTsInterfaceAttribute()); + var builder = new TypeGen.Core.SpecGeneration.Builders.Generic.InterfaceSpecBuilder(spec); + + builder.CustomHeader(header); + + var attribute = spec.ExportAttribute; + Assert.Equal(header, attribute.CustomHeader); + } + + [Fact] + public void CustomBody_Invoked_SpecUpdated() + { + const string body = "body"; + var spec = new TypeSpec(new ExportTsInterfaceAttribute()); + var builder = new TypeGen.Core.SpecGeneration.Builders.Generic.InterfaceSpecBuilder(spec); + + builder.CustomBody(body); + + var attribute = spec.ExportAttribute; + Assert.Equal(body, attribute.CustomBody); + } + [Theory] [InlineData(true)] [InlineData(false)] @@ -271,4 +297,4 @@ public void Undefined_Invoked_SpecUpdated() Assert.IsType(attribute); } } -} \ No newline at end of file +} diff --git a/src/TypeGen/TypeGen.Core/Generator/Generator.cs b/src/TypeGen/TypeGen.Core/Generator/Generator.cs index f4a37242..7c3e6fc3 100644 --- a/src/TypeGen/TypeGen.Core/Generator/Generator.cs +++ b/src/TypeGen/TypeGen.Core/Generator/Generator.cs @@ -409,8 +409,12 @@ private IEnumerable GenerateClass(Type type, ExportTsClassAttribute clas string tsTypeNameFirstPart = tsTypeName.RemoveTypeGenericComponent(); string filePath = GetFilePath(type, outputDir); string filePathRelative = GetRelativeFilePath(type, outputDir); - string customHead = _tsContentGenerator.GetCustomHead(filePath); - string customBody = _tsContentGenerator.GetCustomBody(filePath, Options.TabLength); + string customInFileHead = _tsContentGenerator.GetCustomHead(filePath); + string customAttributeHead = classAttribute.CustomHeader; + string customHead = string.Join(Environment.NewLine, new[] { customInFileHead, customAttributeHead }.Where(i => !string.IsNullOrWhiteSpace(i))); + string customInFileBody = _tsContentGenerator.GetCustomBody(filePath, Options.TabLength); + string customAttributeBody = classAttribute.CustomBody; + string customBody = string.Join(Environment.NewLine, new[] { customInFileBody, customAttributeBody }.Where(i => !string.IsNullOrWhiteSpace(i))); var tsDoc = GetTsDocForType(type); var content = _typeService.UseDefaultExport(type) ? @@ -458,8 +462,12 @@ private IEnumerable GenerateInterface(Type type, ExportTsInterfaceAttrib string tsTypeNameFirstPart = tsTypeName.RemoveTypeGenericComponent(); string filePath = GetFilePath(type, outputDir); string filePathRelative = GetRelativeFilePath(type, outputDir); - string customHead = _tsContentGenerator.GetCustomHead(filePath); - string customBody = _tsContentGenerator.GetCustomBody(filePath, Options.TabLength); + string customInFileHead = _tsContentGenerator.GetCustomHead(filePath); + string customAttributeHead = interfaceAttribute.CustomHeader; + string customHead = string.Join(Environment.NewLine, new[] { customInFileHead, customAttributeHead }.Where(i => !string.IsNullOrWhiteSpace(i))); + string customInFileBody = _tsContentGenerator.GetCustomBody(filePath, Options.TabLength); + string customAttributeBody = interfaceAttribute.CustomBody; + string customBody = string.Join(Environment.NewLine, new[] { customInFileBody, customAttributeBody }.Where(i => !string.IsNullOrWhiteSpace(i))); var tsDoc = GetTsDocForType(type); var content = _typeService.UseDefaultExport(type) ? diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs index a39408a3..15d9866d 100644 --- a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/ClassSpecBuilderBase.cs @@ -6,6 +6,8 @@ namespace TypeGen.Core.SpecGeneration.Builders { public abstract class ClassSpecBuilderBase : SpecBuilderBase, ICustomBaseTrait, + ICustomHeaderTrait, + ICustomBodyTrait, IDefaultExportTrait, IDefaultTypeOutputTrait, IDefaultValueTrait, @@ -26,6 +28,8 @@ public abstract class ClassSpecBuilderBase : SpecBuilderBase, where TSelf : SpecBuilderBase { private readonly CustomBaseTrait _customBaseTrait; + private readonly CustomBodyTrait _customBodyTrait; + private readonly CustomHeaderTrait _customHeaderTrait; private readonly DefaultExportTrait _defaultExportTrait; private readonly DefaultTypeOutputTrait _defaultTypeOutputTrait; private readonly DefaultValueTrait _defaultValueTrait; @@ -48,6 +52,8 @@ internal ClassSpecBuilderBase(TypeSpec typeSpec) : base(typeSpec) { MemberTrait = new MemberTrait(this as TSelf, typeSpec); _customBaseTrait = new CustomBaseTrait(this as TSelf, typeSpec); + _customBodyTrait = new CustomBodyTrait(this as TSelf, typeSpec); + _customHeaderTrait = new CustomHeaderTrait(this as TSelf, typeSpec); _defaultExportTrait = new DefaultExportTrait(this as TSelf, typeSpec); _defaultTypeOutputTrait = new DefaultTypeOutputTrait(this as TSelf, typeSpec, MemberTrait); _defaultValueTrait = new DefaultValueTrait(this as TSelf, typeSpec, MemberTrait); @@ -75,7 +81,15 @@ public TSelf CustomBase(string @base = null, string importPath = null, string or public TSelf CustomBase(string @base = null, string importPath = null, string originalTypeName = null, bool isDefaultExport = false, params ImplementedInterface[] implementedInterfaces) => _customBaseTrait.CustomBase(@base, importPath, originalTypeName, isDefaultExport, implementedInterfaces); - + + /// + public TSelf CustomBody(string body) + => _customBodyTrait.CustomBody(body); + + /// + public TSelf CustomHeader(string header) + => _customHeaderTrait.CustomHeader(header); + /// public TSelf DefaultExport(bool enabled = true) => _defaultExportTrait.DefaultExport(enabled); diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/InterfaceSpecBuilderBase.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/InterfaceSpecBuilderBase.cs index a7558fa4..54efcd60 100644 --- a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/InterfaceSpecBuilderBase.cs +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/InterfaceSpecBuilderBase.cs @@ -9,6 +9,8 @@ namespace TypeGen.Core.SpecGeneration.Builders /// public abstract class InterfaceSpecBuilderBase : SpecBuilderBase, ICustomBaseTrait, + ICustomHeaderTrait, + ICustomBodyTrait, IDefaultExportTrait, IDefaultTypeOutputTrait, IDefaultValueTrait, @@ -28,6 +30,8 @@ public abstract class InterfaceSpecBuilderBase : SpecBuilderBase, where TSelf : SpecBuilderBase { private readonly CustomBaseTrait _customBaseTrait; + private readonly CustomBodyTrait _customBodyTrait; + private readonly CustomHeaderTrait _customHeaderTrait; private readonly DefaultExportTrait _defaultExportTrait; private readonly DefaultTypeOutputTrait _defaultTypeOutputTrait; private readonly DefaultValueTrait _defaultValueTrait; @@ -49,6 +53,8 @@ internal InterfaceSpecBuilderBase(TypeSpec typeSpec) : base(typeSpec) { MemberTrait = new MemberTrait(this as TSelf, typeSpec); _customBaseTrait = new CustomBaseTrait(this as TSelf, typeSpec); + _customBodyTrait = new CustomBodyTrait(this as TSelf, typeSpec); + _customHeaderTrait = new CustomHeaderTrait(this as TSelf, typeSpec); _defaultExportTrait = new DefaultExportTrait(this as TSelf, typeSpec); _defaultTypeOutputTrait = new DefaultTypeOutputTrait(this as TSelf, typeSpec, MemberTrait); _defaultValueTrait = new DefaultValueTrait(this as TSelf, typeSpec, MemberTrait); @@ -75,6 +81,14 @@ public TSelf CustomBase(string @base = null, string importPath = null, string or public TSelf CustomBase(string @base = null, string importPath = null, string originalTypeName = null, bool isDefaultExport = false, params ImplementedInterface[] implementedInterfaces) => _customBaseTrait.CustomBase(@base, importPath, originalTypeName, isDefaultExport, implementedInterfaces); + + /// + public TSelf CustomBody(string body) + => _customBodyTrait.CustomBody(body); + + /// + public TSelf CustomHeader(string header) + => _customHeaderTrait.CustomHeader(header); /// public TSelf DefaultExport(bool enabled = true) => _defaultExportTrait.DefaultExport(enabled); @@ -131,4 +145,4 @@ public TSelf Type(string typeName, string importPath = null, string originalType /// public TSelf Undefined() => _undefinedTrait.Undefined(); } -} \ No newline at end of file +} diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomBodyTrait.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomBodyTrait.cs new file mode 100644 index 00000000..90624a88 --- /dev/null +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomBodyTrait.cs @@ -0,0 +1,21 @@ +using TypeGen.Core.TypeAnnotations; + +namespace TypeGen.Core.SpecGeneration.Builders.Traits; + +internal class CustomBodyTrait : ICustomBodyTrait +{ + private readonly TSpecBuilder _this; + private readonly TypeSpec _typeSpec; + + public CustomBodyTrait(TSpecBuilder @this, TypeSpec typeSpec) + { + _this = @this; + _typeSpec = typeSpec; + } + + public TSpecBuilder CustomBody(string body) + { + _typeSpec.SetCustomBody(body); + return _this; + } +} diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomHeaderTrait.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomHeaderTrait.cs new file mode 100644 index 00000000..5ece8940 --- /dev/null +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/CustomHeaderTrait.cs @@ -0,0 +1,21 @@ +using TypeGen.Core.TypeAnnotations; + +namespace TypeGen.Core.SpecGeneration.Builders.Traits; + +internal class CustomHeaderTrait : ICustomHeaderTrait +{ + private readonly TSpecBuilder _this; + private readonly TypeSpec _typeSpec; + + public CustomHeaderTrait(TSpecBuilder @this, TypeSpec typeSpec) + { + _this = @this; + _typeSpec = typeSpec; + } + + public TSpecBuilder CustomHeader(string header) + { + _typeSpec.SetCustomHeader(header); + return _this; + } +} diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomBodyTrait.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomBodyTrait.cs new file mode 100644 index 00000000..58dd12ce --- /dev/null +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomBodyTrait.cs @@ -0,0 +1,10 @@ +namespace TypeGen.Core.SpecGeneration.Builders.Traits; + +internal interface ICustomBodyTrait +{ + /// + /// Indicates type has a custom body (equivalent of TsExportAttribute's CustomBody). + /// + /// The current instance of . + TSpecBuilder CustomBody(string body); +} diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomHeaderTrait.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomHeaderTrait.cs new file mode 100644 index 00000000..ab69a726 --- /dev/null +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/Builders/Traits/ICustomHeaderTrait.cs @@ -0,0 +1,10 @@ +namespace TypeGen.Core.SpecGeneration.Builders.Traits; + +internal interface ICustomHeaderTrait +{ + /// + /// Indicates type has a custom header (equivalent of TsExportAttribute's CustomHeader). + /// + /// The current instance of . + TSpecBuilder CustomHeader(string header); +} diff --git a/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs b/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs index f8f1f67e..89d131c6 100644 --- a/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs +++ b/src/TypeGen/TypeGen.Core/SpecGeneration/TypeSpec.cs @@ -21,7 +21,7 @@ public TypeSpec(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, @@ -32,6 +32,8 @@ public void AddCustomBaseAttribute(string @base = null, string importPath = null 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()); @@ -48,8 +50,8 @@ public void AddTypeAttribute(string memberName, string typeName, string importPa 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); } -} \ No newline at end of file +} diff --git a/src/TypeGen/TypeGen.Core/TypeAnnotations/ExportAttribute.cs b/src/TypeGen/TypeGen.Core/TypeAnnotations/ExportAttribute.cs index 509dc0a4..be5b55d2 100644 --- a/src/TypeGen/TypeGen.Core/TypeAnnotations/ExportAttribute.cs +++ b/src/TypeGen/TypeGen.Core/TypeAnnotations/ExportAttribute.cs @@ -11,7 +11,9 @@ namespace TypeGen.Core.TypeAnnotations public abstract class ExportAttribute : Attribute { private string _outputDir; - + private string _customHeader; + private string _customBody; + /// /// TypeScript file output directory /// @@ -20,5 +22,23 @@ public string OutputDir get => _outputDir; set => _outputDir = FileSystemUtils.AsDirectory(value); } + + /// + /// TypeScript file custom header + /// + public string CustomHeader + { + get => _customHeader; + set => _customHeader = value; + } + + /// + /// TypeScript file custom body + /// + public string CustomBody + { + get => _customBody; + set => _customBody = value; + } } }