Repository: microsoft/kiota (csharp)

Issue:
TypeScript - investigate grouping all reusable models in a single file
follow up to #3814 which has yielded significant file numbers reductions (from 36k to 21k) and marginal size reduction (72MB to 70MB). If we grouped all reusable models in a single file per namespace we could achieve another 6k files reduction and reduce the size of the package further

Pull request description:
fixes #3843

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80fb63e1a3..b8010b9447 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,12 +15,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Request builders are now in the index file to simplify imports and reduce generated code in TypeScript. [#3799](https://github.com/microsoft/kiota/issues/3799)
 - Groups request builders and inline request/response bodies in the same file in TypeScript.
+- Groups all reusable models in a single file in TypeScript. [#3843](https://github.com/microsoft/kiota/issues/3843)
 - Fixed a bug where reserved name rename would not rename objects properly. [#3609](https://github.com/microsoft/kiota/issues/3609)
 - Switched to a Jammy Chiseled base image for docker containers.
 - Moved the withUrlMethod of TypeScript in the base package. [#3812](https://github.com/microsoft/kiota/issues/3812)
 - Fixed a bug where path parameters deduplication would create collisions on sub path segments. [#3757](https://github.com/microsoft/kiota/issues/3757)
 - Moved from net7 to net8.
-- Removed windows OS from docker multi-partform image to align with [dotnet changes](https://github.com/dotnet/dotnet-docker/issues/4492).
+- Removed windows OS from docker multi-platform image to align with [dotnet changes](https://github.com/dotnet/dotnet-docker/issues/4492).
 - Fixed a bug where the emitted CSharp would not be compatible with netstandad2.0. [#3829](https://github.com/microsoft/kiota/issues/3829)
 - Fixed a bug where import statements for additionalDataHolder and enumSet are missing when BackingStore is enabled in java. [#3643](https://github.com/microsoft/kiota/pull/3643)
 - Fixed an issue where Kiota's regex's might time out. [#3797](https://github.com/microsoft/kiota/issues/3797)
@@ -33,7 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Fixed a bug where property names that matched reserved type would be replaced in dotnet.
 - Fixed pass by value for `contentType` param in Go `requestInfo.SetStreamContentAndContentType`[#3830](https://github.com/microsoft/kiota/issues/3830)
 - Fixed parsing of `DateOnly` values generated in request executors [#3679](https://github.com/microsoft/kiota/issues/3679)
-- Fixes generation of default values names for go contructor functions [#3436](https://github.com/microsoft/kiota/issues/3436)
+- Fixes generation of default values names for go constructor functions [#3436](https://github.com/microsoft/kiota/issues/3436)
 - [Java] Removed the usage of reflection in `ApiClientBuilder` [`kiota-java#923`](https://github.com/microsoft/kiota-java/issues/923)
 
 ## [1.8.2] - 2023-11-08
diff --git a/src/Kiota.Builder/CodeDOM/CodeFile.cs b/src/Kiota.Builder/CodeDOM/CodeFile.cs
index a4e293fe55..dbe9653e1d 100644
--- a/src/Kiota.Builder/CodeDOM/CodeFile.cs
+++ b/src/Kiota.Builder/CodeDOM/CodeFile.cs
@@ -8,6 +8,7 @@ public class CodeFile : CodeBlock<CodeFileDeclaration, CodeFileBlockEnd>
 {
     public IEnumerable<CodeInterface> Interfaces => InnerChildElements.Values.OfType<CodeInterface>().OrderBy(static x => x.Name, StringComparer.Ordinal);
     public IEnumerable<CodeClass> Classes => InnerChildElements.Values.OfType<CodeClass>().OrderBy(static x => x.Name, StringComparer.Ordinal);
+    public IEnumerable<CodeEnum> Enums => InnerChildElements.Values.OfType<CodeEnum>().OrderBy(static x => x.Name, StringComparer.Ordinal);
 
     public IEnumerable<T> AddElements<T>(params T[] elements) where T : CodeElement
     {
@@ -19,8 +20,8 @@ public IEnumerable<T> AddElements<T>(params T[] elements) where T : CodeElement
         return AddRange(elements);
     }
 
-    public IEnumerable<CodeUsing> AllUsingsFromChildElements => GetChildElements()
-        .SelectMany(static x => x.GetChildElements())
+    public IEnumerable<CodeUsing> AllUsingsFromChildElements => GetChildElements(true)
+        .SelectMany(static x => x.GetChildElements(false))
         .OfType<ProprietableBlockDeclaration>()
         .SelectMany(static x => x.Usings);
 }
diff --git a/src/Kiota.Builder/CodeDOM/CodeNamespace.cs b/src/Kiota.Builder/CodeDOM/CodeNamespace.cs
index 60f64ceab1..e6556a0c75 100644
--- a/src/Kiota.Builder/CodeDOM/CodeNamespace.cs
+++ b/src/Kiota.Builder/CodeDOM/CodeNamespace.cs
@@ -35,7 +35,8 @@ public CodeFile TryAddCodeFile(string fileName, params CodeElement[] children)
         var file = FindChildByName<CodeFile>(fileName, false) ?? new CodeFile { Name = fileName };
         RemoveChildElement(children);
         RemoveChildElementByName(fileName);
-        file.AddElements(children);
+        if (children is { Length: > 0 })
+            file.AddElements(children);
 
         if (!file.IsChildOf(this, true))
             AddRange(file);
diff --git a/src/Kiota.Builder/Configuration/GenerationConfiguration.cs b/src/Kiota.Builder/Configuration/GenerationConfiguration.cs
index 7c52185c85..8dc08fb33d 100644
--- a/src/Kiota.Builder/Configuration/GenerationConfiguration.cs
+++ b/src/Kiota.Builder/Configuration/GenerationConfiguration.cs
@@ -83,14 +83,11 @@ public bool ShouldWriteBarrelsIfClassExists
             return BarreledLanguagesWithConstantFileName.Contains(Language);
         }
     }
-    private static readonly HashSet<GenerationLanguage> BarreledLanguages = new(3) {
+    private static readonly HashSet<GenerationLanguage> BarreledLanguages = [
         GenerationLanguage.Ruby,
-        GenerationLanguage.TypeScript,
         GenerationLanguage.Swift,
-    };
-    private static readonly HashSet<GenerationLanguage> BarreledLanguagesWithConstantFileName = new(1) {
-        GenerationLanguage.TypeScript
-    };
+    ];
+    private static readonly HashSet<GenerationLanguage> BarreledLanguagesWithConstantFileName = [];
     public bool CleanOutput
     {
         get; set;
diff --git a/src/Kiota.Builder/PathSegmenters/TypeScriptPathSegmenter.cs b/src/Kiota.Builder/PathSegmenters/TypeScriptPathSegmenter.cs
index e50341bc7c..257186d451 100644
--- a/src/Kiota.Builder/PathSegmenters/TypeScriptPathSegmenter.cs
+++ b/src/Kiota.Builder/PathSegmenters/TypeScriptPathSegmenter.cs
@@ -1,5 +1,4 @@
 ﻿using System;
-using System.Collections.Generic;
 using System.Linq;
 
 using Kiota.Builder.CodeDOM;
@@ -19,7 +18,6 @@ public override string NormalizeFileName(CodeElement currentElement)
         modelsNamespace ??= currentElement.GetImmediateParentOfType<CodeNamespace>()?.GetRootNamespace().FindChildByName<CodeNamespace>($"{ClientNamespaceName}.{GenerationConfiguration.ModelsNamespaceSegmentName}");
         return currentElement switch
         {
-            CodeNamespace => IndexFileName,
             CodeFile currentFile when modelsNamespace is not null &&
                         currentElement.GetImmediateParentOfType<CodeNamespace>() is CodeNamespace currentNamespace &&
                         !(modelsNamespace.IsParentOf(currentNamespace) || modelsNamespace == currentNamespace) &&
@@ -30,12 +28,4 @@ CodeFile currentFile when modelsNamespace is not null &&
     }
     private static string GetDefaultFileName(CodeElement currentElement) => GetLastFileNameSegment(currentElement).ToFirstCharacterLowerCase();
     public override string NormalizeNamespaceSegment(string segmentName) => segmentName.ToFirstCharacterLowerCase();
-    public override IEnumerable<string> GetAdditionalSegment(CodeElement currentElement, string fileName)
-    {
-        return currentElement switch
-        {
-            CodeNamespace => new[] { GetDefaultFileName(currentElement) },// We put barrels inside namespace folders
-            _ => Enumerable.Empty<string>(),
-        };
-    }
 }
diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
index a87b3a90bf..32ab9623e2 100644
--- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
+++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
@@ -153,20 +153,44 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
                 factoryNameCallbackFromType
             );
             ReplacePropertyNames(generatedCode,
-                new() {
+                [
                     CodePropertyKind.Custom,
                     CodePropertyKind.QueryParameter,
-                },
+                ],
                 static s => s.ToCamelCase(UnderscoreArray));
             IntroducesInterfacesAndFunctions(generatedCode, factoryNameCallbackFromType);
             AliasUsingsWithSameSymbol(generatedCode);
             var modelsNamespace = generatedCode.FindOrAddNamespace(_configuration.ModelsNamespaceName); // ensuring we have a models namespace in case we don't have any reusable model
             GenerateReusableModelsCodeFiles(modelsNamespace);
             GenerateRequestBuilderCodeFiles(modelsNamespace);
-            CorrectCodeFileUsing(generatedCode);
+            GroupReusableModelsInSingleFile(modelsNamespace);
+            RemoveSelfReferencingUsings(generatedCode);
             cancellationToken.ThrowIfCancellationRequested();
         }, cancellationToken);
     }
+    private const string FileNameForModels = "index";
+    private static void GroupReusableModelsInSingleFile(CodeElement currentElement)
+    {
+        if (currentElement is CodeNamespace codeNamespace)
+        {
+            var targetFile = codeNamespace.TryAddCodeFile(FileNameForModels);
+            foreach (var otherFile in codeNamespace.Files.Except([targetFile]))
+            {
+                targetFile.AddUsing(otherFile.Usings.ToArray());
+                targetFile.AddElements(otherFile.GetChildElements(true).ToArray());
+                codeNamespace.RemoveChildElement(otherFile);
+            }
+            if (codeNamespace.Enums.ToArray() is { Length: > 0 } enums)
+            {
+                targetFile.AddElements(enums);
+                codeNamespace.RemoveChildElement(enums);
+            }
+            RemoveSelfReferencingUsingForFile(targetFile, codeNamespace);
+            var childElements = targetFile.GetChildElements(true).ToArray();
+            AliasCollidingSymbols(childElements.SelectMany(GetUsingsFromCodeElement).Distinct(), childElements.Select(static x => x.Name).ToHashSet(StringComparer.OrdinalIgnoreCase));
+        }
+        CrawlTree(currentElement, GroupReusableModelsInSingleFile);
+    }
     private void GenerateReusableModelsCodeFiles(CodeElement currentElement)
     {
         if (currentElement.Parent is CodeNamespace codeNamespace && currentElement is CodeInterface codeInterface && codeInterface.IsOfKind(CodeInterfaceKind.Model))
@@ -254,58 +278,65 @@ private static void GenerateRequestBuilderCodeFile(CodeClass codeClass, CodeName
         codeNamespace.TryAddCodeFile(codeClass.Name, elements);
     }
 
-    private static void CorrectCodeFileUsing(CodeElement currentElement)
+    private static IEnumerable<CodeUsing> GetUsingsFromCodeElement(CodeElement codeElement)
     {
-        // if element is a code file eliminate using references to the same file
-        if (currentElement is CodeFile codeFile && codeFile.Parent is CodeNamespace codeNamespace)
+        return codeElement switch
         {
-            // correct the using values
-            // eliminate the using referring the elements in the same file
-
-            var elementSet = codeFile.GetChildElements(true).Select(static x => x.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
-            foreach (var element in codeFile.GetChildElements(true))
+            CodeFunction f => f.StartBlock.Usings,
+            CodeInterface ci => ci.Usings,
+            CodeEnum ce => ce.Usings,
+            CodeClass cc => cc.Usings,
+            _ => Enumerable.Empty<CodeUsing>()
+        };
+    }
+    private static void RemoveSelfReferencingUsingForFile(CodeFile codeFile, CodeNamespace codeNamespace)
+    {
+        // correct the using values
+        // eliminate the using referring the elements in the same file
+        var elementSet = codeFile.GetChildElements(true).Select(static x => x.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
+        var fileElements = codeFile.GetChildElements(true).ToArray();
+        foreach (var element in fileElements)
+        {
+            var foundUsingsNames = GetUsingsFromCodeElement(element)
+                .Select(static x => x.Declaration?.TypeDefinition)
+                .OfType<CodeElement>()
+                .Where(x => x.GetImmediateParentOfType<CodeNamespace>() == codeNamespace)
+                .Where(x => elementSet.Contains(x.Name))
+                .Select(static x => x.Name);
+
+            foreach (var x in foundUsingsNames)
             {
-                var startBlockUsings = element switch
-                {
-                    CodeFunction f => f.StartBlock.Usings,
-                    CodeInterface ci => ci.Usings,
-                    CodeEnum ce => ce.Usings,
-                    CodeClass cc => cc.Usings,
-                    _ => Enumerable.Empty<CodeUsing>()
-                };
-
-                var foundUsingsNames = startBlockUsings
-                    .Select(static x => x.Declaration?.TypeDefinition)
-                    .OfType<CodeElement>()
-                    .Where(x => x.GetImmediateParentOfType<CodeNamespace>() == codeNamespace)
-                    .Where(x => elementSet.Contains(x.Name))
-                    .Select(static x => x.Name);
-
-                foreach (var x in foundUsingsNames)
+                switch (element)
                 {
-                    switch (element)
-                    {
-                        case CodeFunction ci:
-                            ci.RemoveUsingsByDeclarationName(x);
-                            break;
-                        case CodeInterface ci:
-                            ci.RemoveUsingsByDeclarationName(x);
-                            break;
-                        case CodeEnum ci:
-                            ci.RemoveUsingsByDeclarationName(x);
-                            break;
-                        case CodeClass ci:
-                            ci.RemoveUsingsByDeclarationName(x);
-                            break;
-                    }
+                    case CodeFunction ci:
+                        ci.RemoveUsingsByDeclarationName(x);
+                        break;
+                    case CodeInterface ci:
+                        ci.RemoveUsingsByDeclarationName(x);
+                        break;
+                    case CodeEnum ci:
+                        ci.RemoveUsingsByDeclarationName(x);
+                        break;
+                    case CodeClass ci:
+                        ci.RemoveUsingsByDeclarationName(x);
+                        break;
                 }
             }
         }
+    }
+    private static void RemoveSelfReferencingUsings(CodeElement currentElement)
+    {
+        if (currentElement is CodeFile { Parent: CodeNamespace codeNamespace } codeFile)
+            RemoveSelfReferencingUsingForFile(codeFile, codeNamespace);
 
-        CrawlTree(currentElement, CorrectCodeFileUsing);
+        CrawlTree(currentElement, RemoveSelfReferencingUsings);
     }
 
     private static void AliasCollidingSymbols(IEnumerable<CodeUsing> usings, string currentSymbolName)
+    {
+        AliasCollidingSymbols(usings, new HashSet<string>(StringComparer.OrdinalIgnoreCase) { currentSymbolName });
+    }
+    private static void AliasCollidingSymbols(IEnumerable<CodeUsing> usings, HashSet<string> currentSymbolNames)
     {
         var enumeratedUsings = usings.ToArray();
         var duplicatedSymbolsUsings = enumeratedUsings.Where(static x => !x.IsExternal)
@@ -316,9 +347,7 @@ private static void AliasCollidingSymbols(IEnumerable<CodeUsing> usings, string
                                                                 .SelectMany(static x => x)
                                                                 .Union(enumeratedUsings
                                                                         .Where(static x => !x.IsExternal && x.Declaration != null)
-                                                                        .Where(x => x.Declaration!
-                                                                                        .Name
-                                                                                        .Equals(currentSymbolName, StringComparison.OrdinalIgnoreCase)))
+                                                                        .Where(x => currentSymbolNames.Contains(x.Declaration!.Name)))
                                                                 .ToArray();
         foreach (var usingElement in duplicatedSymbolsUsings)
             usingElement.Alias = (usingElement.Declaration
diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
index e0dd329e71..3e0c3bfb00 100644
--- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
@@ -58,7 +58,8 @@ private void WriteDiscriminatorFunction(CodeFunction codeElement, LanguageWriter
     {
         var returnType = conventions.GetTypeString(codeElement.OriginalLocalMethod.ReturnType, codeElement);
 
-        CodeMethodWriter.WriteDefensiveStatements(codeElement.OriginalLocalMethod, writer);
+        if (codeElement.OriginalMethodParentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType)
+            CodeMethodWriter.WriteDefensiveStatements(codeElement.OriginalLocalMethod, writer);
         WriteFactoryMethodBody(codeElement, returnType, writer);
     }
 
diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeNameSpaceWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeNameSpaceWriter.cs
deleted file mode 100644
index 7fc5707858..0000000000
--- a/src/Kiota.Builder/Writers/TypeScript/CodeNameSpaceWriter.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-﻿using System;
-using System.Linq;
-using Kiota.Builder.CodeDOM;
-using Kiota.Builder.Extensions;
-
-namespace Kiota.Builder.Writers.TypeScript;
-public class CodeNameSpaceWriter : BaseElementWriter<CodeNamespace, TypeScriptConventionService>
-{
-    public CodeNameSpaceWriter(TypeScriptConventionService conventionService) : base(conventionService) { }
-
-    /// <summary>
-    /// Writes export statements for classes and enums belonging to a namespace into a generated index.ts file. 
-    /// The classes should be export in the order of inheritance so as to avoid circular dependency issues in javascript.
-    /// </summary>
-    /// <param name="codeElement">Code element is a code namespace</param>
-    /// <param name="writer"></param>
-    public override void WriteCodeElement(CodeNamespace codeElement, LanguageWriter writer)
-    {
-        ArgumentNullException.ThrowIfNull(codeElement);
-        ArgumentNullException.ThrowIfNull(writer);
-        writer.WriteLines(codeElement.Enums
-                                    .Concat<CodeElement>(codeElement.Functions)
-                                    .Concat(codeElement.Interfaces)
-                                    .Concat(codeElement.Files)
-                                    .OrderBy(static x => x is CodeEnum ? 0 : 1)
-                                    .ThenBy(static x => x.Name, StringComparer.OrdinalIgnoreCase)
-                                    .Select(static x => x.Name.ToFirstCharacterLowerCase())
-                                    .Select(static x => $"export * from './{x}'"));
-    }
-}
diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptRelativeImportManager.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptRelativeImportManager.cs
index e7110c9905..e88efbb56b 100644
--- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptRelativeImportManager.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptRelativeImportManager.cs
@@ -1,13 +1,10 @@
-﻿using System;
-using Kiota.Builder.CodeDOM;
-using Kiota.Builder.Configuration;
+﻿using Kiota.Builder.CodeDOM;
 using Kiota.Builder.Extensions;
 
 namespace Kiota.Builder.Writers.TypeScript;
 public class TypescriptRelativeImportManager : RelativeImportManager
 
 {
-    private CodeNamespace? modelsNamespace;
     public TypescriptRelativeImportManager(string namespacePrefix, char namespaceSeparator) : base(namespacePrefix, namespaceSeparator)
     {
     }
@@ -32,27 +29,6 @@ public override (string, string, string) GetRelativeImportPathForUsing(CodeUsing
             return (importSymbol, codeUsing.Alias, "./"); // it's relative to the folder, with no declaration (default failsafe)
         var importNamespace = typeDef.GetImmediateParentOfType<CodeNamespace>();
         var importPath = GetImportRelativePathFromNamespaces(currentNamespace, importNamespace);
-        var isCodeUsingAModel = codeUsing.Declaration?.TypeDefinition is CodeClass codeClass && codeClass.IsOfKind(CodeClassKind.Model);
-        modelsNamespace ??= currentNamespace.GetRootNamespace().FindChildByName<CodeNamespace>($"{prefix}.{GenerationConfiguration.ModelsNamespaceSegmentName}");
-        if ("./".Equals(importPath, StringComparison.OrdinalIgnoreCase) && isCodeUsingAModel)
-        {
-            importPath += "index";
-        }
-        else if (string.IsNullOrEmpty(importPath))
-            importPath += codeUsing.Name;
-        else if (!isCodeUsingAModel && (modelsNamespace is null || modelsNamespace.IsParentOf(importNamespace) || modelsNamespace == importNamespace))
-        {
-            var nameSpaceName = string.IsNullOrEmpty(codeUsing.Declaration?.Name) ? codeUsing.Name : codeUsing.Declaration.Name;
-            if (codeUsing.Declaration?.TypeDefinition?.GetImmediateParentOfType<CodeNamespace>()?
-                    .FindChildByName<CodeElement>(nameSpaceName)?.Parent is CodeFile f)
-            {
-                importPath += f.Name.ToFirstCharacterLowerCase();
-            }
-            else
-            {
-                importPath += (!string.IsNullOrEmpty(codeUsing.Declaration?.TypeDefinition?.Name) ? codeUsing.Declaration.TypeDefinition.Name : codeUsing.Declaration?.Name).ToFirstCharacterLowerCase();
-            }
-        }
         return (importSymbol, codeUsing.Alias, importPath);
     }
 }
diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs
index 611196461e..ea6306f2f0 100644
--- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs
@@ -15,7 +15,6 @@ public TypeScriptWriter(string rootPath, string clientNamespaceName, bool usesBa
         AddOrReplaceCodeElementWriter(new CodeFunctionWriter(conventionService, clientNamespaceName));
         AddOrReplaceCodeElementWriter(new CodePropertyWriter(conventionService));
         AddOrReplaceCodeElementWriter(new CodeTypeWriter(conventionService));
-        AddOrReplaceCodeElementWriter(new CodeNameSpaceWriter(conventionService));
         AddOrReplaceCodeElementWriter(new CodeInterfaceDeclarationWriter(conventionService, clientNamespaceName));
         AddOrReplaceCodeElementWriter(new CodeFileBlockEndWriter(conventionService));
         AddOrReplaceCodeElementWriter(new CodeFileDeclarationWriter(conventionService, clientNamespaceName));


Test patch:
diff --git a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs
index ab72ef6fd9..e432369a52 100644
--- a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs
+++ b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs
@@ -242,9 +242,10 @@ public async Task AddsUsingsForErrorTypesForRequestExecutor()
     public async Task EscapesReservedKeywords()
     {
         var generationConfiguration = new GenerationConfiguration { Language = GenerationLanguage.TypeScript };
-        var model = TestHelper.CreateModelClassInModelsNamespace(generationConfiguration, root, "break");
+        TestHelper.CreateModelClassInModelsNamespace(generationConfiguration, root, "break");
         await ILanguageRefiner.Refine(generationConfiguration, root);
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
         var interFaceModel = codeFile.Interfaces.First(x => "BreakEscaped".Equals(x.Name, StringComparison.Ordinal));
         Assert.NotEqual("break", interFaceModel.Name);
@@ -352,7 +353,8 @@ public async Task CorrectsCoreType()
 
         await ILanguageRefiner.Refine(generationConfiguration, root);
 
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
 
         var interFaceModel = codeFile.Interfaces.First(x => x.Name == model.Name.ToFirstCharacterUpperCase());
@@ -387,7 +389,8 @@ public async Task ReplacesDateTimeOffsetByNativeType()
         }).First();
         await ILanguageRefiner.Refine(generationConfiguration, root);
 
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
         var modelInterface = codeFile.Interfaces.First(x => x.Name == model.Name.ToFirstCharacterUpperCase());
         Assert.NotEmpty(modelInterface.StartBlock.Usings);
@@ -409,7 +412,8 @@ public async Task ReplacesGuidsByRespectiveType()
         }).First();
         await ILanguageRefiner.Refine(generationConfiguration, root);
 
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
         var modelInterface = codeFile.Interfaces.First(x => x.Name.Equals(model.Name, StringComparison.OrdinalIgnoreCase));
         Assert.NotEmpty(modelInterface.StartBlock.Usings);
@@ -431,7 +435,8 @@ public async Task ReplacesDateOnlyByNativeType()
         }).First();
         await ILanguageRefiner.Refine(generationConfiguration, root);
         Assert.NotEmpty(model.StartBlock.Usings);
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
         var modelInterface = codeFile.Interfaces.First(x => x.Name == model.Name.ToFirstCharacterUpperCase());
         Assert.NotEmpty(modelInterface.StartBlock.Usings);
@@ -453,13 +458,15 @@ public async Task ReplacesTimeOnlyByNativeType()
         await ILanguageRefiner.Refine(generationConfiguration, root);
         Assert.NotEmpty(model.StartBlock.Usings);
 
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
         var modelInterface = codeFile.Interfaces.First(x => x.Name == model.Name.ToFirstCharacterUpperCase());
         Assert.NotEmpty(modelInterface.StartBlock.Usings);
         Assert.Equal("TimeOnly", modelInterface.Properties.First(x => x.Name == codeProperty.Name).Type.Name);
 
     }
+    private const string IndexFileName = "index";
     [Fact]
     public async Task ReplacesDurationByNativeType()
     {
@@ -475,7 +482,8 @@ public async Task ReplacesDurationByNativeType()
         }).First();
         await ILanguageRefiner.Refine(generationConfiguration, root);
         Assert.NotEmpty(model.StartBlock.Usings);
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
         var modelInterface = codeFile.Interfaces.First(x => x.Name == model.Name.ToFirstCharacterUpperCase());
         Assert.NotEmpty(modelInterface.StartBlock.Usings);
@@ -561,26 +569,14 @@ public async Task AliasesDuplicateUsingSymbols()
         model.AddUsing(using2);
         await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, root);
 
-        var modelCodeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelCodeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(modelCodeFile);
         var modelInterface = modelCodeFile.Interfaces.First(x => x.Name == model.Name.ToFirstCharacterUpperCase());
+        var source1Interface = modelCodeFile.Interfaces.First(x => x.Name == source1.Name.ToFirstCharacterUpperCase());
+        var source2Interface = modelCodeFile.Interfaces.First(x => x.Name == source2.Name.ToFirstCharacterUpperCase());
 
-        var source1CodeFile = modelsNS.FindChildByName<CodeFile>(source1.Name.ToFirstCharacterUpperCase());
-        Assert.NotNull(source1CodeFile);
-        var source1Interface = source1CodeFile.Interfaces.First(x => x.Name == source1.Name.ToFirstCharacterUpperCase());
-
-        var source2CodeFile = submodelsNS.FindChildByName<CodeFile>(source2.Name.ToFirstCharacterUpperCase());
-        Assert.NotNull(source2CodeFile);
-        var source2Interface = source2CodeFile.Interfaces.First(x => x.Name == source2.Name.ToFirstCharacterUpperCase());
-
-        var modelUsing1 = modelInterface.Usings.First(x => x.Declaration?.TypeDefinition == source2Interface);
-        var modelUsing2 = modelInterface.Usings.First(x => x.Declaration?.TypeDefinition == source1Interface);
-        Assert.NotNull(modelUsing1.Declaration);
-        Assert.NotNull(modelUsing2.Declaration);
-        Assert.Equal(modelUsing1.Declaration.Name, modelUsing2.Declaration.Name);
-        Assert.NotEmpty(modelUsing1.Alias);
-        Assert.NotEmpty(modelUsing2.Alias);
-        Assert.NotEqual(modelUsing1.Alias, modelUsing2.Alias);
+        Assert.Empty(modelInterface.Usings.Where(x => x.Declaration?.TypeDefinition == source2Interface));
+        Assert.Empty(modelInterface.Usings.Where(x => x.Declaration?.TypeDefinition == source1Interface));
     }
     [Fact]
     public async Task DoesNotKeepCancellationParametersInRequestExecutors()
@@ -620,11 +616,12 @@ public async Task DoesNotKeepCancellationParametersInRequestExecutors()
     public async Task AddsModelInterfaceForAModelClass()
     {
         var generationConfiguration = new GenerationConfiguration { Language = GenerationLanguage.TypeScript };
-        var model = TestHelper.CreateModelClassInModelsNamespace(generationConfiguration, root, "modelA");
+        TestHelper.CreateModelClassInModelsNamespace(generationConfiguration, root, "modelA");
 
         await ILanguageRefiner.Refine(generationConfiguration, root);
 
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile);
         Assert.Contains(codeFile.Interfaces, static x => "ModelA".Equals(x.Name, StringComparison.OrdinalIgnoreCase));
     }
@@ -778,7 +775,8 @@ public async Task GeneratesCodeFiles()
 
         await ILanguageRefiner.Refine(generationConfiguration, root);
 
-        var codeFile = root.FindChildByName<CodeFile>(model.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindNamespaceByName(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>(IndexFileName, false);
         Assert.NotNull(codeFile); // codefile exists
 
         // model , interface, deserializer, serializer should be direct descendant of the codefile
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs
index 8414aacf81..a4d5c536ef 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFileWriterTests.cs
@@ -52,7 +52,8 @@ public async Task WritesAutoGenerationStart()
         var parentClass = TestHelper.CreateModelClassInModelsNamespace(generationConfiguration, root, "parentClass", true);
         TestHelper.AddSerializationPropertiesToModelClass(parentClass);
         await ILanguageRefiner.Refine(generationConfiguration, root);
-        var codeFile = root.FindChildByName<CodeFile>(parentClass.Name.ToFirstCharacterUpperCase());
+        var modelsNS = root.FindChildByName<CodeNamespace>(generationConfiguration.ModelsNamespaceName);
+        var codeFile = modelsNS.FindChildByName<CodeFile>("index", false);
         WriteCode(writer, codeFile);
 
         var result = tw.ToString();
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeNamespaceWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeNamespaceWriterTests.cs
deleted file mode 100644
index a30d0b8a7e..0000000000
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeNamespaceWriterTests.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-﻿using System;
-using System.IO;
-
-using Kiota.Builder.CodeDOM;
-using Kiota.Builder.Writers;
-
-using Xunit;
-
-namespace Kiota.Builder.Tests.Writers.TypeScript;
-public sealed class CodeNameSpaceWriterTests : IDisposable
-{
-    private const string DefaultPath = "./";
-    private const string DefaultName = "name";
-    private readonly StringWriter tw;
-    private readonly LanguageWriter writer;
-
-    public CodeNameSpaceWriterTests()
-    {
-        writer = LanguageWriter.GetLanguageWriter(GenerationLanguage.TypeScript, DefaultPath, DefaultName);
-        tw = new StringWriter();
-        writer.SetTextWriter(tw);
-    }
-
-    public void Dispose()
-    {
-        tw?.Dispose();
-        GC.SuppressFinalize(this);
-    }
-
-    [Fact]
-    public void ExportsInterfacesAndFunctions()
-    {
-        var root = CodeNamespace.InitRootNamespace();
-        var modelInterface = new CodeInterface
-        {
-            Name = "ModelInterface",
-            Kind = CodeInterfaceKind.Model
-        };
-        var modelEnum = new CodeEnum
-        {
-            Name = "TestEnum", // The tests should verify if the printed file names start with lower case.
-        };
-        root.AddEnum(modelEnum);
-        root.AddInterface(modelInterface);
-        writer.Write(root);
-        var result = tw.ToString();
-        Console.WriteLine(result);
-        Assert.Contains($"export * from './testEnum'{Environment.NewLine}export * from './modelInterface'{Environment.NewLine}", result);
-    }
-
-}
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScriptRelativeImportManagerTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScriptRelativeImportManagerTests.cs
index 85567ea73e..9dbaa393dc 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScriptRelativeImportManagerTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScriptRelativeImportManagerTests.cs
@@ -44,7 +44,7 @@ public void ReplacesImportsSubNamespace()
         };
         declaration.AddUsings(nUsing);
         var result = importManager.GetRelativeImportPathForUsing(nUsing, graphNS);
-        Assert.Equal("./messages/message", result.Item3);
+        Assert.Equal("./messages/", result.Item3);
     }
     [Fact]
     public void ReplacesImportsParentNamespace()
@@ -118,8 +118,8 @@ public void ReplacesImportsInOtherTrunk()
         declaration2.AddUsings(nUsing2);
         var result = importManager.GetRelativeImportPathForUsing(nUsing, usedRangeNS1);
         var result2 = importManager.GetRelativeImportPathForUsing(nUsing2, usedRangeNS2);
-        Assert.Equal("../../../../workbookRange", result.Item3);
-        Assert.Equal("../../workbookRange", result2.Item3);
+        Assert.Equal("../../../../", result.Item3);
+        Assert.Equal("../../", result2.Item3);
     }
     [Fact]
     public void ReplacesImportsSameNamespace()
@@ -141,7 +141,7 @@ public void ReplacesImportsSameNamespace()
         };
         declaration.AddUsings(nUsing);
         var result = importManager.GetRelativeImportPathForUsing(nUsing, graphNS);
-        Assert.Equal("./message", result.Item3);
+        Assert.Equal("./", result.Item3);
     }
 
     [Fact]
@@ -165,6 +165,6 @@ public void ReplacesImportsSameNamespaceIndex()
         };
         declaration.AddUsings(nUsing);
         var result = importManager.GetRelativeImportPathForUsing(nUsing, graphNS);
-        Assert.Equal("./index", result.Item3);
+        Assert.Equal("./", result.Item3);
     }
 }