Skip to content

Commit

Permalink
Merge pull request #3863 from microsoft/feature/ts-group-models
Browse files Browse the repository at this point in the history
feature/ts group models
  • Loading branch information
baywet authored Dec 7, 2023
2 parents d4514e2 + 5c6c593 commit 914c027
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 210 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions src/Kiota.Builder/CodeDOM/CodeFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Kiota.Builder/CodeDOM/CodeNamespace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 3 additions & 6 deletions src/Kiota.Builder/Configuration/GenerationConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 0 additions & 10 deletions src/Kiota.Builder/PathSegmenters/TypeScriptPathSegmenter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Kiota.Builder.CodeDOM;
Expand All @@ -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) &&
Expand All @@ -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>(),
};
}
}
123 changes: 76 additions & 47 deletions src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
30 changes: 0 additions & 30 deletions src/Kiota.Builder/Writers/TypeScript/CodeNameSpaceWriter.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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)
{
}
Expand All @@ -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);
}
}
Loading

0 comments on commit 914c027

Please sign in to comment.