diff --git a/CHANGELOG.md b/CHANGELOG.md index bfdda50..e31d965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Simplified response for generated API clients using the React template (#203) - Add default maps for unsigned numbers (#180) +- Apply `TypeContractorIgnore` to properties ### Fixed diff --git a/README.md b/README.md index 02033b5..c51200d 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,8 @@ Available annotations: If you have a controller that doesn't need a client generated, you can annotate that controller using `TypeContractorIgnore` and it will be automatically skipped. + + Also works on properties that shouldn't be included in generated DTOs. * `TypeContractorName`: If you have a badly named controller that you can't rename, you want something custom, or just don't like the default naming diff --git a/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs b/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs index 03dacd2..f520890 100644 --- a/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs +++ b/TypeContractor.Annotations/TypeContractorIgnoreAttribute.cs @@ -3,11 +3,11 @@ namespace TypeContractor.Annotations { /// - /// Tells TypeContractor to ignore the given controller when generating - /// automatic API clients. For example a controller that serves static - /// assets for the HTML templates. + /// Tells TypeContractor to ignore the target when generating TypeScript. + /// For example a controller that serves static assets for HTML templates. + /// Can also be used for properties that don't need to be exposed. /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class TypeContractorIgnoreAttribute : Attribute { } diff --git a/TypeContractor.Tests/TypeScript/TypeScriptConverterTests.cs b/TypeContractor.Tests/TypeScript/TypeScriptConverterTests.cs index 12221ab..2cd229f 100644 --- a/TypeContractor.Tests/TypeScript/TypeScriptConverterTests.cs +++ b/TypeContractor.Tests/TypeScript/TypeScriptConverterTests.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Runtime.InteropServices; +using TypeContractor.Annotations; using TypeContractor.TypeScript; namespace TypeContractor.Tests.TypeScript; @@ -416,6 +417,18 @@ public void Handles_Arrays() list.IsArray.Should().BeTrue(); } + [Fact] + public void Ignores_Properties_With_IgnoreAttribute() + { + var result = Sut.Convert(typeof(ResponseWithIgnoredProperties)); + + result.Should().NotBeNull(); + result.Properties.Should() + .NotBeNull() + .And.ContainSingle() + .And.Contain(x => x.DestinationName == "dontIgnoreMeBro"); + } + #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. private record TopLevelRecord(string Name, SecondStoryRecord? SecondStoryRecord); private record SecondStoryRecord(string Description, SomeOtherDeeplyNestedRecord? SomeOtherDeeplyNestedRecord); @@ -559,6 +572,13 @@ private class ResponseWithArrayDto public DateOnlyResponse[] DateOnlyResponses { get; set; } } + private class ResponseWithIgnoredProperties + { + public string DontIgnoreMeBro { get; set; } + [TypeContractorIgnore] + public string FeelFreeToIgnoreMe { get; set; } + } + #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. private MetadataLoadContext BuildMetadataLoadContext() diff --git a/TypeContractor.Tool/ConsoleLogger.cs b/TypeContractor.Tool/ConsoleLogger.cs index f446fe4..bc7d59e 100644 --- a/TypeContractor.Tool/ConsoleLogger.cs +++ b/TypeContractor.Tool/ConsoleLogger.cs @@ -4,6 +4,7 @@ namespace TypeContractor.Tool; public enum LogLevel { + Trace, Debug, Info, Warning, @@ -42,4 +43,10 @@ public void LogDebug(string message) if (logLevel <= LogLevel.Debug) Console.WriteLine($"[ DBG] {message}"); } + + public void LogTrace(string message) + { + if (logLevel <= LogLevel.Trace) + Console.WriteLine($"[TRC] {message}"); + } } diff --git a/TypeContractor/Logger/ILog.cs b/TypeContractor/Logger/ILog.cs index c0d5d9c..59734ae 100644 --- a/TypeContractor/Logger/ILog.cs +++ b/TypeContractor/Logger/ILog.cs @@ -2,6 +2,7 @@ namespace TypeContractor.Logger; public interface ILog { + void LogTrace(string message); void LogDebug(string message); void LogError(Exception exception, string message); void LogError(string message); diff --git a/TypeContractor/Logger/NullLogger.cs b/TypeContractor/Logger/NullLogger.cs index 5557503..d4e75bb 100644 --- a/TypeContractor/Logger/NullLogger.cs +++ b/TypeContractor/Logger/NullLogger.cs @@ -2,6 +2,10 @@ namespace TypeContractor.Logger; public class NullLogger : ILog { + public void LogTrace(string message) + { + } + public void LogDebug(string message) { } diff --git a/TypeContractor/TypeScript/TypeScriptConverter.cs b/TypeContractor/TypeScript/TypeScriptConverter.cs index 2ec0fb6..24b16e9 100644 --- a/TypeContractor/TypeScript/TypeScriptConverter.cs +++ b/TypeContractor/TypeScript/TypeScriptConverter.cs @@ -1,5 +1,7 @@ using System.Reflection; +using TypeContractor.Annotations; using TypeContractor.Helpers; +using TypeContractor.Logger; using TypeContractor.Output; namespace TypeContractor.TypeScript; @@ -62,6 +64,12 @@ private List GetProperties(Type type) // Evaluate type of property foreach (var property in properties) { + if (property.HasCustomAttribute(typeof(TypeContractorIgnoreAttribute).FullName!)) + { + Log.Instance.LogTrace($"Property {type.FullName ?? type.Name}.{property.Name} is ignored by attribute"); + continue; + } + // Need to have a getter if (!property.CanRead) continue;