diff --git a/CHANGELOG.md b/CHANGELOG.md index c61fa498be..a2d01b9be3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Control generated type access modifier for C# via `--type-access-modifier` flag. [#4788](https://github.com/microsoft/kiota/issues/4788) ### Changed diff --git a/src/Kiota.Builder/CodeDOM/AccessModifier.cs b/src/Kiota.Builder/CodeDOM/AccessModifier.cs index b440fbca54..1ff57953d8 100644 --- a/src/Kiota.Builder/CodeDOM/AccessModifier.cs +++ b/src/Kiota.Builder/CodeDOM/AccessModifier.cs @@ -1,6 +1,7 @@ namespace Kiota.Builder.CodeDOM; public enum AccessModifier { + Internal = 3, Public = 2, Protected = 1, Private = 0 diff --git a/src/Kiota.Builder/CodeDOM/CodeClass.cs b/src/Kiota.Builder/CodeDOM/CodeClass.cs index 1e5be4b934..8ac263668e 100644 --- a/src/Kiota.Builder/CodeDOM/CodeClass.cs +++ b/src/Kiota.Builder/CodeDOM/CodeClass.cs @@ -30,9 +30,12 @@ public enum CodeClassKind /// /// CodeClass represents an instance of a Class to be generated in source code /// -public class CodeClass : ProprietableBlock, ITypeDefinition, IDiscriminatorInformationHolder, IDeprecableElement +public class CodeClass : ProprietableBlock, ITypeDefinition, IDiscriminatorInformationHolder, IDeprecableElement, IAccessibleElement { private readonly ConcurrentDictionary PropertiesByWireName = new(StringComparer.OrdinalIgnoreCase); + + public AccessModifier Access { get; set; } = AccessModifier.Public; + public bool IsErrorDefinition { get; set; diff --git a/src/Kiota.Builder/CodeDOM/CodeEnum.cs b/src/Kiota.Builder/CodeDOM/CodeEnum.cs index 3a46dd0a40..c4c48550e5 100644 --- a/src/Kiota.Builder/CodeDOM/CodeEnum.cs +++ b/src/Kiota.Builder/CodeDOM/CodeEnum.cs @@ -5,9 +5,10 @@ namespace Kiota.Builder.CodeDOM; #pragma warning disable CA1711 -public class CodeEnum : CodeBlock, IDocumentedElement, ITypeDefinition, IDeprecableElement +public class CodeEnum : CodeBlock, IDocumentedElement, ITypeDefinition, IDeprecableElement, IAccessibleElement { #pragma warning restore CA2227 + public AccessModifier Access { get; set; } = AccessModifier.Public; public bool Flags { get; set; diff --git a/src/Kiota.Builder/Configuration/GenerationConfiguration.cs b/src/Kiota.Builder/Configuration/GenerationConfiguration.cs index 6e81b63f23..352dd98b65 100644 --- a/src/Kiota.Builder/Configuration/GenerationConfiguration.cs +++ b/src/Kiota.Builder/Configuration/GenerationConfiguration.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Text.Json.Nodes; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Kiota.Builder.Lock; using Microsoft.OpenApi.ApiManifest; @@ -38,6 +39,7 @@ public ConsumerOperation? Operation public string ApiManifestPath { get; set; } = "apimanifest.json"; public string OutputPath { get; set; } = "./output"; public string ClientClassName { get; set; } = "ApiClient"; + public AccessModifier TypeAccessModifier { get; set; } = AccessModifier.Public; public string ClientNamespaceName { get; set; } = "ApiSdk"; public string NamespaceNameSeparator { get; set; } = "."; public bool ExportPublicApi diff --git a/src/Kiota.Builder/Lock/KiotaLock.cs b/src/Kiota.Builder/Lock/KiotaLock.cs index a5d38c2fc4..671def487b 100644 --- a/src/Kiota.Builder/Lock/KiotaLock.cs +++ b/src/Kiota.Builder/Lock/KiotaLock.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; namespace Kiota.Builder.Lock; @@ -31,6 +32,10 @@ public class KiotaLock /// public string ClientClassName { get; set; } = string.Empty; /// + /// The type access modifier to use for the client types. + /// + public string TypeAccessModifier { get; set; } = "Public"; + /// /// The main namespace for this client. /// public string ClientNamespaceName { get; set; } = string.Empty; @@ -102,9 +107,11 @@ public void UpdateGenerationConfigurationFromLock(GenerationConfiguration config { ArgumentNullException.ThrowIfNull(config); config.ClientClassName = ClientClassName; - config.ClientNamespaceName = ClientNamespaceName; if (Enum.TryParse(Language, out var parsedLanguage)) config.Language = parsedLanguage; + config.ClientNamespaceName = ClientNamespaceName; + if (Enum.TryParse(TypeAccessModifier, out var parsedAccessModifier)) + config.TypeAccessModifier = parsedAccessModifier; config.UsesBackingStore = UsesBackingStore; config.ExcludeBackwardCompatible = ExcludeBackwardCompatible; config.IncludeAdditionalData = IncludeAdditionalData; @@ -132,6 +139,7 @@ public KiotaLock(GenerationConfiguration config) ArgumentNullException.ThrowIfNull(config); Language = config.Language.ToString(); ClientClassName = config.ClientClassName; + TypeAccessModifier = config.TypeAccessModifier.ToString(); ClientNamespaceName = config.ClientNamespaceName; UsesBackingStore = config.UsesBackingStore; ExcludeBackwardCompatible = config.ExcludeBackwardCompatible; diff --git a/src/Kiota.Builder/Lock/KiotaLockComparer.cs b/src/Kiota.Builder/Lock/KiotaLockComparer.cs index 26f156f74a..b2f9c7333e 100644 --- a/src/Kiota.Builder/Lock/KiotaLockComparer.cs +++ b/src/Kiota.Builder/Lock/KiotaLockComparer.cs @@ -35,6 +35,7 @@ public bool Equals(KiotaLock? x, KiotaLock? y) && _stringComparer.Equals(x.ClientClassName, y.ClientClassName) && _stringComparer.Equals(x.ClientNamespaceName, y.ClientNamespaceName) && _stringComparer.Equals(x.Language, y.Language) + && _stringComparer.Equals(x.TypeAccessModifier, y.TypeAccessModifier) && _stringIEnumerableDeepComparer.Equals(x.DisabledValidationRules, y.DisabledValidationRules) && _stringIEnumerableDeepComparer.Equals(x.Serializers, y.Serializers) && _stringIEnumerableDeepComparer.Equals(x.Deserializers, y.Deserializers) @@ -56,6 +57,7 @@ public int GetHashCode([DisallowNull] KiotaLock obj) hash.Add(obj.ClientClassName, _stringComparer); hash.Add(obj.ClientNamespaceName, _stringComparer); hash.Add(obj.Language, _stringComparer); + hash.Add(obj.TypeAccessModifier, _stringComparer); hash.Add(obj.ExcludeBackwardCompatible); hash.Add(obj.UsesBackingStore); hash.Add(obj.IncludeAdditionalData); diff --git a/src/Kiota.Builder/Refiners/CSharpRefiner.cs b/src/Kiota.Builder/Refiners/CSharpRefiner.cs index 31c12c6bbe..c432dee00e 100644 --- a/src/Kiota.Builder/Refiners/CSharpRefiner.cs +++ b/src/Kiota.Builder/Refiners/CSharpRefiner.cs @@ -110,6 +110,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken generatedCode, "IParseNode" ); + SetTypeAccessModifiers(generatedCode); }, cancellationToken); } protected static void DisambiguatePropertiesWithClassNames(CodeElement currentElement) @@ -260,4 +261,14 @@ protected static void CorrectIndexerType(CodeIndexer currentIndexer) }) }, }; + + private void SetTypeAccessModifiers(CodeElement currentElement) + { + if (currentElement is IAccessibleElement accessibleElement and (CodeEnum or CodeClass)) + { + accessibleElement.Access = _configuration.TypeAccessModifier; + } + + CrawlTree(currentElement, SetTypeAccessModifiers); + } } diff --git a/src/Kiota.Builder/WorkspaceManagement/ApiClientConfiguration.cs b/src/Kiota.Builder/WorkspaceManagement/ApiClientConfiguration.cs index a8441571fd..05fe7ed810 100644 --- a/src/Kiota.Builder/WorkspaceManagement/ApiClientConfiguration.cs +++ b/src/Kiota.Builder/WorkspaceManagement/ApiClientConfiguration.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Microsoft.OpenApi.ApiManifest; @@ -15,6 +16,10 @@ public class ApiClientConfiguration : BaseApiConsumerConfiguration, ICloneable /// public string Language { get; set; } = string.Empty; /// + /// The type access modifier to use for the client types. + /// + public string TypeAccessModifier { get; set; } = "Public"; + /// /// The structured mime types used for this client. /// #pragma warning disable CA1002 @@ -64,6 +69,7 @@ public ApiClientConfiguration(GenerationConfiguration config) : base(config) { ArgumentNullException.ThrowIfNull(config); Language = config.Language.ToString(); + TypeAccessModifier = config.TypeAccessModifier.ToString(); ClientNamespaceName = config.ClientNamespaceName; UsesBackingStore = config.UsesBackingStore; ExcludeBackwardCompatible = config.ExcludeBackwardCompatible; @@ -84,6 +90,8 @@ public void UpdateGenerationConfigurationFromApiClientConfiguration(GenerationCo config.ClientNamespaceName = ClientNamespaceName; if (Enum.TryParse(Language, out var parsedLanguage)) config.Language = parsedLanguage; + if (Enum.TryParse(TypeAccessModifier, out var parsedTypeAccessModifier)) + config.TypeAccessModifier = parsedTypeAccessModifier; config.UsesBackingStore = UsesBackingStore; config.ExcludeBackwardCompatible = ExcludeBackwardCompatible; config.IncludeAdditionalData = IncludeAdditionalData; @@ -97,6 +105,7 @@ public object Clone() var result = new ApiClientConfiguration { Language = Language, + TypeAccessModifier = TypeAccessModifier, StructuredMimeTypes = [.. StructuredMimeTypes], ClientNamespaceName = ClientNamespaceName, UsesBackingStore = UsesBackingStore, diff --git a/src/Kiota.Builder/WorkspaceManagement/ApiClientConfigurationComparer.cs b/src/Kiota.Builder/WorkspaceManagement/ApiClientConfigurationComparer.cs index d13b5621cb..29e7a901dc 100644 --- a/src/Kiota.Builder/WorkspaceManagement/ApiClientConfigurationComparer.cs +++ b/src/Kiota.Builder/WorkspaceManagement/ApiClientConfigurationComparer.cs @@ -28,6 +28,7 @@ public override bool Equals(ApiClientConfiguration? x, ApiClientConfiguration? y if (x.IncludeAdditionalData != y.IncludeAdditionalData) return false; if (!_stringComparer.Equals(x.ClientNamespaceName, y.ClientNamespaceName)) return false; if (!_stringComparer.Equals(x.Language, y.Language)) return false; + if (!_stringComparer.Equals(x.TypeAccessModifier, y.TypeAccessModifier)) return false; // slow deep comparison return _stringIEnumerableDeepComparer.Equals(x.DisabledValidationRules, y.DisabledValidationRules) @@ -42,6 +43,7 @@ public override int GetHashCode([DisallowNull] ApiClientConfiguration obj) hash.Add(obj.DisabledValidationRules, _stringIEnumerableDeepComparer); // _stringIEnumerableDeepComparer orders hash.Add(obj.ClientNamespaceName, _stringComparer); hash.Add(obj.Language, _stringComparer); + hash.Add(obj.TypeAccessModifier, _stringComparer); hash.Add(obj.ExcludeBackwardCompatible); hash.Add(obj.UsesBackingStore); hash.Add(obj.IncludeAdditionalData); diff --git a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs index 40baff16f0..46a6fda2f0 100644 --- a/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs +++ b/src/Kiota.Builder/Writers/CSharp/CSharpConventionService.cs @@ -96,6 +96,7 @@ public override string GetAccessModifier(AccessModifier access) { return access switch { + AccessModifier.Internal => "internal", AccessModifier.Public => "public", AccessModifier.Protected => "protected", _ => "private", diff --git a/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs index f457430ec9..c7f3bdb808 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeClassDeclarationWriter.cs @@ -41,7 +41,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit conventions.WriteDeprecationAttribute(parentClass, writer); writer.WriteLine(GeneratedCodeAttribute); if (!hasDescription) conventions.WritePragmaDisable(writer, CSharpConventionService.CS1591); - writer.WriteLine($"public partial class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}"); + writer.WriteLine($"{conventions.GetAccessModifier(parentClass.Access)} partial class {codeElement.Name.ToFirstCharacterUpperCase()} {derivation}"); if (!hasDescription) conventions.WritePragmaRestore(writer, CSharpConventionService.CS1591); writer.StartBlock(); } diff --git a/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs index 588bb7db87..5b43dd3c44 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeEnumWriter.cs @@ -37,7 +37,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine("[Flags]"); conventions.WriteDeprecationAttribute(codeElement, writer); if (!hasDescription) writer.WriteLine("#pragma warning disable CS1591"); - writer.WriteLine($"public enum {codeElement.Name.ToFirstCharacterUpperCase()}"); + writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)} enum {codeElement.Name.ToFirstCharacterUpperCase()}"); if (!hasDescription) writer.WriteLine("#pragma warning restore CS1591"); writer.StartBlock(); var idx = 0; diff --git a/src/kiota/Handlers/Client/AddHandler.cs b/src/kiota/Handlers/Client/AddHandler.cs index b7eb188e97..beec8f8058 100644 --- a/src/kiota/Handlers/Client/AddHandler.cs +++ b/src/kiota/Handlers/Client/AddHandler.cs @@ -2,6 +2,7 @@ using System.CommandLine.Invocation; using System.Text.Json; using Kiota.Builder; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; using Kiota.Builder.WorkspaceManagement; @@ -27,6 +28,10 @@ public required Option LanguageOption { get; init; } + public required Option TypeAccessModifierOption + { + get; init; + } public required Option DescriptionOption { get; init; @@ -69,6 +74,7 @@ public override async Task InvokeAsync(InvocationContext context) { string output = context.ParseResult.GetValueForOption(OutputOption) ?? string.Empty; GenerationLanguage language = context.ParseResult.GetValueForOption(LanguageOption); + AccessModifier typeAccessModifier = context.ParseResult.GetValueForOption(TypeAccessModifierOption); string openapi = context.ParseResult.GetValueForOption(DescriptionOption) ?? string.Empty; bool backingStore = context.ParseResult.GetValueForOption(BackingStoreOption); bool excludeBackwardCompatible = context.ParseResult.GetValueForOption(ExcludeBackwardCompatibleOption); @@ -90,6 +96,7 @@ public override async Task InvokeAsync(InvocationContext context) Configuration.Generation.IncludeAdditionalData = includeAdditionalData; Configuration.Generation.Language = language; WarnUsingPreviewLanguage(language); + Configuration.Generation.TypeAccessModifier = typeAccessModifier; Configuration.Generation.SkipGeneration = skipGeneration; Configuration.Generation.Operation = ConsumerOperation.Add; if (includePatterns.Count != 0) diff --git a/src/kiota/Handlers/Client/EditHandler.cs b/src/kiota/Handlers/Client/EditHandler.cs index ae28990879..5c2bee3dfb 100644 --- a/src/kiota/Handlers/Client/EditHandler.cs +++ b/src/kiota/Handlers/Client/EditHandler.cs @@ -2,6 +2,7 @@ using System.CommandLine.Invocation; using System.Text.Json; using Kiota.Builder; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; using Kiota.Builder.WorkspaceManagement; @@ -27,6 +28,10 @@ public required Option LanguageOption { get; init; } + public required Option TypeAccessModifierOption + { + get; init; + } public required Option DescriptionOption { get; init; @@ -69,6 +74,7 @@ public override async Task InvokeAsync(InvocationContext context) { string output = context.ParseResult.GetValueForOption(OutputOption) ?? string.Empty; GenerationLanguage? language = context.ParseResult.GetValueForOption(LanguageOption); + AccessModifier? typeAccessModifier = context.ParseResult.GetValueForOption(TypeAccessModifierOption); string openapi = context.ParseResult.GetValueForOption(DescriptionOption) ?? string.Empty; bool? backingStore = context.ParseResult.GetValueForOption(BackingStoreOption); bool? excludeBackwardCompatible = context.ParseResult.GetValueForOption(ExcludeBackwardCompatibleOption); @@ -109,6 +115,8 @@ public override async Task InvokeAsync(InvocationContext context) clientConfiguration.UpdateGenerationConfigurationFromApiClientConfiguration(Configuration.Generation, className); if (language.HasValue) Configuration.Generation.Language = language.Value; + if (typeAccessModifier.HasValue) + Configuration.Generation.TypeAccessModifier = typeAccessModifier.Value; if (backingStore.HasValue) Configuration.Generation.UsesBackingStore = backingStore.Value; if (excludeBackwardCompatible.HasValue) diff --git a/src/kiota/Handlers/KiotaGenerateCommandHandler.cs b/src/kiota/Handlers/KiotaGenerateCommandHandler.cs index a0442d81af..d44c035fdf 100644 --- a/src/kiota/Handlers/KiotaGenerateCommandHandler.cs +++ b/src/kiota/Handlers/KiotaGenerateCommandHandler.cs @@ -3,6 +3,7 @@ using System.Text.Json; using Kiota.Builder; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Extensions; using Microsoft.Extensions.Logging; @@ -27,6 +28,10 @@ public required Option ClassOption { get; init; } + public required Option TypeAccessModifierOption + { + get; init; + } public required Option NamespaceOption { get; init; @@ -72,6 +77,7 @@ public override async Task InvokeAsync(InvocationContext context) bool disableSSLValidation = context.ParseResult.GetValueForOption(DisableSSLValidationOption); bool includeAdditionalData = context.ParseResult.GetValueForOption(AdditionalDataOption); string className = context.ParseResult.GetValueForOption(ClassOption) ?? string.Empty; + AccessModifier typeAccessModifier = context.ParseResult.GetValueForOption(TypeAccessModifierOption); string namespaceName = context.ParseResult.GetValueForOption(NamespaceOption) ?? string.Empty; List serializer = context.ParseResult.GetValueForOption(SerializerOption) ?? []; List deserializer = context.ParseResult.GetValueForOption(DeserializerOption) ?? []; @@ -86,6 +92,7 @@ public override async Task InvokeAsync(InvocationContext context) AssignIfNotNullOrEmpty(manifest, (c, s) => c.ApiManifestPath = s); AssignIfNotNullOrEmpty(className, (c, s) => c.ClientClassName = s); AssignIfNotNullOrEmpty(namespaceName, (c, s) => c.ClientNamespaceName = s); + Configuration.Generation.TypeAccessModifier = typeAccessModifier; Configuration.Generation.UsesBackingStore = backingStore; Configuration.Generation.ExcludeBackwardCompatible = excludeBackwardCompatible; Configuration.Generation.IncludeAdditionalData = includeAdditionalData; diff --git a/src/kiota/KiotaClientCommands.cs b/src/kiota/KiotaClientCommands.cs index df7bced23a..cd912c3b90 100644 --- a/src/kiota/KiotaClientCommands.cs +++ b/src/kiota/KiotaClientCommands.cs @@ -33,6 +33,7 @@ public static Command GetAddCommand() { var defaultConfiguration = new GenerationConfiguration(); var languageOption = KiotaHost.GetLanguageOption(); + var typeAccessModifierOption = KiotaHost.GetTypeAccessModifierOption(); var outputOption = KiotaHost.GetOutputPathOption(defaultConfiguration.OutputPath); var descriptionOption = KiotaHost.GetDescriptionOption(defaultConfiguration.OpenAPIFilePath, true); var namespaceOption = KiotaHost.GetNamespaceOption(defaultConfiguration.ClientNamespaceName); @@ -50,6 +51,7 @@ public static Command GetAddCommand() descriptionOption, outputOption, languageOption, + typeAccessModifierOption, clientNameOption, namespaceOption, logLevelOption, @@ -67,6 +69,7 @@ public static Command GetAddCommand() DescriptionOption = descriptionOption, OutputOption = outputOption, LanguageOption = languageOption, + TypeAccessModifierOption = typeAccessModifierOption, ClassOption = clientNameOption, NamespaceOption = namespaceOption, LogLevelOption = logLevelOption, @@ -104,6 +107,7 @@ public static Command GetRemoveCommand() public static Command GetEditCommand() { var languageOption = KiotaHost.GetOptionalLanguageOption(); + var typeAccessModifierOption = KiotaHost.GetOptionalTypeAccessModifierOption(); var outputOption = KiotaHost.GetOutputPathOption(string.Empty); var descriptionOption = KiotaHost.GetDescriptionOption(string.Empty); var namespaceOption = KiotaHost.GetNamespaceOption(string.Empty); @@ -121,6 +125,7 @@ public static Command GetEditCommand() descriptionOption, outputOption, languageOption, + typeAccessModifierOption, clientNameOption, namespaceOption, logLevelOption, @@ -138,6 +143,7 @@ public static Command GetEditCommand() DescriptionOption = descriptionOption, OutputOption = outputOption, LanguageOption = languageOption, + TypeAccessModifierOption = typeAccessModifierOption, ClassOption = clientNameOption, NamespaceOption = namespaceOption, LogLevelOption = logLevelOption, diff --git a/src/kiota/KiotaConfigurationExtensions.cs b/src/kiota/KiotaConfigurationExtensions.cs index a4e241847c..c54572b1f6 100644 --- a/src/kiota/KiotaConfigurationExtensions.cs +++ b/src/kiota/KiotaConfigurationExtensions.cs @@ -1,4 +1,5 @@ using Kiota.Builder; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Microsoft.Extensions.Configuration; @@ -54,6 +55,7 @@ public static void BindConfiguration(this KiotaConfiguration configObject, IConf configObject.Generation.OpenAPIFilePath = configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.OpenAPIFilePath)}"] is string openApiFilePath && !string.IsNullOrEmpty(openApiFilePath) ? openApiFilePath : configObject.Generation.OpenAPIFilePath; configObject.Generation.OutputPath = configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.OutputPath)}"] is string outputPath && !string.IsNullOrEmpty(outputPath) ? outputPath : configObject.Generation.OutputPath; configObject.Generation.ClientClassName = configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.ClientClassName)}"] is string clientClassName && !string.IsNullOrEmpty(clientClassName) ? clientClassName : configObject.Generation.ClientClassName; + configObject.Generation.TypeAccessModifier = Enum.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.TypeAccessModifier)}"], true, out var accessModifier) ? accessModifier : AccessModifier.Public; configObject.Generation.ClientNamespaceName = configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.ClientNamespaceName)}"] is string clientNamespaceName && !string.IsNullOrEmpty(clientNamespaceName) ? clientNamespaceName : configObject.Generation.ClientNamespaceName; configObject.Generation.UsesBackingStore = bool.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.UsesBackingStore)}"], out var usesBackingStore) && usesBackingStore; configObject.Generation.IncludeAdditionalData = bool.TryParse(configuration[$"{nameof(configObject.Generation)}:{nameof(GenerationConfiguration.IncludeAdditionalData)}"], out var includeAdditionalData) && includeAdditionalData; diff --git a/src/kiota/KiotaHost.cs b/src/kiota/KiotaHost.cs index 238406b020..a604cf5602 100644 --- a/src/kiota/KiotaHost.cs +++ b/src/kiota/KiotaHost.cs @@ -4,6 +4,7 @@ using kiota.Handlers; using kiota.Rpc; using Kiota.Builder; +using Kiota.Builder.CodeDOM; using Kiota.Builder.Configuration; using Kiota.Builder.Validation; using Microsoft.Extensions.Logging; @@ -364,6 +365,21 @@ internal static Option GetLanguageOption() AddEnumValidator(languageOption, "language"); return languageOption; } + internal static Option GetTypeAccessModifierOption() + { + var accessOption = new Option("--type-access-modifier", "The type access modifier to use for the client types."); + accessOption.AddAlias("--tam"); + accessOption.SetDefaultValue(AccessModifier.Public); + AddEnumValidator(accessOption, "type-access-modifier"); + return accessOption; + } + internal static Option GetOptionalTypeAccessModifierOption() + { + var accessOption = new Option("--type-access-modifier", "The type access modifier to use for the client types."); + accessOption.AddAlias("--tam"); + AddEnumValidator(accessOption, "type-access-modifier"); + return accessOption; + } internal static Option GetNamespaceOption(string defaultNamespaceName) { var namespaceOption = new Option("--namespace-name", () => defaultNamespaceName, "The namespace to use for the core client class specified with the --class-name option."); @@ -432,6 +448,8 @@ private static Command GetGenerateCommand() classOption.ArgumentHelpName = "name"; AddStringRegexValidator(classOption, classNameRegex(), "class name"); + var typeAccessModifierOption = GetTypeAccessModifierOption(); + var namespaceOption = GetNamespaceOption(defaultConfiguration.ClientNamespaceName); var logLevelOption = GetLogLevelOption(); @@ -474,6 +492,7 @@ private static Command GetGenerateCommand() outputOption, languageOption, classOption, + typeAccessModifierOption, namespaceOption, logLevelOption, backingStoreOption, @@ -496,6 +515,7 @@ private static Command GetGenerateCommand() OutputOption = outputOption, LanguageOption = languageOption, ClassOption = classOption, + TypeAccessModifierOption = typeAccessModifierOption, NamespaceOption = namespaceOption, LogLevelOption = logLevelOption, BackingStoreOption = backingStoreOption, diff --git a/tests/Kiota.Builder.Tests/Refiners/CSharpLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/CSharpLanguageRefinerTests.cs index df29b9e80b..73fb546e0b 100644 --- a/tests/Kiota.Builder.Tests/Refiners/CSharpLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/CSharpLanguageRefinerTests.cs @@ -910,5 +910,23 @@ public async Task AddsUsingForUntypedNodeAsync() Assert.Equal("Microsoft.Kiota.Abstractions.Serialization", nodeUsing[0].Declaration.Name); } + [Theory] + [InlineData(AccessModifier.Public)] + [InlineData(AccessModifier.Internal)] + public async Task SetTypeAccessModifierAsync(AccessModifier accessModifier) + { + var codeClass = root.AddClass(new CodeClass + { + Name = "Class1", + Kind = CodeClassKind.Model + }).First(); + var codeEnum = root.AddEnum(new CodeEnum + { + Name = "Enum1", + }).First(); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.CSharp, TypeAccessModifier = accessModifier }, root); + Assert.Equal(codeClass.Access, accessModifier); + Assert.Equal(codeEnum.Access, accessModifier); + } #endregion } diff --git a/tests/Kiota.Builder.Tests/WorkspaceManagement/ApiClientConfigurationComparerTests.cs b/tests/Kiota.Builder.Tests/WorkspaceManagement/ApiClientConfigurationComparerTests.cs index f967f0b54b..161466ccc6 100644 --- a/tests/Kiota.Builder.Tests/WorkspaceManagement/ApiClientConfigurationComparerTests.cs +++ b/tests/Kiota.Builder.Tests/WorkspaceManagement/ApiClientConfigurationComparerTests.cs @@ -25,10 +25,11 @@ public void GetsHashCode() var stringComparer = StringComparer.OrdinalIgnoreCase; hash.Add(string.Empty, stringComparer); hash.Add(string.Empty, stringComparer); + hash.Add("public", stringComparer); hash.Add(false); hash.Add(true); hash.Add(false); - hash.Add(new List(), iEnumComparer); + hash.Add([], iEnumComparer); var hash2 = new HashCode(); hash2.Add(string.Empty, stringComparer); hash2.Add(string.Empty, stringComparer); diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeClassDeclarationWriterTests.cs index 20d0b3df68..836c5221e8 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeClassDeclarationWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeClassDeclarationWriterTests.cs @@ -123,4 +123,15 @@ public void WritesGeneratedCodeAttribute() var result = tw.ToString(); Assert.Matches(CodeEnumWriterTests.GeneratedCodePattern, result); } + + [Theory] + [InlineData(AccessModifier.Public)] + [InlineData(AccessModifier.Internal)] + public void WritesAccessModifier(AccessModifier accessModifier) + { + parentClass.Access = accessModifier; + codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); + var result = tw.ToString(); + Assert.Contains($"{accessModifier.ToString().ToLower()} partial class", result); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeEnumWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeEnumWriterTests.cs index bbbd6fd2f5..0a76a2e617 100644 --- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeEnumWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeEnumWriterTests.cs @@ -139,4 +139,18 @@ public void WritesGeneratedCodeAttribute() var result = tw.ToString(); Assert.Matches(GeneratedCodePattern, result); } + + [Theory] + [InlineData(AccessModifier.Public)] + [InlineData(AccessModifier.Internal)] + public void WritesAccessModifier(AccessModifier accessModifier) + { + currentEnum.Access = accessModifier; + currentEnum.AddOption(Option); + writer.Write(currentEnum); + var result = tw.ToString(); + Assert.Contains($"{accessModifier.ToString().ToLower()} enum", result); + AssertExtensions.CurlyBracesAreClosed(result, 1); + Assert.Contains(Option.Name, result); + } }