Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for composed types in Typescript #4602

Merged
merged 162 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 118 commits
Commits
Show all changes
162 commits
Select commit Hold shift + click to select a range
b6644d4
initial commit for composed types implementation for typescript
koros Apr 26, 2024
43a7efb
Merge branch 'main' into feature/typescript/composed-types
koros May 2, 2024
1aa3a62
use inline declaration of composed types instead of wrapper types
koros May 3, 2024
bc9b323
Merge branch 'main' into feature/typescript/composed-types
koros May 3, 2024
11a33f0
serialize primitive union types
koros May 7, 2024
a57dc2f
Merge branch 'main' into feature/typescript/composed-types
koros May 8, 2024
87518d2
finished adding support for composed types comprised of union of prim…
koros May 9, 2024
67c2872
use more meaningful naming & semantics
koros May 10, 2024
5225bdb
refactor large methods
koros May 13, 2024
507db72
Merge branch 'main' into feature/typescript/composed-types
koros May 13, 2024
99650f1
unit test for TypescriptRefiner
koros May 13, 2024
2d88aa8
ad dopen api test file
koros May 13, 2024
442532f
unit tests for Typescript refiner
koros May 14, 2024
a7e3102
Merge branch 'main' into feature/typescript/composed-types
koros May 14, 2024
55d9a66
Merge branch 'main' into feature/typescript/composed-types
koros May 15, 2024
bec7828
test coverage - cover all cases
koros May 15, 2024
325fcab
minor cleanup refactor for TypeScript/CodeFunctionWriter.cs
koros May 16, 2024
d2782ad
access the conventions service from static context
koros May 16, 2024
dfe28b1
move the method to get factory name to the conventions service
koros May 16, 2024
6a07f54
Merge branch 'main' into feature/typescript/composed-types
koros May 16, 2024
75022fc
refactor composed type to use specific writers
koros May 16, 2024
5c43b9d
increase coverage
koros May 17, 2024
7b3a92a
increase code coverage
koros May 17, 2024
4f36114
Merge branch 'main' into feature/typescript/composed-types
koros May 17, 2024
663798e
handle union of objects in typescript
koros May 21, 2024
9385ac0
Merge branch 'main' into feature/typescript/composed-types
koros May 21, 2024
8c6e25b
remove unused code
koros May 21, 2024
5e41e0d
add serialization for union objects
koros May 22, 2024
3814a86
Merge branch 'main' into feature/typescript/composed-types
koros May 22, 2024
15a5140
fix failing test and improve coverage
koros May 22, 2024
9b27708
add pets union test yml file
koros May 22, 2024
d61a5be
remove unused parameter
koros May 23, 2024
9a9d267
Merge branch 'main' into feature/typescript/composed-types
koros May 23, 2024
f44220b
retrieve serialization method correctly
koros May 28, 2024
39648b6
Merge branch 'main' into feature/typescript/composed-types
koros May 28, 2024
14ee8cb
rectify the serilaization function for CodeUnion types
koros May 29, 2024
b1086de
Merge branch 'main' into feature/typescript/composed-types
koros May 29, 2024
2f2d855
**allow primitive intersection types as per existing yml test file
koros May 29, 2024
615b3fa
typescript: add support for intersection type objects
koros May 29, 2024
ae857c5
fix primitive intersection bug
koros May 30, 2024
6084d07
refactor the factory method for primitive composed type values
koros Jun 5, 2024
dc7592b
Merge branch 'main' into feature/typescript/composed-types
koros Jun 5, 2024
35b6120
removed unused import statement
koros Jun 7, 2024
d8d3145
Merge branch 'main' into feature/typescript/composed-types
koros Jun 7, 2024
b5baad2
inline composed types
koros Jun 7, 2024
9d20950
Merge branch 'main' into feature/typescript/composed-types
koros Jun 7, 2024
37e78fa
remove unused param
koros Jun 7, 2024
5688854
fix sonar warnings
koros Jun 7, 2024
d101bf9
format code
koros Jun 7, 2024
f71be97
address pr comments
koros Jun 10, 2024
4a7c5da
Merge branch 'main' into feature/typescript/composed-types
koros Jun 10, 2024
84b8792
adress pr comments
koros Jun 12, 2024
c247ea1
address pr comments
koros Jun 12, 2024
9cb0f84
address pr comments
koros Jun 12, 2024
73517d0
Merge branch 'main' into feature/typescript/composed-types
koros Jun 12, 2024
dba8f83
address pr coments
koros Jun 12, 2024
2966b66
format code
koros Jun 12, 2024
8c52767
address pr comments
koros Jun 12, 2024
1f82494
increase test coverage
koros Jun 12, 2024
16d848c
increase test coverage
koros Jun 12, 2024
4507925
Merge branch 'main' into feature/typescript/composed-types
koros Jun 12, 2024
c86251d
address pr comments
koros Jun 13, 2024
8b5615e
Merge branch 'main' into feature/typescript/composed-types
koros Jun 13, 2024
111b0e1
address pr comments
koros Jun 13, 2024
8f0f5d6
address pr comments
koros Jun 13, 2024
cc2e34b
address pr comments
koros Jun 13, 2024
b3e5655
remove reference to external urls on tests
koros Jun 14, 2024
8c26bde
Merge branch 'main' into feature/typescript/composed-types
koros Jun 14, 2024
c42969c
Merge branch 'main' into feature/typescript/composed-types
koros Jun 18, 2024
8eddb41
simplify open api sample test files
koros Jun 18, 2024
b9b5474
Merge branch 'main' into feature/typescript/composed-types
koros Jun 18, 2024
5ba007c
address pr comments
koros Jun 20, 2024
719082b
Merge branch 'main' into feature/typescript/composed-types
koros Jun 20, 2024
9665e19
address pr comments, format code
koros Jun 20, 2024
63abe19
address pr comments
koros Jun 20, 2024
edf1a7f
fix failing test
koros Jun 20, 2024
d334d4c
address pr comments
koros Jun 21, 2024
3ecff4e
format code
koros Jun 21, 2024
57d4253
Merge branch 'main' into feature/typescript/composed-types
koros Jun 21, 2024
ca06ae9
apply pr suggestion to other places for consistency
koros Jun 21, 2024
448a4e1
Merge branch 'main' into feature/typescript/composed-types
koros Jun 21, 2024
d75489a
Merge branch 'main' into feature/typescript/composed-types
koros Jun 24, 2024
8a6922f
Merge branch 'main' into feature/typescript/composed-types
koros Jun 25, 2024
799b0d6
enable supressed typescript tests
koros Jun 25, 2024
fc8e892
allow generation to constinue when the discriminator property is missing
koros Jun 25, 2024
89b5a87
fix failing it tests
koros Jun 25, 2024
9797869
fix it test compilation error 'parseNode' is possibly 'undefined' for…
koros Jun 25, 2024
a818bda
Merge branch 'main' into feature/typescript/composed-types
koros Jun 26, 2024
1b8cb7e
fix failing test
koros Jun 26, 2024
f62886a
fix failing it test
koros Jun 26, 2024
ce4b4a1
ignore null default values
koros Jun 26, 2024
1df1e8f
ignore 'null' default values
koros Jun 26, 2024
6df873d
omit null from default values while serializing
koros Jun 26, 2024
9b0f3eb
exclude apisguru::stripe.com integration test from running since it c…
koros Jun 26, 2024
d3e9bb0
address pr comments
koros Jun 27, 2024
83b8bb8
Merge branch 'main' into feature/typescript/composed-types
koros Jun 27, 2024
e4b1f2d
format code
koros Jun 27, 2024
4787e3b
fix sonar warnings
koros Jun 27, 2024
881f0dd
search for factory function using namespace only
koros Jun 28, 2024
fe5ac63
use a more meaningful method name
koros Jul 1, 2024
26abee4
Merge branch 'main' into feature/typescript/composed-types
koros Jul 1, 2024
7a662c4
appply pr suggestion
koros Jul 1, 2024
8fefc3b
refactor code remove new enum values
koros Jul 3, 2024
1de703d
format code
koros Jul 3, 2024
d5bf8a7
remove unused parameters
koros Jul 3, 2024
af80621
fix compilation issue
koros Jul 3, 2024
681b900
remove unused deserializer
koros Jul 3, 2024
a17523a
simplify statement
koros Jul 3, 2024
2575217
Merge branch 'main' into feature/typescript/composed-types
koros Jul 3, 2024
02d880b
apply pr review suggestions
koros Jul 4, 2024
997a64f
Merge branch 'main' into feature/typescript/composed-types
koros Jul 4, 2024
cb60924
Merge branch 'main' into feature/typescript/composed-types
koros Jul 15, 2024
90f681a
Merge branch 'main' into feature/typescript/composed-types
koros Jul 16, 2024
8d1278e
remove unused parameter
koros Jul 16, 2024
c054766
Merge branch 'main' into feature/typescript/composed-types
koros Jul 16, 2024
a0ceb85
Merge branch 'main' into feature/typescript/composed-types
koros Jul 22, 2024
04a4178
use | symbol for code intersection in typescript
koros Jul 23, 2024
9d4e679
Merge branch 'main' into feature/typescript/composed-types
koros Jul 23, 2024
33becc4
move composed-type utility method to extensions
koros Jul 23, 2024
4dec28d
remove CodeComposedTypeBase extension class
koros Jul 23, 2024
515c872
use Nullish Coalescing Operator ?? over logical or ||
koros Jul 23, 2024
6cd579d
handle edge cases for composed types - Union of objects and primitive…
koros Jul 29, 2024
5072ec6
format code
koros Jul 29, 2024
4fdd941
remove unused code in CodeMethod.cs
koros Jul 29, 2024
a9ecd07
Merge branch 'main' into feature/typescript/composed-types
koros Jul 29, 2024
0cb4684
delete unused method
koros Jul 29, 2024
fc32d31
import all associated deserializers for composed types
koros Jul 30, 2024
83f95bf
remove collection symbol for composed type param in serailizer and de…
koros Aug 1, 2024
40c226f
handle endge cases where composed type is a mix of objects and/or arr…
koros Aug 5, 2024
f31bad4
fix casing
koros Aug 5, 2024
9a34c23
add serialization functions to obsolete class definitions to prevent …
koros Aug 6, 2024
c725e83
use correct serialization method for composed type collection
koros Aug 6, 2024
1d7937b
improve code coverage
koros Aug 6, 2024
04cd4d6
Merge branch 'main' of github.com:microsoft/kiota into feature/typesc…
rkodev Aug 19, 2024
d6953fb
Refactor composed types
rkodev Aug 19, 2024
ed4888d
fix: null check on composed types
rkodev Aug 19, 2024
a69e620
fix: type casting
rkodev Aug 19, 2024
69a6c1a
Fix serialization
rkodev Aug 20, 2024
305b01b
Fix serialization with differenterent types
rkodev Aug 21, 2024
429d1a9
Fixes import collition for types
rkodev Aug 22, 2024
b6ac6b3
Fix import types
rkodev Aug 23, 2024
4a5c2c3
Merge branch 'main' into feature/typescript/composed-types
rkodev Aug 23, 2024
fbdb569
Fix import
rkodev Aug 26, 2024
940017e
Fix unit tests
rkodev Aug 26, 2024
9ef966b
minor refactr
rkodev Aug 27, 2024
2b7f992
Find correct function
rkodev Aug 27, 2024
af4a934
fix: formatting
rkodev Aug 27, 2024
c5a4ce1
fix: unit tests
rkodev Aug 27, 2024
3c8c85b
fix: tests
rkodev Aug 27, 2024
1d69c3c
format code
rkodev Aug 27, 2024
fc5bbb9
rafactor: reduce code complexity
rkodev Aug 27, 2024
5ca3aa9
fix: String as value
rkodev Aug 27, 2024
68aefac
Merge branch 'main' into feature/typescript/composed-types
rkodev Aug 27, 2024
08469bf
feat: add unit tests
rkodev Aug 27, 2024
6ef11d5
code cleanup
rkodev Aug 28, 2024
527c700
sonar cleanup
rkodev Aug 28, 2024
7cc8f44
Merge branch 'main' into feature/typescript/composed-types
rkodev Aug 28, 2024
41efaf3
Merge branch 'main' into feature/typescript/composed-types
rkodev Aug 29, 2024
3bb9d6d
fix: compilation errors from main branch
rkodev Aug 29, 2024
d4c29c2
Update src/Kiota.Builder/CodeDOM/CodeComposedTypeBase.cs
baywet Aug 29, 2024
bbee168
fix: typo
baywet Aug 29, 2024
0b5128f
Merge branch 'main' into feature/typescript/composed-types
rkodev Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 1 addition & 25 deletions it/config.json
andrueastman marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@
}
],
"Suppressions": [
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
},
{
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/1816"
Expand Down Expand Up @@ -156,10 +152,6 @@
"Language": "go",
"Rationale": "https://github.com/microsoft/kiota/issues/3436"
},
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
},
{
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/2484"
Expand All @@ -170,10 +162,6 @@
}
],
"IdempotencySuppressions": [
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
}
]
},
"apisguru::twilio.com:api": {
Expand Down Expand Up @@ -248,7 +236,7 @@
"Suppressions": [
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
"Rationale": "This document includes an intersection between objects and primitive values, which is not supported in the TypeScript language and results in compilation errors."
baywet marked this conversation as resolved.
Show resolved Hide resolved
},
{
"Language": "go",
Expand Down Expand Up @@ -280,10 +268,6 @@
"Language": "python",
"Rationale": "https://github.com/microsoft/kiota/issues/2842"
},
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
},
{
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/1816"
Expand Down Expand Up @@ -312,20 +296,12 @@
},
"apisguru::twitter.com:current": {
"Suppressions": [
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
},
{
"Language": "ruby",
"Rationale": "https://github.com/microsoft/kiota/issues/1816"
}
],
"IdempotencySuppressions": [
{
"Language": "typescript",
"Rationale": "https://github.com/microsoft/kiota/issues/1812"
}
]
},
"apisguru::apis.guru": {
Expand Down
21 changes: 21 additions & 0 deletions src/Kiota.Builder/CodeDOM/CodeMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,27 @@
method.AddParameter(parameter);
return method;
}
public static CodeMethod FromCodeFunctionAndInterface(CodeInterface codeInterface, CodeFunction function, CodeMethodKind kind)
{
ArgumentNullException.ThrowIfNull(codeInterface);
ArgumentNullException.ThrowIfNull(function);
ArgumentNullException.ThrowIfNull(kind);
var method = new CodeMethod
{
Name = function.OriginalLocalMethod.Name,
ReturnType = function.OriginalLocalMethod.ReturnType,
Kind = kind,
Access = function.OriginalLocalMethod.Access,
IsAsync = function.OriginalLocalMethod.IsAsync,
IsStatic = function.OriginalLocalMethod.IsStatic,
Documentation = function.OriginalLocalMethod.Documentation,
Parent = codeInterface.OriginalClass,
};

method.AddParameter(function.OriginalLocalMethod.Parameters.ToArray());

return method;
}
public HttpMethod? HttpMethod
{
get; set;
Expand Down Expand Up @@ -345,7 +366,7 @@

public void AddParameter(params CodeParameter[] methodParameters)
{
if (methodParameters == null || methodParameters.Any(static x => x == null))

Check warning on line 369 in src/Kiota.Builder/CodeDOM/CodeMethod.cs

View workflow job for this annotation

GitHub Actions / Build

Collection-specific "Exists" method should be used instead of the "Any" extension. (https://rules.sonarsource.com/csharp/RSPEC-6605)

Check warning on line 369 in src/Kiota.Builder/CodeDOM/CodeMethod.cs

View workflow job for this annotation

GitHub Actions / Build

Collection-specific "Exists" method should be used instead of the "Any" extension. (https://rules.sonarsource.com/csharp/RSPEC-6605)
throw new ArgumentNullException(nameof(methodParameters));
if (methodParameters.Length == 0)
throw new ArgumentOutOfRangeException(nameof(methodParameters));
Expand Down
161 changes: 140 additions & 21 deletions src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,30 @@
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Configuration;
using Kiota.Builder.Extensions;
using static Kiota.Builder.Writers.TypeScript.TypeScriptConventionService;

namespace Kiota.Builder.Refiners;
public class TypeScriptRefiner : CommonLanguageRefiner, ILanguageRefiner
public class TypeScriptRefiner(GenerationConfiguration configuration) : CommonLanguageRefiner(configuration), ILanguageRefiner
{
public static readonly string BackingStoreEnabledKey = "backingStoreEnabled";
public TypeScriptRefiner(GenerationConfiguration configuration) : base(configuration) { }

public override Task Refine(CodeNamespace generatedCode, CancellationToken cancellationToken)
{
return Task.Run(() =>
{
cancellationToken.ThrowIfCancellationRequested();
DeduplicateErrorMappings(generatedCode);
RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlConstructor, CodeMethodKind.RawUrlBuilder);
// Invoke the ConvertUnionTypesToWrapper method to maintain a consistent CodeDOM structure.
// Note that in the later stages, specifically within the GenerateModelCodeFile() function, the introduced wrapper interface is disregarded.
// Instead, a ComposedType is created, which has its own writer, along with the associated Factory, Serializer, and Deserializer functions
// that are incorporated into the CodeFile.
ConvertUnionTypesToWrapper(
baywet marked this conversation as resolved.
Show resolved Hide resolved
generatedCode,
_configuration.UsesBackingStore,
s => s.ToFirstCharacterLowerCase(),
false
);
ReplaceReservedNames(generatedCode, new TypeScriptReservedNamesProvider(), static x => $"{x}Escaped");
ReplaceReservedExceptionPropertyNames(generatedCode, new TypeScriptExceptionsReservedNamesProvider(), static x => $"{x}Escaped");
MoveRequestBuilderPropertiesToBaseType(generatedCode,
Expand Down Expand Up @@ -250,20 +261,128 @@ parentNamespace.Parent is CodeNamespace parentLevelNamespace &&

private static CodeFile? GenerateModelCodeFile(CodeInterface codeInterface, CodeNamespace codeNamespace)
{
var functions = codeNamespace.GetChildElements(true).OfType<CodeFunction>().Where(codeFunction =>
codeFunction.OriginalLocalMethod.Kind is CodeMethodKind.Deserializer or CodeMethodKind.Serializer &&
codeFunction.OriginalLocalMethod.Parameters
.Any(x => x.Type.Name.Equals(codeInterface.Name, StringComparison.OrdinalIgnoreCase)) ||

codeFunction.OriginalLocalMethod.Kind is CodeMethodKind.Factory &&
codeInterface.Name.EqualsIgnoreCase(codeFunction.OriginalMethodParentClass.Name) &&
codeFunction.OriginalMethodParentClass.IsChildOf(codeNamespace)
).ToArray();
var functions = GetSerializationAndFactoryFunctions(codeInterface, codeNamespace).ToArray();

if (functions.Length == 0)
return null;
return codeNamespace.TryAddCodeFile(codeInterface.Name, [codeInterface, .. functions]);

var composedType = GetOriginalComposedType(codeInterface);
var elements = composedType is null ? new List<CodeElement> { codeInterface }.Concat(functions) : GetCodeFileElementsForComposedType(codeInterface, codeNamespace, composedType, functions);

return codeNamespace.TryAddCodeFile(codeInterface.Name, elements.ToArray());
}

private static IEnumerable<CodeFunction> GetSerializationAndFactoryFunctions(CodeInterface codeInterface, CodeNamespace codeNamespace)
{
return codeNamespace.GetChildElements(true)
.OfType<CodeFunction>()
.Where(codeFunction =>
IsDeserializerOrSerializerFunction(codeFunction, codeInterface) ||
IsFactoryFunction(codeFunction, codeInterface, codeNamespace));
}

private static bool IsDeserializerOrSerializerFunction(CodeFunction codeFunction, CodeInterface codeInterface)
{
return codeFunction.OriginalLocalMethod.Kind is CodeMethodKind.Deserializer or CodeMethodKind.Serializer &&
codeFunction.OriginalLocalMethod.Parameters.Any(x => x.Type is CodeType codeType && codeType.TypeDefinition == codeInterface);
}

private static bool IsFactoryFunction(CodeFunction codeFunction, CodeInterface codeInterface, CodeNamespace codeNamespace)
{
return codeFunction.OriginalLocalMethod.Kind is CodeMethodKind.Factory &&
codeInterface.Name.EqualsIgnoreCase(codeFunction.OriginalMethodParentClass.Name) &&
codeFunction.OriginalMethodParentClass.IsChildOf(codeNamespace);
}

private static List<CodeElement> GetCodeFileElementsForComposedType(CodeInterface codeInterface, CodeNamespace codeNamespace, CodeComposedTypeBase composedType, CodeFunction[] functions)
{
var children = new List<CodeElement>(functions)
{
// Add the composed type, The writer will output the composed type as a type definition e.g export type Pet = Cat | Dog
composedType
};

ReplaceFactoryMethodForComposedType(composedType, children);
ReplaceSerializerMethodForComposedType(composedType, children);
ReplaceDeserializerMethodForComposedType(codeInterface, codeNamespace, composedType, children);

return children;
}

private static CodeFunction? FindFunctionOfKind(List<CodeElement> elements, CodeMethodKind kind)
{
return elements.OfType<CodeFunction>().FirstOrDefault(function => function.OriginalLocalMethod.IsOfKind(kind));
}

private static void RemoveUnusedDeserializerImport(List<CodeElement> children, CodeFunction factoryFunction)
{
if (FindFunctionOfKind(children, CodeMethodKind.Deserializer) is { } deserializerMethod)
factoryFunction.RemoveUsingsByDeclarationName(deserializerMethod.Name);
}

private static void ReplaceFactoryMethodForComposedType(CodeComposedTypeBase composedType, List<CodeElement> children)
{
if (FindFunctionOfKind(children, CodeMethodKind.Factory) is not { } function) return;

if (composedType is not null && IsComposedOfPrimitives(composedType))
function.OriginalLocalMethod.ReturnType = composedType;

// Remove the deserializer import statement if its not being used
if (composedType is CodeUnionType || composedType is not null && IsComposedOfPrimitives(composedType))
{
RemoveUnusedDeserializerImport(children, function);
}
}

private static void ReplaceSerializerMethodForComposedType(CodeComposedTypeBase composedType, List<CodeElement> children)
{
if (FindFunctionOfKind(children, CodeMethodKind.Serializer) is not { } function) return;

// Add the key parameter if the composed type is a union of primitive values
if (IsComposedOfPrimitives(composedType))
function.OriginalLocalMethod.AddParameter(CreateKeyParameter());
}

private static void ReplaceDeserializerMethodForComposedType(CodeInterface codeInterface, CodeNamespace codeNamespace, CodeComposedTypeBase composedType, List<CodeElement> children)
{
if (FindFunctionOfKind(children, CodeMethodKind.Deserializer) is not { } deserializerMethod) return;

// For code union Deserializer is not required, however its needed for Object Intersection types
if (composedType is not CodeIntersectionType || IsComposedOfPrimitives(composedType))
{
children.Remove(deserializerMethod);
codeInterface.RemoveChildElement(deserializerMethod);
codeNamespace.RemoveChildElement(deserializerMethod);
}
}

private static CodeParameter CreateKeyParameter()
{
return new CodeParameter
{
Name = "key",
Type = new CodeType { Name = "string", IsExternal = true, IsNullable = false },
Optional = false,
Documentation = new()
{
DescriptionTemplate = "The name of the property to write in the serialization.",
},
};
}

public static CodeComposedTypeBase? GetOriginalComposedType(CodeElement element)
{
return element switch
{
CodeParameter param => GetOriginalComposedType(param.Type),
CodeType codeType when codeType.TypeDefinition is not null => GetOriginalComposedType(codeType.TypeDefinition),
CodeClass codeClass => codeClass.OriginalComposedType,
CodeInterface codeInterface => codeInterface.OriginalClass.OriginalComposedType,
CodeComposedTypeBase composedType => composedType,
_ => null,
};
}

private static readonly CodeUsing[] navigationMetadataUsings = [
new CodeUsing
{
Expand Down Expand Up @@ -739,9 +858,9 @@ private static void AddInterfaceParamToSerializer(CodeInterface modelInterface,

method.AddParameter(new CodeParameter
{
Name = ReturnFinalInterfaceName(modelInterface),
Name = GetFinalInterfaceName(modelInterface),
DefaultValue = "{}",
Type = new CodeType { Name = ReturnFinalInterfaceName(modelInterface), TypeDefinition = modelInterface },
Type = new CodeType { Name = GetFinalInterfaceName(modelInterface), TypeDefinition = modelInterface },
Kind = CodeParameterKind.DeserializationTarget,
});

Expand All @@ -752,7 +871,7 @@ private static void AddInterfaceParamToSerializer(CodeInterface modelInterface,
Name = modelInterface.Parent.Name,
Declaration = new CodeType
{
Name = ReturnFinalInterfaceName(modelInterface),
Name = GetFinalInterfaceName(modelInterface),
TypeDefinition = modelInterface
}
});
Expand Down Expand Up @@ -783,7 +902,7 @@ private static void RenameModelInterfacesAndRemoveClasses(CodeElement currentEle
{
if (currentElement is CodeInterface modelInterface && modelInterface.IsOfKind(CodeInterfaceKind.Model) && modelInterface.Parent is CodeNamespace parentNS)
{
var finalName = ReturnFinalInterfaceName(modelInterface);
var finalName = GetFinalInterfaceName(modelInterface);
if (!finalName.Equals(modelInterface.Name, StringComparison.Ordinal))
{
if (parentNS.FindChildByName<CodeClass>(finalName, false) is CodeClass existingClassToRemove)
Expand All @@ -803,11 +922,11 @@ private static void RenameCodeInterfaceParamsInSerializers(CodeFunction codeFunc
{
if (codeFunction.OriginalLocalMethod.Parameters.FirstOrDefault(static x => x.Type is CodeType codeType && codeType.TypeDefinition is CodeInterface) is CodeParameter param && param.Type is CodeType codeType && codeType.TypeDefinition is CodeInterface paramInterface)
{
param.Name = ReturnFinalInterfaceName(paramInterface);
param.Name = GetFinalInterfaceName(paramInterface);
}
}

private static string ReturnFinalInterfaceName(CodeInterface codeInterface)
private static string GetFinalInterfaceName(CodeInterface codeInterface)
{
return codeInterface.OriginalClass.Name.ToFirstCharacterUpperCase();
}
Expand Down Expand Up @@ -927,7 +1046,7 @@ private static void SetTypeAsModelInterface(CodeInterface interfaceElement, Code
Name = interfaceElement.Name,
TypeDefinition = interfaceElement,
};
requestBuilder.RemoveUsingsByDeclarationName(ReturnFinalInterfaceName(interfaceElement));
requestBuilder.RemoveUsingsByDeclarationName(GetFinalInterfaceName(interfaceElement));
if (!requestBuilder.Usings.Any(x => x.Declaration?.TypeDefinition == elemType.TypeDefinition))
{
requestBuilder.AddUsing(new CodeUsing
Expand Down Expand Up @@ -971,7 +1090,7 @@ private static CodeInterface CreateModelInterface(CodeClass modelClass, Func<Cod
Kind = CodeInterfaceKind.Model,
Documentation = modelClass.Documentation,
Deprecation = modelClass.Deprecation,
OriginalClass = modelClass
OriginalClass = modelClass,
};

var modelInterface = modelClass.Parent is CodeClass modelParentClass ?
Expand All @@ -996,7 +1115,7 @@ private static void ProcessModelClassDeclaration(CodeClass modelClass, CodeInter
var parentInterface = CreateModelInterface(baseClass, tempInterfaceNamingCallback);
var codeType = new CodeType
{
Name = ReturnFinalInterfaceName(parentInterface),
Name = GetFinalInterfaceName(parentInterface),
TypeDefinition = parentInterface,
};
modelInterface.StartBlock.AddImplements(codeType);
Expand Down
6 changes: 6 additions & 0 deletions src/Kiota.Builder/Writers/LanguageWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ public void Write<T>(T code) where T : CodeElement
case CodeConstant codeConstant:
((ICodeElementWriter<CodeConstant>)elementWriter).WriteCodeElement(codeConstant, this);
break;
case CodeUnionType codeUnionType:
((ICodeElementWriter<CodeUnionType>)elementWriter).WriteCodeElement(codeUnionType, this);
break;
case CodeIntersectionType codeIntersectionType:
((ICodeElementWriter<CodeIntersectionType>)elementWriter).WriteCodeElement(codeIntersectionType, this);
break;
}
else if (code is not CodeClass &&
code is not BlockDeclaration &&
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Linq;
using Kiota.Builder.CodeDOM;
using Kiota.Builder.Extensions;

namespace Kiota.Builder.Writers.TypeScript;

public abstract class CodeComposedTypeBaseWriter<TCodeComposedTypeBase>(TypeScriptConventionService conventionService) : BaseElementWriter<TCodeComposedTypeBase, TypeScriptConventionService>(conventionService) where TCodeComposedTypeBase : CodeComposedTypeBase
{
public abstract string TypesDelimiter
{
get;
}

public override void WriteCodeElement(TCodeComposedTypeBase codeElement, LanguageWriter writer)
{
ArgumentNullException.ThrowIfNull(codeElement);
ArgumentNullException.ThrowIfNull(writer);

if (!codeElement.Types.Any())
throw new InvalidOperationException("CodeComposedTypeBase should be comprised of one or more types.");

var codeUnionString = string.Join($" {TypesDelimiter} ", codeElement.Types.Select(x => conventions.GetTypeString(x, codeElement)));

writer.WriteLine($"export type {codeElement.Name.ToFirstCharacterUpperCase()} = {codeUnionString};");
}
}
Loading
Loading