diff --git a/packages/http-client-csharp/docs/emitter.md b/packages/http-client-csharp/docs/emitter.md index 827da57427a..1cea78a066e 100644 --- a/packages/http-client-csharp/docs/emitter.md +++ b/packages/http-client-csharp/docs/emitter.md @@ -56,9 +56,9 @@ Set to `false` to skip generation of convenience methods. The default value is ` ### `unreferenced-types-handling` -**Type:** `"removeOrInternalize" | "internalize" | "keepAll"` +**Type:** `"internalize" | "keepAll"` -Defines the strategy on how to handle unreferenced types. The default value is `removeOrInternalize`. +Defines the strategy on how to handle unreferenced types. The default value is `internalize`. ### `new-project` diff --git a/packages/http-client-csharp/emitter/src/options.ts b/packages/http-client-csharp/emitter/src/options.ts index 6978e355f9b..4d3df57e8bf 100644 --- a/packages/http-client-csharp/emitter/src/options.ts +++ b/packages/http-client-csharp/emitter/src/options.ts @@ -15,7 +15,7 @@ type ApiVersionSelection = string | Record; export interface CSharpEmitterOptions { "api-version"?: ApiVersionSelection; - "unreferenced-types-handling"?: "removeOrInternalize" | "internalize" | "keepAll"; + "unreferenced-types-handling"?: "internalize" | "keepAll"; "new-project"?: boolean; "save-inputs"?: boolean; debug?: boolean; @@ -61,10 +61,10 @@ export const CSharpEmitterOptionsSchema: JSONSchemaType = }, "unreferenced-types-handling": { type: "string", - enum: ["removeOrInternalize", "internalize", "keepAll"], + enum: ["internalize", "keepAll"], nullable: true, description: - "Defines the strategy on how to handle unreferenced types. The default value is `removeOrInternalize`.", + "Defines the strategy on how to handle unreferenced types. The default value is `internalize`.", }, "new-project": { type: "boolean", diff --git a/packages/http-client-csharp/emitter/src/type/configuration.ts b/packages/http-client-csharp/emitter/src/type/configuration.ts index 2a2f3e2f2e8..11bce6cde71 100644 --- a/packages/http-client-csharp/emitter/src/type/configuration.ts +++ b/packages/http-client-csharp/emitter/src/type/configuration.ts @@ -3,7 +3,7 @@ export interface Configuration { "package-name": string | null; - "unreferenced-types-handling"?: "removeOrInternalize" | "internalize" | "keepAll"; + "unreferenced-types-handling"?: "internalize" | "keepAll"; "disable-xml-docs"?: boolean; "disable-roslyn-reduce"?: boolean; license?: { diff --git a/packages/http-client-csharp/emitter/test/Unit/options.test.ts b/packages/http-client-csharp/emitter/test/Unit/options.test.ts index be8603adeb0..9f62fae3d5a 100644 --- a/packages/http-client-csharp/emitter/test/Unit/options.test.ts +++ b/packages/http-client-csharp/emitter/test/Unit/options.test.ts @@ -124,7 +124,7 @@ describe("Configuration tests", async () => { } const customOptions: TestEmitterOptions = { "package-name": "custom-package", - "unreferenced-types-handling": "removeOrInternalize", + "unreferenced-types-handling": "internalize", "disable-xml-docs": true, "disable-roslyn-reduce": true, license: { @@ -141,7 +141,7 @@ describe("Configuration tests", async () => { const config = createConfiguration(customOptions, "rootNamespace", sdkContext); expect(config["package-name"]).toBe("custom-package"); - expect(config["unreferenced-types-handling"]).toBe("removeOrInternalize"); + expect(config["unreferenced-types-handling"]).toBe("internalize"); expect(config["disable-xml-docs"]).toBe(true); expect(config["disable-roslyn-reduce"]).toBe(true); expect(config.license).toEqual({ diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs index 15596c96918..13ecacc98f1 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/ScmTypeFactory.cs @@ -269,7 +269,8 @@ public virtual MethodBodyStatement SerializeXmlValue( SerializationFormat format) => MrwSerializationTypeDefinition.SerializeXmlValueCore(valueType, value, xmlWriter, mrwOptionsParameter, format); - protected override ModelProvider? CreateModelCore(InputModelType model) => new ScmModelProvider(model); + protected override ModelProvider? CreateModelCore(InputModelType model) + => model.IsFileType ? null : new ScmModelProvider(model); protected override ModelFactoryProvider CreateModelFactoryCore(IEnumerable models) => new ScmModelFactoryProvider(models); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ScmTypeFactoryTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ScmTypeFactoryTests.cs index 98f1b9a5fd0..c7fc0dc70cf 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ScmTypeFactoryTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/ScmTypeFactoryTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Reflection; using Microsoft.TypeSpec.Generator.ClientModel.Providers; using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; @@ -146,6 +147,18 @@ public void TestCreateSerializations_ReturnsBothMrwAndMultipart_WhenJsonAndMpfdU "Expected a multipart serialization provider for a model with MultipartFormData usage."); } + [Test] + public void FileTypeDoesNotCreateModelProvider() + { + var file = InputFactory.Model("File", @namespace: "TypeSpec.Http"); + typeof(InputModelType).GetProperty(nameof(InputModelType.IsFileType))!.SetValue(file, true); + + MockHelpers.LoadMockGenerator(inputModels: () => [file]); + + var provider = ScmCodeModelGenerator.Instance.TypeFactory.CreateModel(file); + Assert.IsNull(provider); + } + // ScmTypeFactory overrides CreateModelCore to return ScmModelProvider. External-type // handling lives in the (non-overridable) base TypeFactory.CreateModel, so it must still // apply here. This guards against regressing the fix by re-introducing external handling diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CSharpGen.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CSharpGen.cs index c013817a72e..da0b80a9409 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CSharpGen.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/CSharpGen.cs @@ -90,6 +90,19 @@ await GeneratedCodeWorkspace.LoadBaselineContract(), { // Ensure back-compatibility processing is done after all visitors have run outputType.ProcessTypeForBackCompatibility(); + } + + PostProcessTypeProviders(output.TypeProviders); + + LoggingHelpers.LogElapsedTime("All generated type providers post-processed"); + + var modelFactory = output.ModelFactory.Value; + foreach (var outputType in output.TypeProviders) + { + if (ReferenceEquals(outputType, modelFactory) && outputType.Methods.Count == 0) + { + continue; + } var writer = CodeModelGenerator.Instance.GetWriter(outputType); generateFilesTasks.Add(generatedCodeWorkspace.AddGeneratedFile(writer.Write())); @@ -111,8 +124,6 @@ await GeneratedCodeWorkspace.LoadBaselineContract(), LoggingHelpers.LogElapsedTime("All old generated files have been deleted"); - await generatedCodeWorkspace.PostProcessAsync(); - // Write the generated files to the output directory await foreach (var file in generatedCodeWorkspace.GetGeneratedFilesAsync()) { @@ -138,6 +149,21 @@ await GeneratedCodeWorkspace.LoadBaselineContract(), LoggingHelpers.LogElapsedTime("All files have been written to disk"); } + private static void PostProcessTypeProviders(IReadOnlyList typeProviders) + { + if (Configuration.UnreferencedTypesHandling == Configuration.UnreferencedTypesHandlingOption.KeepAll) + { + return; + } + + var modelFactory = CodeModelGenerator.Instance.OutputLibrary.ModelFactory.Value; + var postProcessor = new PostProcessor( + [.. CodeModelGenerator.Instance.TypeFactory.UnionVariantTypesToKeep, .. CodeModelGenerator.Instance.AdditionalRootTypes], + modelFactoryFullName: modelFactory.Type.FullyQualifiedName, + additionalNonRootTypeNames: CodeModelGenerator.Instance.NonRootTypes); + postProcessor.Internalize(typeProviders); + } + internal static void FilterAllCustomizedMembers(OutputLibrary output) { foreach (var typeProvider in output.TypeProviders) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Configuration.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Configuration.cs index 39ddf41b3ec..663e26c103a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Configuration.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Configuration.cs @@ -15,9 +15,8 @@ public class Configuration { public enum UnreferencedTypesHandlingOption { - RemoveOrInternalize = 0, - Internalize = 1, - KeepAll = 2 + Internalize = 0, + KeepAll = 1 } private const string GeneratedFolderName = "Generated"; @@ -83,7 +82,7 @@ private static class Options /// public LicenseInfo? LicenseInfo { get; } - internal static UnreferencedTypesHandlingOption UnreferencedTypesHandling { get; private set; } = UnreferencedTypesHandlingOption.RemoveOrInternalize; + internal static UnreferencedTypesHandlingOption UnreferencedTypesHandling { get; private set; } = UnreferencedTypesHandlingOption.Internalize; private string? _projectDirectory; internal string ProjectDirectory => _projectDirectory ??= Path.Combine(OutputDirectory, "src"); @@ -253,7 +252,7 @@ private static T ReadEnumOption(JsonElement root, string option) where T : st public static Enum? GetDefaultEnumOptionValue(string option) => option switch { - Options.UnreferencedTypesHandling => UnreferencedTypesHandlingOption.RemoveOrInternalize, + Options.UnreferencedTypesHandling => UnreferencedTypesHandlingOption.Internalize, _ => null }; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/GeneratedCodeWorkspace.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/GeneratedCodeWorkspace.cs index c36686f637f..64d8f664e19 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/GeneratedCodeWorkspace.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/GeneratedCodeWorkspace.cs @@ -260,33 +260,6 @@ internal static Project AddDirectory(Project project, string directory, Func - /// This method invokes the postProcessor to do some post processing work - /// Depending on the configuration, it will either remove + internalize, just internalize or do nothing - /// - public async Task PostProcessAsync() - { - var modelFactory = CodeModelGenerator.Instance.OutputLibrary.ModelFactory.Value; - var nonRootTypes = CodeModelGenerator.Instance.NonRootTypes; - var postProcessor = new PostProcessor( - [.. CodeModelGenerator.Instance.TypeFactory.UnionVariantTypesToKeep, .. CodeModelGenerator.Instance.AdditionalRootTypes], - modelFactoryFullName: modelFactory.Type.FullyQualifiedName, - additionalNonRootTypeNames: nonRootTypes); - - switch (Configuration.UnreferencedTypesHandling) - { - case Configuration.UnreferencedTypesHandlingOption.KeepAll: - break; - case Configuration.UnreferencedTypesHandlingOption.Internalize: - _project = await postProcessor.InternalizeAsync(_project); - break; - case Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize: - _project = await postProcessor.InternalizeAsync(_project); - _project = await postProcessor.RemoveAsync(_project); - break; - } - } - /// /// Resolves PackageReference items from the project's .csproj file and adds their assemblies /// as metadata references so that custom code referencing external NuGet types compiles correctly. diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/PostProcessor.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/PostProcessor.cs index dc42f801732..20505bed0a3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/PostProcessor.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/PostProcessor.cs @@ -10,6 +10,8 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Simplification; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; namespace Microsoft.TypeSpec.Generator { @@ -113,6 +115,95 @@ private async Task GetTypeSymbolsAsync(Compilation compilation, protected virtual bool ShouldIncludeDocument(Document document) => !GeneratedCodeWorkspace.IsGeneratedTestDocument(document); + public void Internalize(IReadOnlyList typeProviders) + { + var allProviders = ProviderReferenceMapBuilder.GetAllProviders(typeProviders).ToArray(); + var candidateProviders = allProviders + .Where(IsPublicType) + .Where(provider => !IsExcludedProvider(provider)) + .ToArray(); + var rootProviders = candidateProviders.Where(IsRootProvider).ToArray(); + var referenceMap = new ProviderReferenceMapBuilder(typeProviders).BuildPublicReferenceMap(rootProviders); + var referencedProviders = VisitProvidersFromRoot(rootProviders, referenceMap).ToHashSet(); + var providersToInternalize = candidateProviders + .Where(provider => !referencedProviders.Contains(provider)) + .ToArray(); + + foreach (var provider in providersToInternalize) + { + provider.Update(modifiers: MakeInternal(provider.DeclarationModifiers)); + } + + RemoveMethodsFromModelFactory(providersToInternalize.Select(provider => provider.Name).ToHashSet()); + } + + private bool IsRootProvider(TypeProvider provider) + => IsClientProvider(provider) || provider.CustomCodeView != null || ShouldKeepProvider(provider, _typesToKeep); + + private bool IsExcludedProvider(TypeProvider provider) + => IsModelFactoryProvider(provider) || ShouldKeepProvider(provider, _additionalNonRootTypeNames); + + private bool IsModelFactoryProvider(TypeProvider provider) + => _modelFactoryFullName != null && provider.Type.FullyQualifiedName == _modelFactoryFullName; + + private static bool IsClientProvider(TypeProvider provider) + => provider.Name.EndsWith("Client", StringComparison.Ordinal); + + private static bool ShouldKeepProvider(TypeProvider provider, HashSet typesToKeep) + => typesToKeep.Contains(provider.Name) || typesToKeep.Contains(provider.Type.FullyQualifiedName); + + private static bool IsPublicType(TypeProvider provider) + => provider.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public); + + private static TypeSignatureModifiers MakeInternal(TypeSignatureModifiers modifiers) + => (modifiers & ~(TypeSignatureModifiers.Public | TypeSignatureModifiers.Private | TypeSignatureModifiers.Protected)) | TypeSignatureModifiers.Internal; + + private static IEnumerable VisitProvidersFromRoot( + IEnumerable rootProviders, + IReadOnlyDictionary> referenceMap) + { + var queue = new Queue(rootProviders); + var visited = new HashSet(); + while (queue.Count > 0) + { + var provider = queue.Dequeue(); + if (!visited.Add(provider)) + { + continue; + } + + yield return provider; + if (!referenceMap.TryGetValue(provider, out var references)) + { + continue; + } + + foreach (var reference in references) + { + queue.Enqueue(reference); + } + } + } + + private void RemoveMethodsFromModelFactory(HashSet namesToRemove) + { + if (_modelFactoryFullName == null || namesToRemove.Count == 0) + { + return; + } + + var modelFactory = CodeModelGenerator.Instance.OutputLibrary.ModelFactory.Value; + if (modelFactory.Type.FullyQualifiedName != _modelFactoryFullName) + { + return; + } + + var methodsToKeep = modelFactory.Methods + .Where(method => !namesToRemove.Contains(method.Signature.Name)) + .ToArray(); + modelFactory.Update(methods: methodsToKeep); + } + /// /// This method marks the "not publicly" referenced types as internal if they are previously defined as public. It will do this job in the following steps: /// 1. This method will read all the public types defined in the given , and build a cache for those symbols @@ -133,12 +224,12 @@ public async Task InternalizeAsync(Project project) // first get all the declared symbols var definitions = await GetTypeSymbolsAsync(compilation, project, true); + // get the root symbols + var rootSymbols = await GetRootSymbolsAsync(project, definitions); // build the reference map var referenceMap = await new ReferenceMapBuilder(compilation, project).BuildPublicReferenceMapAsync( definitions.DeclaredSymbols, definitions.DeclaredNodesCache); - // get the root symbols - var rootSymbols = await GetRootSymbolsAsync(project, definitions); // traverse all the root and recursively add all the things we met var publicSymbols = VisitSymbolsFromRootAsync(rootSymbols, referenceMap); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/ProviderReferenceMapBuilder.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/ProviderReferenceMapBuilder.cs new file mode 100644 index 00000000000..68e26bd167c --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/PostProcessing/ProviderReferenceMapBuilder.cs @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; + +namespace Microsoft.TypeSpec.Generator +{ + internal class ProviderReferenceMapBuilder + { + private readonly IReadOnlyList _providers; + + public ProviderReferenceMapBuilder(IReadOnlyList providers) + { + _providers = [.. GetAllProviders(providers)]; + } + + public IReadOnlyDictionary> BuildPublicReferenceMap(IEnumerable rootTypes) + { + var referenceMap = new Dictionary>(); + var visited = new HashSet(); + var queue = new Queue(rootTypes); + + while (queue.Count > 0) + { + var provider = queue.Dequeue(); + if (!visited.Add(provider)) + { + continue; + } + + var referencedTypes = BuildPublicApiReferences(provider.CanonicalView); + referenceMap[provider] = referencedTypes; + foreach (var referencedType in referencedTypes) + { + queue.Enqueue(referencedType); + } + } + + return referenceMap; + } + + public static IEnumerable GetAllProviders(IEnumerable providers) + { + foreach (var provider in providers) + { + yield return provider; + + foreach (var nestedType in GetAllProviders(provider.CanonicalView.NestedTypes)) + { + yield return nestedType; + } + + foreach (var serializationProvider in provider.SerializationProviders) + { + yield return serializationProvider; + } + } + } + + private IReadOnlyList BuildPublicApiReferences(TypeProvider provider) + { + var referencedTypes = new HashSet(); + + AddType(provider.Type, referencedTypes); + AddType(provider.BaseType, referencedTypes); + foreach (var implementedType in provider.Implements) + { + AddType(implementedType, referencedTypes); + } + + foreach (var constructor in provider.Constructors.Where(static c => IsPublicApi(c.Signature.Modifiers))) + { + AddSignatureTypes(constructor.Signature, referencedTypes); + } + + foreach (var method in provider.Methods.Where(static m => IsPublicApi(m.Signature.Modifiers))) + { + AddSignatureTypes(method.Signature, referencedTypes); + AddType(method.Signature.ExplicitInterface, referencedTypes); + foreach (var genericArgument in method.Signature.GenericArguments ?? []) + { + AddType(genericArgument, referencedTypes); + } + } + + foreach (var property in provider.Properties.Where(static p => IsPublicApi(p.Modifiers))) + { + AddType(property.Type, referencedTypes); + AddType(property.ExplicitInterface, referencedTypes); + } + + foreach (var field in provider.Fields.Where(static f => IsPublicApi(f.Modifiers))) + { + AddType(field.Type, referencedTypes); + } + + foreach (var nestedType in provider.NestedTypes.Where(static t => IsPublicApi(t.DeclarationModifiers))) + { + AddType(nestedType.Type, referencedTypes); + } + + return [.. referencedTypes]; + } + + private void AddSignatureTypes(MethodSignatureBase signature, HashSet referencedTypes) + { + AddType(signature.ReturnType, referencedTypes); + foreach (var parameter in signature.Parameters) + { + AddType(parameter.Type, referencedTypes); + } + } + + private void AddType(CSharpType? type, HashSet referencedTypes) + { + if (type == null) + { + return; + } + + foreach (var provider in ResolveTypes(type)) + { + referencedTypes.Add(provider); + } + + AddType(type.BaseType, referencedTypes); + AddType(type.DeclaringType, referencedTypes); + foreach (var argument in type.Arguments) + { + AddType(argument, referencedTypes); + } + + if (type.IsUnion) + { + foreach (var unionItemType in type.UnionItemTypes) + { + AddType(unionItemType, referencedTypes); + } + } + } + + private IEnumerable ResolveTypes(CSharpType type) + { + if (type.IsFrameworkType) + { + return []; + } + + if (CodeModelGenerator.Instance.TypeFactory.CSharpTypeMap.TryGetValue(type, out var provider) && provider != null) + { + return _providers.Where(candidate => ReferenceEquals(candidate, provider) || candidate.Type.AreNamesEqual(type)); + } + + return _providers.Where(provider => + provider.Type.AreNamesEqual(type) || provider.CanonicalView.Type.AreNamesEqual(type)); + } + + private static bool IsPublicApi(MethodSignatureModifiers modifiers) + => (modifiers.HasFlag(MethodSignatureModifiers.Public) || modifiers.HasFlag(MethodSignatureModifiers.Protected)) + && !modifiers.HasFlag(MethodSignatureModifiers.Private); + + private static bool IsPublicApi(FieldModifiers modifiers) + => (modifiers.HasFlag(FieldModifiers.Public) || modifiers.HasFlag(FieldModifiers.Protected)) + && !modifiers.HasFlag(FieldModifiers.Private); + + private static bool IsPublicApi(TypeSignatureModifiers modifiers) + => (modifiers.HasFlag(TypeSignatureModifiers.Public) || modifiers.HasFlag(TypeSignatureModifiers.Protected)) + && !modifiers.HasFlag(TypeSignatureModifiers.Private); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/ConfigurationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/ConfigurationTests.cs index b0d402825e8..197bb9eb5e8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/ConfigurationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/ConfigurationTests.cs @@ -156,7 +156,6 @@ public void DisableDocsForProperty() } [Test] - [TestCase("removeOrInternalize")] [TestCase("keepAll")] [TestCase("internalize")] public void UnreferencedTypeHandling(string input) @@ -170,7 +169,6 @@ public void UnreferencedTypeHandling(string input) MockHelpers.LoadMockGenerator(configuration: mockJson); var expected = input switch { - "removeOrInternalize" => Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize, "keepAll" => Configuration.UnreferencedTypesHandlingOption.KeepAll, "internalize" => Configuration.UnreferencedTypesHandlingOption.Internalize, _ => throw new ArgumentException("Invalid input", nameof(input)) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/PostProcessing/PostProcessorTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/PostProcessing/PostProcessorTests.cs index 28981148a4d..0e574c2f42f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/PostProcessing/PostProcessorTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/PostProcessing/PostProcessorTests.cs @@ -8,6 +8,9 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using Microsoft.TypeSpec.Generator.Statements; using Microsoft.TypeSpec.Generator.Tests.Common; using NUnit.Framework; @@ -289,6 +292,41 @@ public async Task DoesNotRemoveValidAttributes() Assert.AreEqual(Helpers.GetExpectedFromFile().TrimEnd(), output, "The output should match the expected content."); } + [Test] + public void InternalizeUsesProviderPublicApiReferences() + { + MockHelpers.LoadMockGenerator(); + + var request = new TestTypeProvider("RequestBody"); + var dependency = new TestTypeProvider("Dependency"); + var response = new TestTypeProvider("ResponseBody"); + response.PropertiesToBuild.Add(new PropertyProvider( + null, + MethodSignatureModifiers.Public, + dependency.Type, + "Dependency", + new AutoPropertyBody(false), + response)); + + var client = new TestTypeProvider("SampleClient"); + client.FieldsToBuild.Add(new FieldProvider(FieldModifiers.Private, request.Type, "_request", client)); + client.MethodsToBuild.Add(new MethodProvider( + new MethodSignature("Get", null, MethodSignatureModifiers.Public, response.Type, null, []), + MethodBodyStatement.Empty, + client)); + + var providers = new[] { client, request, response, dependency }; + + var postProcessor = new PostProcessor([]); + postProcessor.Internalize(providers); + + Assert.IsTrue(client.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public)); + Assert.IsTrue(response.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public)); + Assert.IsTrue(dependency.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public)); + Assert.IsTrue(request.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Internal)); + Assert.IsFalse(request.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Public)); + } + private class TestPostProcessor : PostProcessor { private readonly string _rootFile; @@ -303,5 +341,34 @@ protected override Task IsRootDocument(Document document) return document.Name == _rootFile ? Task.FromResult(true) : Task.FromResult(false); } } + + private class TestTypeProvider : TypeProvider + { + private readonly string _name; + + public TestTypeProvider(string name = "Test") + { + _name = name; + } + + public List FieldsToBuild { get; } = []; + public List MethodsToBuild { get; } = []; + public List PropertiesToBuild { get; } = []; + + protected override string BuildName() => _name; + + protected override string BuildNamespace() => "Sample"; + + protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", $"{Name}.cs"); + + protected override TypeSignatureModifiers BuildDeclarationModifiers() + => TypeSignatureModifiers.Public | TypeSignatureModifiers.Partial | TypeSignatureModifiers.Class; + + protected internal override FieldProvider[] BuildFields() => [.. FieldsToBuild]; + + protected internal override MethodProvider[] BuildMethods() => [.. MethodsToBuild]; + + protected internal override PropertyProvider[] BuildProperties() => [.. PropertiesToBuild]; + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/StartUp/GeneratorHandlerTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/StartUp/GeneratorHandlerTests.cs index d8ffdcd323c..eac3a6f1dd8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/StartUp/GeneratorHandlerTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/StartUp/GeneratorHandlerTests.cs @@ -340,7 +340,7 @@ public void AddConfiguredPluginDlls_NoPluginPaths_DoesNothing() new Dictionary(), "TestPackage", false, - Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize, + Configuration.UnreferencedTypesHandlingOption.Internalize, null, pluginPaths: null); @@ -358,7 +358,7 @@ public void AddConfiguredPluginDlls_InvalidDirectory_Throws() new Dictionary(), "TestPackage", false, - Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize, + Configuration.UnreferencedTypesHandlingOption.Internalize, null, pluginPaths: ["/nonexistent/path"]); @@ -385,7 +385,7 @@ public void AddConfiguredPluginDlls_DirectoryWithPreBuiltDlls_LoadsThem() new Dictionary(), "TestPackage", false, - Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize, + Configuration.UnreferencedTypesHandlingOption.Internalize, null, pluginPaths: [testDir]); @@ -422,7 +422,7 @@ namespace AutoBuildPlugin { public class Dummy { } }"); new Dictionary(), "TestPackage", false, - Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize, + Configuration.UnreferencedTypesHandlingOption.Internalize, null, pluginPaths: [testDir]); @@ -464,7 +464,7 @@ namespace Plugin2 { public class Dummy { } }"); new Dictionary(), "TestPackage", false, - Configuration.UnreferencedTypesHandlingOption.RemoveOrInternalize, + Configuration.UnreferencedTypesHandlingOption.Internalize, null, pluginPaths: [testDir1, testDir2]); diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/BinaryContentHelper.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/BinaryContentHelper.cs new file mode 100644 index 00000000000..b76cf24aa37 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/BinaryContentHelper.cs @@ -0,0 +1,175 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using System.Xml; + +namespace SampleTypeSpec +{ + internal static partial class BinaryContentHelper + { + /// + public static BinaryContent FromEnumerable(IEnumerable enumerable) + where T : notnull + { + Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); + content.JsonWriter.WriteStartArray(); + foreach (var item in enumerable) + { + content.JsonWriter.WriteObjectValue(item, ModelSerializationExtensions.WireOptions); + } + content.JsonWriter.WriteEndArray(); + + return content; + } + + /// + public static BinaryContent FromEnumerable(IEnumerable enumerable) + { + Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); + content.JsonWriter.WriteStartArray(); + foreach (var item in enumerable) + { + if (item == null) + { + content.JsonWriter.WriteNullValue(); + } + else + { +#if NET6_0_OR_GREATER + content.JsonWriter.WriteRawValue(item); +#else + using (JsonDocument document = JsonDocument.Parse(item)) + { + JsonSerializer.Serialize(content.JsonWriter, document.RootElement); + } +#endif + } + } + content.JsonWriter.WriteEndArray(); + + return content; + } + + /// + public static BinaryContent FromEnumerable(ReadOnlySpan span) + where T : notnull + { + Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); + content.JsonWriter.WriteStartArray(); + int i = 0; + for (; i < span.Length; i++) + { + content.JsonWriter.WriteObjectValue(span[i], ModelSerializationExtensions.WireOptions); + } + content.JsonWriter.WriteEndArray(); + + return content; + } + + /// + public static BinaryContent FromDictionary(IDictionary dictionary) + where TValue : notnull + { + Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); + content.JsonWriter.WriteStartObject(); + foreach (var item in dictionary) + { + content.JsonWriter.WritePropertyName(item.Key); + content.JsonWriter.WriteObjectValue(item.Value, ModelSerializationExtensions.WireOptions); + } + content.JsonWriter.WriteEndObject(); + + return content; + } + + /// + public static BinaryContent FromDictionary(IDictionary dictionary) + { + Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); + content.JsonWriter.WriteStartObject(); + foreach (var item in dictionary) + { + content.JsonWriter.WritePropertyName(item.Key); + if (item.Value == null) + { + content.JsonWriter.WriteNullValue(); + } + else + { +#if NET6_0_OR_GREATER + content.JsonWriter.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(content.JsonWriter, document.RootElement); + } +#endif + } + } + content.JsonWriter.WriteEndObject(); + + return content; + } + + /// + public static BinaryContent FromObject(object value) + { + Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); + content.JsonWriter.WriteObjectValue(value, ModelSerializationExtensions.WireOptions); + return content; + } + + /// + public static BinaryContent FromObject(BinaryData value) + { + Utf8JsonBinaryContent content = new Utf8JsonBinaryContent(); +#if NET6_0_OR_GREATER + content.JsonWriter.WriteRawValue(value); +#else + using (JsonDocument document = JsonDocument.Parse(value)) + { + JsonSerializer.Serialize(content.JsonWriter, document.RootElement); + } +#endif + return content; + } + + /// + /// + /// + public static BinaryContent FromEnumerable(IEnumerable enumerable, string rootNameHint, string childNameHint) + where T : notnull + { + using (MemoryStream stream = new MemoryStream(256)) + { + using (XmlWriter writer = XmlWriter.Create(stream, ModelSerializationExtensions.XmlWriterSettings)) + { + writer.WriteStartElement(rootNameHint); + foreach (var item in enumerable) + { + writer.WriteObjectValue(item, ModelSerializationExtensions.WireOptions, childNameHint); + } + writer.WriteEndElement(); + } + + if (stream.Position > int.MaxValue) + { + return BinaryContent.Create(BinaryData.FromStream(stream)); + } + else + { + return BinaryContent.Create(new BinaryData(stream.GetBuffer().AsMemory(0, (int)stream.Position))); + } + } + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/PipelineRequestHeadersExtensions.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/PipelineRequestHeadersExtensions.cs new file mode 100644 index 00000000000..69ddd4aee41 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/PipelineRequestHeadersExtensions.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Linq; + +namespace SampleTypeSpec +{ + internal static partial class PipelineRequestHeadersExtensions + { + /// + /// The name. + /// The value. + /// The delimiter. + public static void SetDelimited(this PipelineRequestHeaders headers, string name, IEnumerable value, string delimiter) + { + IEnumerable stringValues = value.Select(v => TypeFormatters.ConvertToString(v)); + headers.Set(name, string.Join(delimiter, stringValues)); + } + + /// + /// The name. + /// The value. + /// The delimiter. + /// The format. + public static void SetDelimited(this PipelineRequestHeaders headers, string name, IEnumerable value, string delimiter, SerializationFormat format) + { + IEnumerable stringValues = value.Select(v => TypeFormatters.ConvertToString(v, format)); + headers.Set(name, string.Join(delimiter, stringValues)); + } + + /// + /// The prefix to prepend to each header key. + /// The dictionary of headers to add. + public static void Add(this PipelineRequestHeaders headers, string prefix, IDictionary value) + { + foreach (var header in value) + { + headers.Add(prefix + header.Key, header.Value); + } + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/Utf8JsonBinaryContent.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/Utf8JsonBinaryContent.cs new file mode 100644 index 00000000000..f4586e305fc --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/Utf8JsonBinaryContent.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel; +using System.IO; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace SampleTypeSpec +{ + internal partial class Utf8JsonBinaryContent : BinaryContent + { + private readonly MemoryStream _stream; + private readonly BinaryContent _content; + + public Utf8JsonBinaryContent() + { + _stream = new MemoryStream(); + _content = Create(_stream); + JsonWriter = new Utf8JsonWriter(_stream); + } + + /// Gets the JsonWriter. + public Utf8JsonWriter JsonWriter { get; } + + /// The stream containing the data to be written. + /// The cancellation token to use. + public override async Task WriteToAsync(Stream stream, CancellationToken cancellationToken = default) + { + await JsonWriter.FlushAsync().ConfigureAwait(false); + await _content.WriteToAsync(stream, cancellationToken).ConfigureAwait(false); + } + + /// The stream containing the data to be written. + /// The cancellation token to use. + public override void WriteTo(Stream stream, CancellationToken cancellationToken = default) + { + JsonWriter.Flush(); + _content.WriteTo(stream, cancellationToken); + } + + /// + public override bool TryComputeLength(out long length) + { + length = JsonWriter.BytesCommitted + JsonWriter.BytesPending; + return true; + } + + public override void Dispose() + { + JsonWriter.Dispose(); + _content.Dispose(); + _stream.Dispose(); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.Serialization.cs index 2ebf7fbba85..87363728c56 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.Serialization.cs @@ -13,7 +13,6 @@ namespace SampleTypeSpec { - /// The ListWithContinuationTokenHeaderResponseResponse. internal partial class ListWithContinuationTokenHeaderResponseResponse : IJsonModel { /// Initializes a new instance of for deserialization. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.cs index dc281b42e3d..fe874d2c945 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenHeaderResponseResponse.cs @@ -11,7 +11,6 @@ namespace SampleTypeSpec { - /// The ListWithContinuationTokenHeaderResponseResponse. internal partial class ListWithContinuationTokenHeaderResponseResponse { /// Keeps track of any properties unknown to the library. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.Serialization.cs index 6e622e685fe..66f3b44350c 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.Serialization.cs @@ -13,7 +13,6 @@ namespace SampleTypeSpec { - /// The ListWithContinuationTokenResponse. internal partial class ListWithContinuationTokenResponse : IJsonModel { /// Initializes a new instance of for deserialization. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.cs index e689ab9f9bd..e5b9b8c3d17 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithContinuationTokenResponse.cs @@ -11,7 +11,6 @@ namespace SampleTypeSpec { - /// The ListWithContinuationTokenResponse. internal partial class ListWithContinuationTokenResponse { /// Keeps track of any properties unknown to the library. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.Serialization.cs index 96bd3d2b4cb..64d4e703b80 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.Serialization.cs @@ -13,7 +13,6 @@ namespace SampleTypeSpec { - /// The ListWithNextLinkResponse. internal partial class ListWithNextLinkResponse : IJsonModel { /// Initializes a new instance of for deserialization. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.cs index 96de907bd81..801674109f8 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithNextLinkResponse.cs @@ -11,7 +11,6 @@ namespace SampleTypeSpec { - /// The ListWithNextLinkResponse. internal partial class ListWithNextLinkResponse { /// Keeps track of any properties unknown to the library. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.Serialization.cs index 8c69549a2dd..48f530aa5d3 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.Serialization.cs @@ -13,7 +13,6 @@ namespace SampleTypeSpec { - /// The ListWithStringNextLinkResponse. internal partial class ListWithStringNextLinkResponse : IJsonModel { /// Initializes a new instance of for deserialization. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.cs index 38c936b133d..8a3b70315db 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/ListWithStringNextLinkResponse.cs @@ -11,7 +11,6 @@ namespace SampleTypeSpec { - /// The ListWithStringNextLinkResponse. internal partial class ListWithStringNextLinkResponse { /// Keeps track of any properties unknown to the library. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.Serialization.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.Serialization.cs index cb23fca29f1..df7d8ba90e0 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.Serialization.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.Serialization.cs @@ -13,7 +13,6 @@ namespace SampleTypeSpec { - /// The PageThing. internal partial class PageThing : IJsonModel { /// Initializes a new instance of for deserialization. diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.cs index 0b9328af0fc..417a8f4d46d 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/PageThing.cs @@ -11,7 +11,6 @@ namespace SampleTypeSpec { - /// The PageThing. internal partial class PageThing { /// Keeps track of any properties unknown to the library. diff --git a/packages/http-client-csharp/readme.md b/packages/http-client-csharp/readme.md index 6dcfdea3555..ef647e8f07c 100644 --- a/packages/http-client-csharp/readme.md +++ b/packages/http-client-csharp/readme.md @@ -78,9 +78,9 @@ Set to `false` to skip generation of convenience methods. The default value is ` ### `unreferenced-types-handling` -**Type:** `"removeOrInternalize" | "internalize" | "keepAll"` +**Type:** `"internalize" | "keepAll"` -Defines the strategy on how to handle unreferenced types. The default value is `removeOrInternalize`. +Defines the strategy on how to handle unreferenced types. The default value is `internalize`. ### `new-project`